From 3b13b78c02eded2ae402531a8ad150e82a14d780 Mon Sep 17 00:00:00 2001 From: "stevethefiddle@gmail.com" Date: Sun, 12 Oct 2014 14:27:22 +0000 Subject: [PATCH] Code optimization and a bit of tidying by Paul Licameli. No changes to UI or algorithm. --- plug-ins/vocoder.ny | 119 +++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/plug-ins/vocoder.ny b/plug-ins/vocoder.ny index 5c38772e2..39eb9d048 100644 --- a/plug-ins/vocoder.ny +++ b/plug-ins/vocoder.ny @@ -9,6 +9,9 @@ ;; vocoder.ny by Edgar-RFT ;; a bit of code added by David R. Sky ;; GUI update by Steve Daulton July 2012. +;; Performance improvement, error message for mono, code cleanup +;; by Paul Licameli and Steve Daulton October 2014 + ;; Released under terms of the GNU General Public License version 2: ;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html ;; @@ -27,93 +30,107 @@ ; if you have lots of nyquist "[gc:" messages try this: ; (expand 100) ; gives Xlisp more memory but I have noticed no speed difference -; number of octaves between 20hz and 20khz +;; number of octaves between 20hz and 20khz (setf octaves (/ (log 1000.0) (log 2.0))) -; convert octaves to number of steps (semitones) +;; convert octaves to number of steps (semitones) (setf steps (* octaves 12.0)) -; interval - number of steps per vocoder band +;; interval - number of steps per vocoder band (setf interval (/ steps bands)) -; Some useful calculations but not used in this plugin +;;; Some useful calculations but not used in this plugin -; half tone distance in linear +;; half tone distance in linear ; (print (exp (/ (log 2.0) 12))) -; octave distance in linear +;; octave distance in linear ; (print (exp (/ (log 1000.0) 40))) -; The Radar Wavetable +;;; The Radar Wavetable -; make *radar-table* a global variable. +;; make *radar-table* a global variable. (setf contol-dummy *control-srate*) ; save old *control-srate* (set-control-srate *sound-srate*) (setf *radar-table* (pwl (/ 1.0 *control-srate*) 1.0 ; 1.0 after 1 sample (/ 2.0 *control-srate*) 0.0 ; 0.0 after 2 samples (/ 1.0 radar-f))) ; stay 0.0 until end of the period (set-control-srate contol-dummy) ; restore *control-srate* -; make *radar-table* become a nyquist wavetable of frequency radar-f +;; make *radar-table* become a nyquist wavetable of frequency radar-f (setf *radar-table* (list *radar-table* (hz-to-step radar-f) T)) -; increase the volume of the audacity track in the middle of the slider -; the sqrt trick is something like an artifical db scaling +;; increase the volume of the audacity track in the middle of the slider +;; the sqrt trick is something like an artifical db scaling (setf track-vol (sqrt (/ track-vl 100.0))) -; decrease the volume of the white noise in the middle of the slider -; the expt trick is an inverse db scaling +;; decrease the volume of the white noise in the middle of the slider +;; the expt trick is an inverse db scaling (setf noise-vol (expt (/ noise-vl 100.0) 2.0)) -; also increase the volume of the needles in the middle of the slider +;; also increase the volume of the needles in the middle of the slider (setf radar-vol (sqrt (/ radar-vl 100.0))) -; here you can switch the tracks on and off for bug tracking +;;; here you can switch the tracks on and off for bug tracking ; (setf radar-vol 0) ; (setf noise-vol 0) ; (setf track-vol 0) -; The Mixer +;;; The Mixer -; calculate duration of audacity selection +;; calculate duration of audacity selection (setf duration (/ len *sound-srate*)) -; if track volume slider is less than 100 percent decrease track volume -(if (< track-vl 100) (setf s (vector (aref s 0) (scale track-vol (aref s 1))))) +(defun mix () + ;; if track volume slider is less than 100 percent decrease track volume + (if (< track-vl 100) + (setf s + (vector (aref s 0) (scale track-vol (aref s 1))))) -; if radar volume slider is more than 0 percent add some radar needles -(if (> radar-vl 0) (setf s (vector (aref s 0) (sim (aref s 1) - (scale radar-vol (osc (hz-to-step radar-f) duration *radar-table*)))))) + ;; if radar volume slider is more than 0 percent add some radar needles + (if (> radar-vl 0) + (setf s + (vector (aref s 0) + (sim (aref s 1) + (scale radar-vol (osc (hz-to-step radar-f) + duration *radar-table*)))))) -; if noise volume slider is more than 0 percent add some white noise -(if (> noise-vl 0) (setf s (vector (aref s 0) (sim (aref s 1) - (scale noise-vol (noise duration)))))) + ;; if noise volume slider is more than 0 percent add some white noise + (if (> noise-vl 0) + (setf s + (vector (aref s 0) + (sim (aref s 1) (scale noise-vol (noise duration))))))) -; The Vocoder +;;; The Vocoder (defun vocoder () - (let ((p (+ (hz-to-step 20) (/ interval 2.0))) ; midi step of 20 Hz + offset - f ; we can leave f initialized to NIL - (q (/ (sqrt 2.0) (/ octaves bands))) ; explanation still missing - (result 0)) ; must be initialized to 0 because you cannot sum to NIL - (dotimes (i bands) - (setf f (step-to-hz p)) - (setf result (sum result - (bandpass2 (mult (lowpass8 - (s-max (bandpass2 (aref s 0) f q) - (scale -1 (bandpass2 (aref s 0) f q))) (/ f dst)) - (bandpass2 (aref s 1) f q)) f q))) - (setf p (+ p interval))) - result)) + (do* ((i 0 (1+ i)) + mod-envelope ; local variable for filtered envelope of left channel. + band ; local variable for band-passed audio. + (result 0) ; result must be initialized because you cannot sum to NIL. + (q (/ (sqrt 2.0) (/ octaves bands))) ; quick approximation of q + ; for given bandwidth. + (p (+ (hz-to-step 20) (/ interval 2.0)) ; midi step of 20 Hz + offset. + (+ p interval)) + (f (step-to-hz p) (step-to-hz p))) + ((= i bands) result) ; DO for each band then return 'result'. + (setf band (bandpass2 s f q)) ; intermediate results (2 channels) + (setf mod-envelope (lowpass8 (s-abs (aref band 0)) (/ f dst))) + (setf result + (sum result + (bandpass2 + (mult mod-envelope (aref band 1)) + f q))))) -; The Program - -(if (arrayp s) (let () - (cond ((= mst 1) (vector (aref s 0) (setf (aref s 1) (vocoder)))) - ((= mst 0) (setf s (vocoder)))) - (cond ((= mst 1) (setq peakamp (peak (aref s 1) ny:all))) - ((= mst 0) (setq peakamp (peak s ny:all)))) - (cond ((= mst 1) (vector (aref s 0) (setf (aref s 1) - (scale (/ 1.0 peakamp) (aref s 1))))) - ((= mst 0) (setf s (scale (/ 1.0 peakamp) s)))) - s) - "Error.\nStereo track required.") +;;; The Program +(cond + ((arrayp s) + (mix) ; changes s + (let ((original (or (= mst 0) (aref s 0)))) + (setf s (vocoder)) + ;; Now normalize s to 0 db peak + (setf s (scale (/ (peak s ny:all)) s)) + (case mst + (0 s) ; let Audacity coerce back to stereo + (1 (vector original s))))) + (t ; this effect isn't meant for mono + "Error.\nStereo track required."))