From d8ce078a6b8013864d00bf97c19353ad9fc31a4f Mon Sep 17 00:00:00 2001 From: "v.audacity" Date: Mon, 30 Jul 2012 22:45:52 +0000 Subject: [PATCH] Steve's updated delay.ny (http://bugzilla.audacityteam.org/show_bug.cgi?id=533) --- plug-ins/delay.ny | 222 +++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 113 deletions(-) diff --git a/plug-ins/delay.ny b/plug-ins/delay.ny index fda0cc904..7e14a40df 100644 --- a/plug-ins/delay.ny +++ b/plug-ins/delay.ny @@ -3,130 +3,126 @@ ;type process ;categories "http://lv2plug.in/ns/lv2core#DelayPlugin" ;name "Delay..." -;action "Performing Delay Effect..." -;info "by Roger Dannenberg, modified by David R. Sky\nReleased under terms of the GNU General Public License Version 2 \nDelay type: 'bouncing ball' makes the echoes occur increasingly close\ntogether (faster); 'reverse bouncing ball' makes them occur increasingly far\napart (slower). In either bouncing ball effect, delay time is not time between\nechoes but the * maximum * delay time in bounces.\nApplying delay can cause clipping (distortion), especially when reducing the\ndecay value and using more echoes. It's normally best to use Effect > Amplify\nto set the peak amplitude to -6 dB before using delay. +;action "Applying Delay Effect..." +;info "by Steve Daulton. Based on an effect by David R. Sky.\nReleased under GPL v2.\n" + +;; by Steve Daulton, July 2012. +;; based on 'Delay' by David R. Sky +;; Released under terms of the GNU General Public License version 2: +;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +;; +;; For information about writing and modifying Nyquist plug-ins: +;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference ;control delay-type "Delay type" choice "regular,bouncing ball,reverse bouncing ball" 0 -;control decay "Decay amount [dB; negative value increases volume]" real "" 6 -1 24 -;control delay "Delay time [seconds]" real "" 0.5 0 5 -;control shift "Pitch change per echo [semitones; negative value = lower, 0 is off]" real "" 0 -2 2 -;control count "Number of echoes" int "" 5 1 30 - -; Delay by Roger B. Dannenberg -; modified by David R. Sky October 2007, -; adding negative decay values, which gives delay effect -; increasing volume with each delay; and adding -; bouncing ball and reverse bouncing ball delay effects -; and pitch [semitone] change with each echo. -; modified by Richard Ash January 2008, removing all -; normalization functions. - -; Note by Roger Dannenberg: this effect will use up memory proportional to -; delay * count, since that many samples must be buffered -; before the first block is freed. - -; initialize empty error message -(setf error-msg "") +;control dgain "Delay level per echo (dB)" real "" -6 -30 1 +;control delay "Delay time (seconds)" real "" 0.3 0 5 +;control pitch-type "Pitch change effect" choice "Pitch/Tempo,LQ Pitch Shift" 0 +;control shift "Pitch change per echo (semitones)" real "" 0 -2 2 +;control number "Number of echoes" int "" 5 1 30 +;control constrain "Allow duration to change" choice "Yes,No" 0 -; check function: returns 1 on error -(defun check (arg min max) -(if (and (>= arg min) (<= arg max)) -0 1)) +;; The default pitch shift effect is a simple resampling, +;; so both pitch and tempo of the delayed audio will change +;; [as in Audacity's Change Speed effect]. +;; LQ Pitch Shift (Low Quality) changes the pitch without +;; changing the tempo, but the sound quality is not very good +;; and tends to cause a short echo effect which can be quite +;; noticeable on percussive sounds though may be acceptable +;; on other sounds. + +(setf err "") ; initialise error message + +(defun err-chk (arg min max) + (if (or (< arg min) (> arg max)) + T nil)) + +(when (err-chk number 1 50)(setq err (format nil + "Number of echoes '~a' outside valid range 1 to 50.~%~a" + number err))) + +(when (err-chk shift -12 12)(setq err (format nil + "Pitch change '~a' outside valid range -12 to +12 semitones.~%~a" + shift err))) + +(when (err-chk delay 0 10)(setq err (format nil + "Delay time '~a' outside valid range 0 to 10 seconds.~%~a" + delay err))) + +(when (err-chk dgain -30 6)(setq err (format nil + "Delay level '~a' outside valid range -30 to +6 dB.~%~a" + dgain err))) -; checking for erroneous user-input values: -(setf error-msg (if (= (check decay -1 24) 0) -error-msg -(strcat error-msg -(format nil "Decay value '~a' outside valid range -1.0 to 24.0 dB. -" decay)))) - -(setf error-msg (if (= (check delay 0 5) 0) -error-msg -(strcat error-msg -(format nil "Delay value '~a' outside valid range 0.0 to 5.0 seconds. -" delay)))) - -(setf error-msg (if (= (check shift -2 2) 0) -error-msg -(strcat error-msg -(format nil "Pitch change value '~a' outside valid range -2.0 to 2.0 semitones. -" shift)))) - -(setf error-msg (if (= (check count 1 30) 0) -error-msg -(strcat error-msg -(format nil "Number of echoes '~a' outside valid range 1 to 30 echoes. -" count)))) -; finished error-checking - -; if error-msg is longer than 0 characters, -; prepend opening message -(setf error-msg (if (> (length error-msg) 0) -(strcat "Error -\n\nYou have input at least one invalid value: -" error-msg) -error-msg)) - -(cond ; 1 -((> (length error-msg) 0) -(format nil "~a" error-msg)) - -(t ; no input errors, perform delay - -; convert shift value to a value the Nyquist code understands -(setf shift (expt 0.5 (/ shift 12.0))) - -; for bouncing ball effects, set delay time to delay time/count -(setf delay (if (> delay-type 0) -(/ delay count) delay)) +;;; anti-alias low pass filter +(defun lp-wall (sig freq) + (do ((count 0 (1+ count)) + (freq (* 0.94 freq))) + ((= count 10) sig) + (setf sig (lowpass8 sig freq)))) - -; function to stretch audio -(defun change (sound shift) -(if (arrayp sound) -(vector -(force-srate 44100 (stretch-abs shift (sound (aref sound 0)))) -(force-srate 44100 (stretch-abs shift (sound (aref sound 1))))) -(force-srate 44100 (stretch-abs shift (sound sound))))) +;;; Change speed +(defun change-speed (sig shift) + (if (= shift 0) ; no pitch shift + sig + (let ((ratio (expt 0.5 (/ shift 12.0)))) ; shift value as frequency ratio + (force-srate *sound-srate* + (stretch-abs ratio (sound sig)))))) -(cond ; 2 -((= delay-type 0) ; regular delay -; delay function -(defun delays (s decay delay count shift) - (if (= count 0) (cue s) - (sim (cue s) - (loud decay (at delay (delays (change s shift) -decay delay (- count 1) shift)))))) +;;; pitch shift audio +(defun p-shift (sig shift) + (if (= shift 0) ; no pitch shift + sig + (let ((sig (force-srate 44100 sig)) ; pitshift quality best at 44100 + ; anti-alias filter frequency + (minrate (* 0.5 (min *sound-srate* 44100))) + (ratio (expt 0.5 (/ shift -12.0)))) ; shift value as frequency ratio + (force-srate *sound-srate* ; convert back to correct rate + (progv '(*sound-srate*) (list 44100) ; pitshift requires rates to match + (cond + ((> shift 5) ; reduce aliasing + (pitshift (lp-wall sig (/ minrate ratio)) ratio 1)) + ((< shift -2) + (pitshift (hp sig 20) ratio 1)) ; reduce sub-sonic frequencies + (T (pitshift sig ratio 1)))))))) -(stretch-abs 1 (delays s (- 0 decay) delay count shift))) +;;; apply effects to echo +(defun modify (sig num gain shift p-type) + (let ((gain (db-to-linear (* num gain))) + (shift (* num shift))) + (if (= p-type 0) + (mult gain (change-speed sig shift)) + (mult gain (p-shift sig shift))))) +;;; compute echoes +(defun delays (sound gain delay shift num type mod) + (let ((echo (s-rest 0))) + (do ((count 1 (1+ count)) + (dly 0)) + ((> count num)(sim echo sound)) + (setq dly + (case type + (0 (+ dly delay)) + (1 (+ dly (* delay (- (1+ num) count)))) + (2 (+ dly (* delay count))))) + (setf echo (sim + (at 0 (cue echo)) + (at-abs dly + (cue (modify sound count gain shift mod)))))))) -((= delay-type 1) ; bouncing ball delay -; bouncing ball delay function -(defun bounces (s decay delay count shift) - (if (= count 0) (cue s) - (sim (cue s) - (loud decay (at (mult delay count) -(bounces (change s shift) decay delay -(- count 1) shift)))))) +(defun constrain-abs (sig dur) + (extract-abs 0 dur (cue sig))) -(stretch-abs 1 (bounces s (- 0 decay) delay count shift))) - - -((= delay-type 2) ; reverse bouncing ball delay -; reverse bouncing ball delay function -(defun revbounces (s decay delay count revcount shift) - (if (= count 0) (cue s) - (sim (cue s) - (loud decay (at (mult delay (- revcount count)) -(revbounces (change s shift) decay delay -(- count 1 ) revcount shift)))))) - -(setf revcount (1+ count)) -(stretch-abs 1 (revbounces s (- 0 decay) delay count revcount shift))) -) ; end cond2, different delay effect choices -) ; end cond1 t -) ; end cond 1 +;;; return errors or process +(if (> (length err) 0) + (format nil "Error.~%~a" err) ; return error + (let* ((delay (if (= delay-type 0) delay (/ delay number))) + (output + (multichan-expand #'delays + s dgain delay shift number delay-type pitch-type))) + (if (= constrain 1) + (multichan-expand #'constrain-abs output (get-duration 1)) + output)))