From ac8860be5f7af85fb05d80f1bf9abf2c74a207d0 Mon Sep 17 00:00:00 2001 From: wan-may Date: Thu, 2 May 2024 23:00:39 -0300 Subject: [PATCH] make a repo --- ADDITIVE3.ny | 133 ++++++++++++++++++++++++++++++ CONVOLVE.ny | 31 +++++++ FILTERSWEEP.ny | 34 ++++++++ FILTERSWEEPTRACK.ny | 52 ++++++++++++ FMCHIRP.ny | 44 ++++++++++ GRAINIMOGRIFIER.ny | 192 +++++++++++++++++++++++++++++++++++++++++++ HARMONIZER.ny | 34 ++++++++ INHARMONIC.ny | 25 ++++++ NOISEMODULATION.ny | 66 +++++++++++++++ RANDOM-TONES.ny | 39 +++++++++ RANDOM-WAVES.ny | 117 ++++++++++++++++++++++++++ RANDOMCHIRP.ny | 85 +++++++++++++++++++ REVERSECHIRP.ny | 28 +++++++ ReverbImpulseDrum.ny | 70 ++++++++++++++++ TONERATIO.ny | 25 ++++++ WINDOW.ny | 16 ++++ 16 files changed, 991 insertions(+) create mode 100644 ADDITIVE3.ny create mode 100644 CONVOLVE.ny create mode 100644 FILTERSWEEP.ny create mode 100644 FILTERSWEEPTRACK.ny create mode 100644 FMCHIRP.ny create mode 100644 GRAINIMOGRIFIER.ny create mode 100644 HARMONIZER.ny create mode 100644 INHARMONIC.ny create mode 100644 NOISEMODULATION.ny create mode 100644 RANDOM-TONES.ny create mode 100644 RANDOM-WAVES.ny create mode 100644 RANDOMCHIRP.ny create mode 100644 REVERSECHIRP.ny create mode 100644 ReverbImpulseDrum.ny create mode 100644 TONERATIO.ny create mode 100644 WINDOW.ny diff --git a/ADDITIVE3.ny b/ADDITIVE3.ny new file mode 100644 index 0000000..5bd4fdc --- /dev/null +++ b/ADDITIVE3.ny @@ -0,0 +1,133 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "Additive Tone..." +;action "Generating Tones..." +;author "dm" +;copyright "Released under terms of the GNU General Public License version 2" +;release 1.1 + +;control coefs-string "Decay Coefficients" string "" "(2.25 3 2.0 5 3) (3.3 2.7) (5.4 2 7.5 (3.2 5) (4 2)) (7.8 9.2) (13.3)" +;control pch "Pitch (Steps)" float-text "" 60 1 96 +;control vib-rate "Vibrato Speed (Hz)" float-text "" 36 0 1102.4 +;control vib-depth "Vibrato Depth (Hz)" float-text "" 3 0 nil +;control dur "Duration" time "" 3 nil nil + +;;;WHAT IT DO + +;Generates a tone with pitch pch and duration dur, with vibrato. +;coefs-string determines the timbre, by specifying how quickly harmonics should ;attenuate according to their frequency. +;coefs-string consists of terms delimited by parentheses (), whose elements may be ;either positive numbers or further sub-terms delimited by parentheses. +;If there are n terms, the first term gives the timbre at the start time, the second at ;dur/n, the third at 2*dur/n, and so on. Timbre is smoothly interpolated between these ;points. +;In a term with k elements, the rth element determines the amplitude of +;the r-1 mod k harmonics. +;If the rth element is a number x, then the ith harmonic (where i is r-1 modulo k) has ;amplitude i^(-x). That is, higher numbers make the harmonics attenuate faster. +;If the rth element is a subterm with l elements, then the sth element of that subterm +;determines the amplitude of the (r+k*(s-1)) mod k*l harmonics. + +;As an example, here are the harmonics and relative amplitudes when +;coefs-string is "((5 (4 2)) 3)" and pch is 69: +;Harmonic Frequency Amplitude Amplitude +;1 440 1^-5 1.000000 +;2 880 2^-3 0.125000 +;3 1320 3^-4 0.012345 +;4 1760 4^-3 0.015625 +;5 2200 5^-5 0.000320 +;6 2640 6^-3 0.004630 +;7 3080 7^-2 0.020408 +;8 3520 8^-3 0.001953 + +;;;ACKNOWLEDGEMENT + +;Shout out to steve for a very thorough code review and loads of coding tips, and the ;rewritten gen-tables which I nicked verbatim from a post of his. +;Thank you David R. Sky for the handy string-to-list function. + +;;;ADDITIONAL GLOBAL VARIABLES + +;;Don't compute harmonics if their frequencies are too high. +(setq hi-freq (min (/ *sound-srate* 2) 17000.0)) +(setq top-overtone (min + 1000 ;magic number to avoid argument stack overflow when calling simrep. + (+ 1 (truncate (/ hi-freq (step-to-hz pch)))))) + +(defun get-coefficient (overtone lst divis) + ;;;recursively search coefficient list for exponent + (let* ((len (length lst)) + (branches (mult divis len)) + (term (nth (rem (/ overtone divis) len) lst))) + (if (numberp term) + term + (get-coefficient overtone term branches)))) + +(defun get-amplitude (overtone coef-list) + (expt (+ 1.0 overtone) + (- (get-coefficient overtone coef-list 1)))) + +;2022-07-06, I fucked up my backup and started from this old version +;which still had stack overflow errors from simrep. +;(defun gen-table (coef-list) +; (simrep (current-overtone top-overtone) +; (scale (get-amplitude current-overtone coef-list) +; (build-harmonic (+ 1 current-overtone) 2048)))) +;2022-07-06, this one should work better. +(defun gen-table (coef-list) + (do ((table 0) + (current-overtone 0)) + ((> current-overtone top-overtone) table) + (setq current-overtone (+ 1 current-overtone)) + (setq table + (sum table (scale (get-amplitude current-overtone coef-list) + (build-harmonic (+ 1 current-overtone) 2048)))))) + +(defun normalize (sig) + ;;;assume signal has 2048 samples + (scale (/ 0.75 (peak sig 2048)) sig)) + +(defun gen-tables (coef-lists pitch interval) + ;;; Push wavetable and breakpoint onto a list 'tables'. + ;;; Discard the final breakpoint, then return 'tables' for siosc. + (let ((count 1) tables) + (dolist (coef-list coef-lists (reverse (cdr tables))) + (push (normalize (gen-table coef-list)) tables) + (push (* interval count) tables) + (incf count)))) + +(defun modulation (vib-rate vib-depth duration) + (if (= vib-rate 0) + (s-rest duration) + (scale vib-depth (lfo vib-rate duration)))) + +(defun gen-tone (pitch duration coef-lists) + ;;;get wavetables and mod. env., pass to built-in Nyquist oscillators. + (validate-coefs coef-lists) + (let* ((mod (modulation vib-rate vib-depth duration)) + (interval (/ duration (length coef-lists))) + (tables (gen-tables coef-lists pitch interval))) + (if (= (length coef-lists) 1) + (fmosc pitch mod (maketable (car tables)) 0) + (siosc pitch mod tables)))) + +(defun validate-coefs (lst) + ;;; All items in top level list must be lists. + (dolist (coef lst) + (when (not (listp coef)) + (throw 'err (format nil "Coefficient ~s is invalid (not a list)." coef))) + (validate-items lst))) + +(defun validate-items (item) + ;;; Items must be lists or numbers. Test recursively. + (cond + ((and (numberp item) (>= item 0))) ;valid + ((listp item) (mapc 'validate-items item)) ;recurse + (t (throw 'err (format nil "Coefficient ~s is invalid." item))))) + +;;;Took this one-liner from David R. Sky's Sequencer 2, released under GPLv2. +;;;Replace this with eval-string when 2.3.1 releases. +(defun string-to-list (string) + (read (make-string-input-stream (format nil "(~a)" string)))) + +;;read string, then generate tone (or throw error) +(setf coefs (string-to-list coefs-string)) +(catch 'err (gen-tone pch dur coefs)) \ No newline at end of file diff --git a/CONVOLVE.ny b/CONVOLVE.ny new file mode 100644 index 0000000..603ec0c --- /dev/null +++ b/CONVOLVE.ny @@ -0,0 +1,31 @@ +;nyquist plug-in +;version 4 +;type process +;preview linear +;name "Convolve Tracks" +;action "Convolving..." +;author "dm" + +(defun get-storage () + (get '*SCRATCH* 'DM-CONVOLVE-STORAGE)) + +(defun clear-storage () + (remprop '*SCRATCH* 'DM-CONVOLVE-STORAGE)) + +(defun store (signal) + (putprop '*SCRATCH* signal 'DM-CONVOLVE-STORAGE) + (sum (s-rest 0) signal)) + +(defun conv-stored (signal) + (convolve signal (get-storage))) + +(setq index (get '*TRACK* 'INDEX)) +(setq tracks (length (get '*SELECTION* 'TRACKS))) +;(print (symbol-plist '*SCRATCH*)) +(if (= index 1) + (if (< tracks 2) + (print "Select two or more tracks") + (store *TRACK*)) + (if (= index tracks) + (prog1 (conv-stored *TRACK*) (clear-storage)) + (store (conv-stored *TRACK*)))) \ No newline at end of file diff --git a/FILTERSWEEP.ny b/FILTERSWEEP.ny new file mode 100644 index 0000000..d4e6fc0 --- /dev/null +++ b/FILTERSWEEP.ny @@ -0,0 +1,34 @@ +;nyquist plug-in +;version 4 +;type process +;preview linear +;name "Filter Sweep..." +;action "Filtering..." +;author "dm" + +;control type "Filter Type" choice "Low-Pass,High-Pass,Band-Pass" 0 +;control start-freq "Start Frequency (Hz)" float-text "" 7000 0 20000 +;control end-freq "End Frequency (Hz)" float-text "" 1000 0 20000 +;control shape-num "Curve Parameter" float-text "" 5 nil nil +;control intensity "Intensity" int-text "" 1 1 50 + +(defun curve (inif finf crv) + (if (zerop crv) + (pwlv inif 1 finf) + (let* ((crv (expt 0.5 crv)) + (norm (/ (- inif finf) (- 1.0 crv))) + (arc (scale norm (diff (pwev 1 1 crv) crv)))) + (sim finf arc)))) + +(defun iter-lp (signal cutoff iter) + (dotimes (n iter signal) (setf signal (lp signal cutoff)))) + +(defun iter-hp (signal cutoff iter) + (dotimes (n iter signal) (setf signal (hp signal cutoff)))) + +(let* ((cutoff (curve start-freq end-freq shape-num)) + (bandwidth (/ *sound-srate* (float intensity) 5.0))) + (case type + (0 (iter-lp *TRACK* cutoff intensity)) + (1 (iter-hp *TRACK* cutoff intensity)) + (2 (reson *TRACK* cutoff bandwidth 1)))) \ No newline at end of file diff --git a/FILTERSWEEPTRACK.ny b/FILTERSWEEPTRACK.ny new file mode 100644 index 0000000..c05a6ae --- /dev/null +++ b/FILTERSWEEPTRACK.ny @@ -0,0 +1,52 @@ +;nyquist plug-in +;version 4 +;type process +;preview linear +;name "Filter Sweep (Track Input)..." +;action "Filtering..." +;author "dm" + +;control type "Filter Type" choice "Low-Pass,High-Pass,Band-Pass" 0 +;control intensity "Intensity" int-text "" 1 1 50 +;control max-cu-freq "Maximum Cutoff Frequency" float "" 15000 1 22030 + +;clip to halfwave, scale to max cutoff freq, downsample to control rate, store, +;compute +(defun store-as-cutoff (signal) + (setf to-store + (sim (s-rest 0) + (force-srate *control-srate* + (scale max-cu-freq + (s-min (const 1) + (s-max (s-rest 1) signal)))))) + (putprop '*SCRATCH* (sim (s-rest 0) to-store) 'DM-FSWEEP-CUTOFF) + *TRACK*) + +(defun clear-storage () + (remprop '*SCRATCH* 'DM-SWEEP-CUTOFF)) + +(defun iter-lp (signal cutoff iter) + (print (snd-length cutoff ny:all)) + (dotimes (n iter signal) + (setf signal (lp signal cutoff)))) + +(defun iter-hp (signal cutoff iter) + (dotimes (n iter signal) + (setf signal (hp signal cutoff)))) + +(defun apply-filter (cutoff) + (let* ((bandwidth (/ *sound-srate* (float intensity) 5.0))) + (case type + (0 (iter-lp *TRACK* cutoff intensity)) + (1 (iter-hp *TRACK* cutoff intensity)) + (2 (reson *TRACK* cutoff bandwidth 1))))) + +(setq index (get '*TRACK* 'INDEX)) +(setq tracks (length (get '*SELECTION* 'TRACKS))) +(if (< tracks 2) + (print "Select 2 tracks") + (if (< index tracks) + (store-as-cutoff *TRACK*) + (let ((cutoff (get '*SCRATCH* 'DM-FSWEEP-CUTOFF))) + (if (= index tracks) (clear-storage)) + (multichan-expand #'apply-filter cutoff)))) diff --git a/FMCHIRP.ny b/FMCHIRP.ny new file mode 100644 index 0000000..bc0784b --- /dev/null +++ b/FMCHIRP.ny @@ -0,0 +1,44 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "FM Chirp..." +;action "Generating Chirp..." +;author "dm" +;copyright "Released under terms of the GNU General Public License version 2" + +;control carri-params "Carrier (Start End Curve)" string "" "800 200 -1.5" +;control modul-params "Modulator (Start End Curve)" string "" "450 -1.0 5.7" +;control modul-scale "Modulation Index" float-text "" 50 0 nil +;control dur "Duration" float "" 1 0.01 5 + +;;;curve going from inf to finf with curve parameter crv. +(defun piece (inif finf crv) + (if (zerop crv) + (pwlv inif 1 finf) + (let* ((epsilon (expt 0.5 crv)) + (norm (/ (- inif finf) (- 1.0 epsilon))) + (arc (scale norm (diff (pwev 1 1 epsilon) epsilon)))) + (sum finf arc)))) + +;;;stole this one from David R. Sky's Sequencer 2. +(defun string-to-list (string) + (read (make-string-input-stream (format nil "(~a)" string)))) + +(defun list-to-floats (input-list) + (mapcar #'float input-list)) + +(defun string-to-curve (string) + (apply #'piece (list-to-floats (string-to-list string)))) + +(defun three-numbersp (input-list) + (eq (mapcar #'numberp input-list) (list (= 0 0) (= 0 0) (= 0 0)))) + +(stretch-abs dur + (let* ((modul-freq (string-to-curve modul-params)) + (carri-freq (string-to-curve carri-params))) + (hzosc + (sum carri-freq + (scale modul-scale + (hzosc modul-freq)))))) \ No newline at end of file diff --git a/GRAINIMOGRIFIER.ny b/GRAINIMOGRIFIER.ny new file mode 100644 index 0000000..b4da2ee --- /dev/null +++ b/GRAINIMOGRIFIER.ny @@ -0,0 +1,192 @@ +;nyquist plug-in +;version 4 +;type process +;name "Grainimogrifier..." +;action "Milling..." +;author "dm" +;preview disabled +;release 1.3.1 +;copyright "Released under terms of the GNU General Public License version 2" + +;control grain-number "Number of Grains" int "" 50 2 1750 +;control min-grain-gap "Minimum Grain Separation (ms)" float "" 1 0 50 +;control grain-length "Grain Length (ms)" float "" 500 0 1000 +;control grain-type "Grain Envelope" choice "Triangle,Sine,Exponential,Rectangular" 0 +;control normal-places "Normalize Sample Start Control Envelope" choice "No,Yes" 0 + +; 'input' raw sample to granulate +; 'gaps-env' t: grain number x: absolute time in seconds until next grain +; 'starts' processed gaps - list of absolute start times of grains +; 'place-env' t: relative time in output x: relative input time where grain starts +; 'places' processed places - list of relative input times where grains start +; where gaps-env or place-env is negative, grains are reversed. + +(defun scratch-cleanup () + (remprop '*SCRATCH* '*DM-GRAN-STARTS*) + (remprop '*SCRATCH* '*DM-GRAN-PLACES*) + (remprop '*SCRATCH* '*DM-GRAN-SIGN*)) + +(defun get-r-grain-length () + (/ grain-length (get-duration 1) 1000.0)) + +;;;FUNCTIONS CALLED BY FIRST RUN +(defun array-to-list (arr) + (do (lst + (ind 0 (1+ ind)) + (end (- (length arr) 1))) + ((> ind end) (reverse lst)) + (push (aref arr ind) lst))) + +(defun downsample-and-list (sig) + (array-to-list (snd-fetch-array + (force-srate (/ grain-number (get-duration 1)) sig) + grain-number 1))) + +(defun gaps-to-starts (lst) + (do ((rslt (list 0))) + ((null lst) (cdr (reverse rslt))) + (push + (+ (car rslt) + (max min-grain-gap (abs (pop lst)))) + rslt))) + +(defun first-invocation () + ;;;resample first track so that we have one sample per grain + ;;;cast sound to list, take cumulative sum and store for future invocations + ;;;also record when list is negative so we know when to reverse grains + ;;mono error + (if (arrayp *TRACK*) + (throw 'err (format nil "First two tracks should be mono."))) + (let ((gaps-list (downsample-and-list *TRACK*))) + (putprop '*SCRATCH* + (gaps-to-starts gaps-list) + '*DM-GRAN-STARTS*) + (putprop '*SCRATCH* + (mapcar #'minusp gaps-list) + '*DM-GRAN-SIGN*))) + +;;;FUNCTIONS CALLED BY SECOND RUN +(defun rev-time (len tim) + ;;;grain starts at local time tim, local duration is len. + ;;;find local start time such that reversing track plays same grain up to reversal. + (- 1.0 tim len)) + +(defun normalize-places (lst) + ;;;ensure elements span from 0 to 1 (or if it's constant, 0) + (if (and lst normal-places) + (let* ((hi (apply #'max lst)) + (lo (apply #'min lst)) + (spread (- hi lo))) + (if (= spread 0) + (mapc (lambda (y) 0) lst) + (mapc (lambda (y) (/ (- y lo) spread)) lst))) + lst)) + +(defun get-final-duration (starts) + ;;;duration of processed track + (+ (/ grain-length 1000.0) (car (last starts)))) + +(defun process-place-env (starts reverses) + ;;;convert times to relative start times, look up values of track + ;;;reverse grains whenever first or second track is negative + (do ((dur-out (get-final-duration starts)) + rev reverses-out + place places) + ((null starts) + (cons + (reverse (normalize-places places)) + (reverse reverses-out))) + (setf place (sref *TRACK* (/ (pop starts) dur-out))) + (setf rev (or (pop reverses) (minusp place))) + ;;Reversing grains is accomplished by graining a reversed copy of the whole track. + ;;Thus we need to adjust the start times. + (push + (if rev + (rev-time (get-r-grain-length) (abs place)) + place) places) + (push rev reverses-out))) + +(defun second-invocation () + ;;;get list of absolute start times of grains from previous invocation + ;;;convert to relative start times + ;;;look up values of current (i.e. second) track at rel. times, store for later + (if (arrayp *TRACK*) + (throw 'err (format nil "First two tracks should be mono." + (scratch-cleanup)))) + (let ((results (process-place-env + (get '*SCRATCH* '*DM-GRAN-STARTS*) + (get '*SCRATCH* '*DM-GRAN-SIGN*)))) + (putprop '*SCRATCH* (car results) '*DM-GRAN-PLACES*) + (putprop '*SCRATCH* (cdr results) '*DM-GRAN-SIGN*))) + +;;;FUNCTIONS CALLED BY THIRD RUN +(defun array-reverse (a length) + (do ((left 0 (1+ left)) + (right (- length 1) (1- right)) + (middle (/ length 2)) + temp) + ((= left middle) a) + (setf temp (aref a left)) + (setf (aref a left) (aref a right)) + (setf (aref a right) temp))) + +(defun snd-reverse (sig) + (let* ((len (snd-length sig NY:ALL)) + (arr (snd-samples sig len))) + (snd-from-array + (snd-t0 sig) + *sound-srate* + (array-reverse arr len)))) + +(defun grain-envelope (len) + (case grain-type + (0 (pwl (/ len 2.0) 1 len 0)) ;triangle + (1 (lfo (/ 0.5 (get-duration 1) len) len)) ;sine + (2 (scale (/ (- 1 len)) (diff (pwev 1 len len) len))) ;exp + (3 1))) ;rect + +(defun any (lst) + (do ((rslt nil (pop lst))) + ((or rslt (null lst)) rslt))) + +(defun granulate (sample) + ;;;extract grains from sample at relative times specified by places + ;;;apply envelope to each grain, cue grains at absolute times specified by starts + (do* ((starts (get '*SCRATCH* '*DM-GRAN-STARTS*)) + (places (get '*SCRATCH* '*DM-GRAN-PLACES*)) + (revers (get '*SCRATCH* '*DM-GRAN-SIGN*)) + ;;optimization - only reverse the sample if we need to. + (rev-sample (if (any revers) (snd-reverse sample) nil)) + (throw 'err (format nil "AAA")) + place + r-grain-length + (grain (s-rest 1)) + (out (s-rest 0))) + ((null starts) out) + (setq place (pop places)) + (setq r-grain-length (get-r-grain-length)) + (setf grain (mult (grain-envelope r-grain-length) + (extract place (+ place r-grain-length) + (if (pop revers) rev-sample sample)))) + (setf out (sim (at 0 (cue out)) + (at-abs (pop starts) (cue grain)))))) + +(defun process-sample-track () + (prog1 + (multichan-expand #'granulate *TRACK*) + (if (= index tracks) (scratch-cleanup)))) + +;;;GLOBALS +(setq index (get '*TRACK* 'INDEX)) +(setq tracks (length (get '*SELECTION* 'TRACKS))) +(setq min-grain-gap (/ min-grain-gap 1000.0)) + +;;;MAIN +(catch 'err + (if (< tracks 3) + (throw 'err (format nil + "Select three or more audio tracks. The top two should be mono.")) + (cond + ((= index 1) (first-invocation) *TRACK*) + ((= index 2) (second-invocation) *TRACK*) + (T (process-sample-track))))) diff --git a/HARMONIZER.ny b/HARMONIZER.ny new file mode 100644 index 0000000..4bffff6 --- /dev/null +++ b/HARMONIZER.ny @@ -0,0 +1,34 @@ +;nyquist plug-in +;version 4 +;type process +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "Harmonize..." +;action "Harmonizing..." +;author "dm" + +;control decay "Decay" float "" 0.5 0 1 +;control harmonics "Harmonics" int "" 2 1 10 + +(setq minor-third (/ 6.0 5.0)) +(setq major-third (/ 5.0 4.0)) + +(defun get-ratio (index) + (if (evenp index) + (/ + (* (expt minor-third (float (/ index 4))) + (expt major-third (float (/ (+ 2 index) 4))))) + (* + (expt minor-third (float (+ 1 (/ index 4)))) + (expt major-third (float (/ (+ 1 index) 4)))))) + +(defun normalize (signal) + (let ((x (* (peak signal ny:all) 0.95))) + (setq signal (scale (/ x) signal)))) + +(do* ((index 0 (incf index)) + (ratio nil (get-ratio index)) + (vol 1.0 (* vol decay)) + (result *TRACK* + (sum result (scale vol (pitshift *TRACK* ratio 1.0))))) + ((>= index harmonics) (normalize result))) \ No newline at end of file diff --git a/INHARMONIC.ny b/INHARMONIC.ny new file mode 100644 index 0000000..bd1702f --- /dev/null +++ b/INHARMONIC.ny @@ -0,0 +1,25 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "Inharmonic..." +;action "Generating Tone..." +;author "dm" + +;control decay "Decay" float "" 0.5 0 1 +;control ratio "Ratio" float "" 1.005 1 1.05 +;control fund-freq "Frequency (Hz)" float "" 420 1 600 +;control duration "Length (Seconds)" float "" 3 0 6 + +(setq loop-number 500) + +(do* ((cur-ind 1 (incf cur-ind)) + (cur-pch (hz-to-step fund-freq) (hz-to-step (* (/ (+ cur-ind 1) 1.0 cur-ind) ratio (step-to-hz cur-pch)))) + (cur-vol decay (* decay cur-vol)) + (result (scale cur-vol (sine cur-pch duration)) + (sum result (scale cur-vol (sine cur-pch duration))))) + ( + (or (> cur-pch 120) (>= cur-ind loop-number)) result) + (print cur-pch) + (print cur-vol)) diff --git a/NOISEMODULATION.ny b/NOISEMODULATION.ny new file mode 100644 index 0000000..652cee3 --- /dev/null +++ b/NOISEMODULATION.ny @@ -0,0 +1,66 @@ +;nyquist plug-in +;version 4 +;type process +;preview linear +;name "Noise Modulation..." +;action "Modulating..." +;author "dm" + +;control mixes-str "Wet-Dry Mix List" string "" "0.5 0 1" +;control width-str "Passband Width" string "" "100 300 0" +;control lp-iterations "Stopband Attenuation" int "" 5 0 15 + +;--- GLOBAL VARIABLES + +;--- PREPARE INPUT +(defun cast-nonnegative-float (element) + (cond + ((floatp element) (abs element)) + ((integerp element) (float (abs element))) + (T 0.0))) + +(defun list-to-floats (input-list) + (mapcar #'cast-nonnegative-float input-list)) + +;;;stole this one from David R. Sky's Sequencer 2. +(defun string-to-list (string) + (read (make-string-input-stream (format nil "(~a)" string)))) + +;;;add some validation to these functions at some point +(defun process-string (string) + (list-to-floats (string-to-list string))) + +;;; COMPUTE SOUND + +;;;this should be written better +(defun gen-envelope (inlist &optional (cutoff (/ *control-srate* 2.1))) + (if (= 1 (length inlist)) + (const (car inlist) 1.0) + (lowpass6 (pwlvr-list (reverse (cdr + (do* ((ylist inlist (cdr ylist)) + (height (car ylist) (car ylist)) + (interval (/ (- (length ylist) 1.0))) + (bp-list (list interval height) + (cons interval (cons height bp-list)))) + ((null (cdr ylist)) bp-list))))) + cutoff))) + +(defun iterate-lp (signal cutoff iterations) + (if (zerop iterations) signal + (iterate-lp (lp signal cutoff) cutoff (- iterations 1)))) + +(defun gen-noise (widths) + (let ((cutoff (gen-envelope widths))) + (iterate-lp (noise 1) cutoff lp-iterations))) + +(defun normalize (signal) + (let ((x (/ 0.95 (peak signal ny:all)))) + (setq signal (scale x signal)))) + +(let* ((modulator (gen-noise (process-string width-str))) + (wet-env (gen-envelope (process-string mixes-str))) + (dry-env (diff 1.0 wet-env)) + (raw (normalize *TRACK*)) + (dry (mult dry-env raw)) + (wet (mult wet-env modulator raw))) + (normalize (sum dry wet))) \ No newline at end of file diff --git a/RANDOM-TONES.ny b/RANDOM-TONES.ny new file mode 100644 index 0000000..cf51708 --- /dev/null +++ b/RANDOM-TONES.ny @@ -0,0 +1,39 @@ +;nyquist plug-in +;name "Random Tones..." +;type generate +;version 4 +;author "dm" +;action "Generating Random Tones..." + +;control seed "Random Seed" int "" 12532 1 134455 +;control duration "Length (Seconds)" float "" 3 0 10 +;control num-tones "Number of tones" int "" 15 1 100 +;control middle "Center Frequency (Hz)" float-text "" 1000 0 20000 +;control width "Width" float-text "" 1 0 20000 +;control table-type "Table" choice "Sine,Saw,Square,Triangle" 0 + +;;;generate pseudorandom int between 1 and 134456 +(defun rnd () + (setq seed (rem (sum (mult 8121 seed) 28411) 134456))) + +;;;generate pseudrandom float between 0 and 1 +(defun rnd-scale () + (/ (float (rnd)) 134456.0)) + +;;;generate pseudorandom (uniformly distributed) frequency within width of middle +(defun rnd-freq () + (print (min (/ *sound-srate* 2.1) + (+ middle (* (- (rnd-scale) 0.5) width 2.0))))) + +(defun gen-tone (hz-freq tbl) + (case tbl + (0 (sine (hz-to-step hz-freq))) + (1 (osc-saw hz-freq)) + (2 (osc-pulse hz-freq 0.0)) + (3 (osc-tri hz-freq)))) + +(stretch-abs duration + (do* ((tone 0 (incf tone)) + (pch 1.0 (rnd-freq)) + (result 0 (sum result (scale (rnd-scale) (gen-tone pch table-type))))) + ((= tone num-tones) (scale (/ (float num-tones)) result)))) \ No newline at end of file diff --git a/RANDOM-WAVES.ny b/RANDOM-WAVES.ny new file mode 100644 index 0000000..2f4b18d --- /dev/null +++ b/RANDOM-WAVES.ny @@ -0,0 +1,117 @@ +;nyquist plug-in +;version 4 +;type generate +;name "Random Piecewise Linear..." +;action "Generating..." +;author "dm" +;copyright "Released under terms of the GNU General Public License version 2" +;release 1.1 + +;control duration "Duration" time "" 3 0 nil +;control fund-freq "Frequency (Hz)" float "" 50 1 300 +;control locks "Parameter Lock (Table Duration)" string "" "(5 3.5) (7 1.1)" +;control text "Timbral Parameters:" +;control seed "Random Seed" int "" 12532 1 134455 +;control num-tables "Number of Key Tables" int "" 5 1 50 +;control num-breakpoints "Max. Segments Per Key Table" int "" 5 1 15 +;control vary-breakpoints "Vary Segments Per Key Table" choice "No,Yes" 0 +;control table-type "Table In" choice "Sine,Saw,Fifth,Triangle,Random" 0 + +(defun rnd () + ;;;pseudorandom number between -1 and 1 + (setq seed (rem (sum (mult 8121 seed) 28411) 134456)) + (- (/ (float seed) 134456 0.5) 1)) + +;;;GENERATE LIST OF WAVETABLES AND BREAKPOINTS FOR SIOSC + +(defun build-shaper (num-breaks) + ;;;pseudorandom piecewise linear function on [0,2] with num-breaks pieces + (if (zerop num-breaks) + (pwlv -1 2.01 1) + (do* ((i 1 (+ i 1)) + (new-time 0 (sum (rnd) 1 new-time)) + (point-list (list (rnd)) (cons (rnd) (cons new-time point-list)))) + ((> i num-breaks) + (stretch-abs (/ 2.01 new-time) (pwlv-list (reverse point-list))))))) + +(defun get-num-breaks (max-breaks) + ;;;decide how many breakpoints build-shaper should create + (case vary-breakpoints + (0 max-breaks) + (1 (truncate (* max-breaks (+ 1 (rnd))))))) + +(defun gen-table (raw-table max-breaks) + (shape raw-table (build-shaper (get-num-breaks max-breaks)) 1)) + +(defun get-raw-table () + ;;;decide which raw table to use + (case table-type + (0 (build-harmonic 1 2048)) + (1 (pwlv -1 1 1)) + (2 (scale 0.49 (sum (build-harmonic 2 2048) (build-harmonic 3 2048)))) + (3 (pwlv -1 1 1 2 -1)) + (4 (scale 0.49 (build-shaper num-breakpoints))))) + +(defun wav-list (duration num-tables breaks-per-table slock-list) + (if (= num-tables 1) + (let ((cur-table (gen-table (get-raw-table) breaks-per-table))) + (list cur-table duration cur-table)) + (let ((interval (/ duration num-tables)) + (raw-table (get-raw-table))) + (do* ((ind 1 (+ 1 ind)) + (cur-time interval (sum interval cur-time)) + (cur-table (gen-table raw-table breaks-per-table) + (gen-table raw-table breaks-per-table)) + (breakpoints-list (list cur-table) + (cons cur-table (cons cur-time breakpoints-list)))) + ((= ind num-tables) (reverse breakpoints-list)) + ;;locks: continue to use current wavetable for specified time + (if (and slock-list (= ind (caar slock-list))) + (progn + (setf cur-time (sum (cadar slock-list) cur-time)) + (setf breakpoints-list (cons cur-table (cons cur-time breakpoints-list))) + (setf slock-list (cdr slock-list)))))))) + +;;;VALIDATE AND PROCESS USER INPUT + +(defun sort-by-car (lst) + (sort lst + (lambda (x y) (< (car x) (car y))))) + +(defun validate-pairs (pair) + (if (and (listp pair) (= 2 (length pair))) + (if (and (integerp (car pair)) + (> (car pair) 0) + (<= (car pair) num-tables)) + (if (and (numberp (cadr pair)) (plusp (cadr pair))) + pair + (throw 'err + (format nil "Lock duration ~s not a positive number." + (cadr pair)))) + (throw 'err (format nil + "Lock table ~s not between 1 and ~s inclusive." (car pair) num-tables))) + (throw 'err (format nil + "Lock ~s not a pair of the form (Table Duration)." pair)))) + +;;;When 2.3.1 is out, replace with eval-string +(defun string-to-list (string) + (read (make-string-input-stream (format nil "(~a)" string)))) + +(defun process-locks (str) + (sort-by-car (mapcar #'validate-pairs (string-to-list str)))) + +;;;PROCESS OUTPUT + +(defun pch-mod (dur) + ;;placeholder + (s-rest dur)) + +(defun normalize (sig) + (let ((ac (highpass8 sig 25))) + (scale (/ 0.95 (peak ac ny:all)) ac))) + +;;;main +(catch 'err (normalize (siosc + (hz-to-step fund-freq) + (pch-mod duration) + (wav-list duration num-tables num-breakpoints (process-locks locks))))) \ No newline at end of file diff --git a/RANDOMCHIRP.ny b/RANDOMCHIRP.ny new file mode 100644 index 0000000..a357c40 --- /dev/null +++ b/RANDOMCHIRP.ny @@ -0,0 +1,85 @@ +;nyquist plug-in +;version 4 +;type generate +;preview linear +;name "Random Chirps..." +;action "Chirping..." +;author "dm" + +;control seed "Seed" int "" 4123 1 134456 +;control duration "Duration" float "" 1 0 5 +;control num-chirps "Number of Chirps" int-text "" 8 1 100 +;control rand-vols "Randomize Volumes" choice "No,Yes" 0 +;control rand-phase "Randomize Phases" choice "No,Yes" 0 +;control freq-intervals "Frequency intervals (low high time)" string "" "(100 1000)" + +;;;Globals: min-rate, max-rate and above +(setq max-rate (/ *sound-srate* 2.1)) +(setq min-rate 0.1) + +;;;generate pseudorandom int between 1 and 134456 +(defun rnd () + (setq seed (rem (sum (mult 8121 seed) 28411) 134456))) + +;;;pseudorandom (uniform) float between lo and hi (assume hi > lo) +(defun unirand (lo hi) + (+ lo (* (- hi lo) (/ (rnd) 134456.0)))) + +(defun piece (inif finf crv) + (if (zerop crv) + (pwlv inif 1 finf) + (let* ((epsilon (expt 0.5 crv)) + (norm (/ (- inif finf) (- 1.0 epsilon))) + (arc (scale norm (diff (pwev 1 1 epsilon) epsilon)))) + (sum finf arc)))) + +(defun bottom (pair) + (min max-rate (max min-rate (car pair)))) + +(defun top (pair) + (min max-rate (max min-rate (cadr pair)))) + +(defun freq-curve (band-list) + (do* ((time -1 (incf time)) + (cur-band (car band-list) (car band-list)) + (lo (bottom cur-band) (bottom cur-band)) + (hi (top cur-band) (top cur-band)) + (prev-freq nil cur-freq) + (cur-freq (unirand lo hi) (unirand lo hi)) + (crv-param (unirand -10.0 10.0)) + (segment nil (piece prev-freq cur-freq crv-param)) + (curve 0 (sim curve (at time (cue segment))))) + ((= (length band-list) 1) curve) + (setf band-list (cdr band-list)))) + +(defun chirp (band-list phase) + (hzosc (freq-curve band-list) *table* phase)) + +;Stole this one from David R. Sky's Sequencer2 +(defun string-to-list (string) + (read (make-string-input-stream (format nil "(~a)" string)))) + +(defun process-freq-intervals (string) + (let ((raw-list (string-to-list string))) + (if (= (length raw-list) 1) + (list (car raw-list) (car raw-list)) + raw-list))) + +(defun get-phase () + (if (zerop rand-phase) + 0 + (unirand -180.0 180.0))) + +(defun get-scale () + (if (zerop rand-vols) + 1.0 + (unirand 0.0 1.0))) + +(stretch-abs duration + (do* ((count 0 (incf count)) + (bands (process-freq-intervals freq-intervals)) + (phase nil (get-phase)) + (vol nil (get-scale)) + (cur-chirp nil (scale vol (chirp bands phase))) + (result 0 (sum result cur-chirp))) + ((= count num-chirps) (scale (/ (float num-chirps)) result)))) \ No newline at end of file diff --git a/REVERSECHIRP.ny b/REVERSECHIRP.ny new file mode 100644 index 0000000..dcc0176 --- /dev/null +++ b/REVERSECHIRP.ny @@ -0,0 +1,28 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "Reverse Chirp..." +;action "Generating Chirp..." +;author "dm" + +;control crv-param "Curve" float "" 5 0 10 +;control top-freq "Top Frequency (Hz)" float "" 6000 1 22050 +;control duration "Length (Seconds)" float-text "" 0.05 0 5 +;control tbl-choice "Waveform" choice "Sine,Sawtooth,Triangle,Square" 0 + +;tone which lingers at high frequencies before chirping downward to zero +;bandpass filter is applied to emphasize frequency halfway down +(let* ((passq 5.0) + (epsilon (expt 0.5 crv-param)) + (tbl-form (case tbl-choice + (0 *sine-table*) + (1 *saw-table*) + (2 (maketable (pwlv -1 0.5 -1 0.501 1 1.0 1))) + (3 *tri-table*)))) + (stretch-abs duration + (bandpass2 + (hzosc (scale (- top-freq) (diff (pwev epsilon 1 1) 1)) + tbl-form 0.0) + (/ top-freq 2.0) passq))) \ No newline at end of file diff --git a/ReverbImpulseDrum.ny b/ReverbImpulseDrum.ny new file mode 100644 index 0000000..8824905 --- /dev/null +++ b/ReverbImpulseDrum.ny @@ -0,0 +1,70 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;author "dm" +;name "Reverb Impulse Drum..." +;action "Generating..." +;info "" + +;control band-list "List: (center amplitude &optional bandwith)" string "" "(420 0.5 250) (1500 0.3 150) (4300 0.01) (7500 0.02 2000) (12345 0.01 3000) (3500 0.05 300)" +;control impulse-type "Kind of Impulse" choice "chirp, noise, spike" 0 +;control impulse-volume "Volume of Impulse" float "" 0.5 0 1 +;control impulse-length "Length of Impulse (ms)" float "" 10 1 50 +;control decay "Decay" float "" 0.5 0.01 1 + +(setq impulse-length (mult 0.001 impulse-length)) + +;Stolen from David R. Sky's Sequencer2, I don't know how this works. +(defun string-to-list (string) +(read (make-string-input-stream (format nil "(~a)" string)))) + +(defun normalize (signal &optional (amplitude 1)) +(setf factor (/ amplitude (peak signal ny:all))) +(scale factor signal) +);end normalize + +(defun gen-noiseband (center &optional (amplitude 1) (bandwidth 1000)) +(partial (hz-to-step center) (lowpass8 (normalize (noise 1) amplitude) bandwidth)) +);end gen-noiseband + +(defun gen-response (band-list dur) +(setf bands ()) +(dolist (band-params (string-to-list band-list)) +(setf bands (cons (apply #'gen-noiseband band-params) bands)) +);end dolist +(mult (normalize (apply #'sim bands) impulse-volume) +(pwlv 1 (* dur 0.25) 0.1 dur 0)) +);end response + +(defun chirp-impulse (dur) +(mult (hzosc (sum +(pwlv (/ *sound-srate* 2.1) (* dur 0.3) 100 dur 1) ;frequency of hzosc +(scale 100 (noise dur)) ;noise to vary frequency of chirp randomly +));end of hzosc +(pwlv 1 dur 0)) ;envelope to get rid of click at and of impulse +);end gen-impulse + +(defun noise-impulse (dur) +(noise dur) +) + +(defun spike-impulse (dur) +(pwl (/ dur 5.0) 1 dur 0) +) + +(defun gen-impulse (dur) +(cond ;chooses which kind of impulse +((= impulse-type 0) (chirp-impulse dur)) +((= impulse-type 1) (noise-impulse dur)) +((= impulse-type 2) (spike-impulse dur)) +);end cond +) + + +(setf impulse (normalize (gen-impulse impulse-length) impulse-volume)) +(setf response (gen-response band-list decay)) +(lowpass8 (sum +impulse +(convolve impulse response)) +15000) \ No newline at end of file diff --git a/TONERATIO.ny b/TONERATIO.ny new file mode 100644 index 0000000..c30e5fd --- /dev/null +++ b/TONERATIO.ny @@ -0,0 +1,25 @@ +;nyquist plug-in +;version 4 +;type generate +;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear +;name "Common Ratio Tone..." +;action "Generating Tone..." +;author "dm" + +;control decay "Decay" float "" 0.5 0 1 +;control ratio "Ratio" float "" 2 1 5 +;control fund-freq "Frequency (Hz)" float "" 420 1 600 +;control duration "Length (Seconds)" float "" 3 0 6 + +(setq loop-number (truncate + (/ (log (/ *sound-srate* fund-freq)) (log ratio)))) + +(do* ((cur-ind 1 (incf cur-ind)) + (cur-pch (hz-to-step fund-freq) (hz-to-step (* ratio (step-to-hz cur-pch)))) + (cur-vol decay (* decay cur-vol)) + (result (scale cur-vol (sine cur-pch duration)) + (sum result (scale cur-vol (sine cur-pch duration))))) + ((>= cur-ind loop-number) result) + (print cur-pch) + (print cur-vol)) diff --git a/WINDOW.ny b/WINDOW.ny new file mode 100644 index 0000000..ac11012 --- /dev/null +++ b/WINDOW.ny @@ -0,0 +1,16 @@ +;nyquist plug-in +;version 4 +;type process +;name "Apply Window" +;action "Windowing..." +;author "dm" + +(defun lump (width) + (lfo (/ 0.5 (get-duration 1) width) width)) + +(setq index (float (get '*TRACK* 'INDEX))) +(setq tracks (float (length (get '*SELECTION* 'TRACKS)))) +(setq start-time (/ (- index 1.0) tracks)) +(mult *TRACK* + (seq (s-rest start-time) + (cue (lump (/ 2.0 tracks))))) \ No newline at end of file