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