[Audacity-nyquist] text version of fir10.ny
A free multi-track audio editor and recorder
Brought to you by:
aosiniao
|
From: David R. S. <dav...@sh...> - 2006-04-17 14:39:48
|
Text of fir10.ny is below. David ;nyquist plug-in ;version 2 ;type process ;name "FIR filter 1.0..." ;action "Applying your FIR filter settings..." ;info "by David R. Sky, thanks to Gary nelson for DSP help\nRepeat value repeats the taps list you have created, appends the second taps list, then inserts zeros between the tap values.\nIf normalization value > 0, normalization will be applied to result at that level.\nReleased under terms of GNU Public License" ;control choice "Choice: 0=convolve 1=test convolution 2=display tap values" int "" 0 0 2 ;control type "Type: 0=linear phase 1=moving average" int "" 0 0 1 ;control result "Result: 0=positive 1=complementary" int "" 0 0 1 ;control values1 "Tap values" string "" "1 1 1 1 1 1 1 1 1 1 1" ;control zeros-1 "Units number of zeros between taps" int "" 0 0 1000 ;control zeros-1000 "Thousands of zeros between taps" int "" 0 0 10 ;control mirror "Mirror above taps list: 0=no 1=yes" int "" 0 0 1 ;control where "Mirror last tap: 0=no 1=yes" int "" 0 0 1 ;control repeat "Repeat above taps list" int "" 0 0 1000 ;control values2 "Additional taps list" string "" "" ;control gain "Gain - percent" int "" 100 0 100 ;control norm "Above 0, normalization will be applied to result at this level" int "" 0 0 100 ; FIR filter 1.0 by David R. Sky with DSP help by Gary nelson ; April 17, 2006 a.m. ; Released under terms of the GNU Public License ; http://www.opensource.org/licenses/gpl-license.php ; determine duration of Audacity selection (setf dur (/ len *sound-srate*)) ; convert gain percent to floating value (setf gain (* 0.01 gain)) ; Format users tap values list into a LISP expression ; and evaluate. ; The result is assigned to symname. ; function written by Steven Jones ; for his Harmonic Noise Generator plug-in (defun eval-string-to-list (symname str) (let ((form (strcat "(setq " symname " (list " str "))"))) (eval (read (make-string-input-stream form))))) ; convert values1 & values2 string inputs ; into list1 and list2 (eval-string-to-list "list1" values1) (eval-string-to-list "list2" values2) ; set reverse (mirrored) copy of list1 (setf mirror1 (reverse list1)) ; if where is 0, remove first value from mirror1 ; (if do not mirror last tap value) (if (= where 0) (pop mirror1)) ; when mirror=1, ; add mirror copy of list to itself (defun add-mirror (list1 mirror1) (setf list1 (append list1 mirror1))) ; extend list1 with mirror1 list if mirror=1 (setf list1 (cond ; do not add mirror ((= mirror 0) list1) ; add mirror ((= mirror 1) (add-mirror list1 mirror1) ) ; end = mirror 1 ) ; end cond ) ; end setf list1 ; initialize master list (setf master-list list1) ; repeat list1 (dotimes (i repeat ) (setf master-list (append master-list list1)) ) ; end dotimes i ; appending list2 to master-list (setf master-list (append master-list list2)) ; calculate total zeros ; units-zeros plus thousands-zeros (setf zeros (+ zeros-1 (* zeros-1000 1000))) ; function to convert list to array + add zeros between taps (defun list2array (list zeros) (setf interval (+ zeros 1)) (setf len-array (+ 1 (* interval (- (length list) 1)))) (setf array1 (make-array len-array)) (dotimes (i (- (length list) 1)) (setf (aref array1 (* i interval)) (nth i list)) (dotimes (j zeros) (setf (aref array1 (+ j 1 (* i interval))) 0) ) ; end dotimes j ) ; end dotimes i (setf (aref array1 (- len-array 1)) (nth (- (length list) 1) list)) ) ; end defun list2array ; convert master list of tap values to array1, ; with zeros between user-defined tap values (list2array master-list zeros) ; function to determine weight of list or array (defun weigh (i input length total) (if (< i length) (weigh (+ i 1) input length (+ total (nth i input)) ) ; end weigh total) ; end if ) ; end defun weigh ; calculate weight of master list ; including gain (setf len1 (length master-list)) (setf weight1 (weigh 0 master-list len1 0.0)) (if (= weight1 0) (format nil "Error - your tap values total a weight of zero. ~% ~% convolve function not tested or applied.") ) ; end if (setf gain (/ gain weight1)) ; convert array1 to convolve response signal (setq response (snd-from-array 0 *sound-srate* array1)) ; check that there are odd number of tap values ; for linear phase convolution. (if (and (= type 0) (evenp (length array1))) (format nil "Error - tap values list has even number of tap values - ~a. ~% ~% Number of tap values must be odd for linear phase convolution. ~% ~% You can enter an even number of tap values with an odd number of zeros, vice versa, or add an odd number of tap values into the second tap values list." (length array1)) (setf len-sil1 (if (= type 0) ; linear phase=no prepended or appended zeros 0 ; otherwise, prepend and append zeros for moving average (truncate (* 0.5 (length array1))) ) ; end if ) ; end setf ) ; end if and ; number of appended zero samples (setf len-sil2 len-sil1) ; convert number of samples to duration in seconds: (setf len-sil1 (/ len-sil1 *sound-srate*)) (setf len-sil2 (/ len-sil2 *sound-srate*)) ; add silence (zero padding) before and after Audacity selection (defun zero-pad (dur len-sil1 len-sil2 sound) (sim (cue (s-rest len-sil1)) (at-abs len-sil1 (cue sound)) (at-abs (+ dur len-sil1) (cue (s-rest len-sil2))) ) ; end sim ) ; end defun zero-pad ; convolve function using built-in Nyquist convolve (defun convolve-s (signal dur len-sil1 len-sil2 gain response) (if (arrayp signal) (vector (convolve (zero-pad dur len-sil1 len-sil2 (aref signal 0)) (mult gain response)) (convolve (zero-pad dur len-sil1 len-sil2 (aref signal 1)) (mult gain response)) ) ; end vector (convolve (zero-pad dur len-sil1 len-sil2 signal) (mult gain response)) ) ; end if arrayp s ) ; end defun convolve-s ; function to normalize output of convolution result ; which is only applied when norm (normalization level) > 0 (defun normalize (norm signal) (cond ((> norm 0) (setf norm (* 0.01 norm)) (setf x (if (arrayp signal) (vector (max (peak (aref signal 0) ny:all) (peak (aref signal 1) ny:all) )) ; end max, vector (peak signal ny:all) ) ; end if arrayp ) ; end setf x (scale (/ norm x) signal) ) ; end norm>0 (t ; don't apply normalization, just generate convolution result (cue signal)) ) ; end cond ) ; end defun normalize ; Convolve, test convolution, or display tap values (cond ((= choice 0) ; apply convolution ; s1 is the signal ; to be added to the convolved result. ; if result=0 (positive) convolution, ; silence of duration 0 is added, ; otherwise inverted s is added to result ; to make complementary result. (setq s1 (if (= result 0) (s-rest 0.0) (mult -1.0 (zero-pad dur len-sil1 len-sil2 s)) ) ; end if ) ; end setq (normalize norm (sim (cue s1) (cue (convolve-s s dur len-sil1 len-sil2 gain response)) ) ; end sim ) ; end norm ) ; end choice=0 convolve ((= choice 1) ; apply convolve test to stereo Audacity selection ; end result: original l channel audio is in left channel ; convolve response is in right channel (if (arrayp s) ; if input signal is stereo (vector ; left channel, with zero padding at end (sim (cue (aref s 0)) (at-abs dur (s-rest (+ len-sil1 len-sil2))) ) ; end sim ; right channel (convolve (zero-pad dur len-sil1 len-sil2 (aref s 1)) (mult gain response)) ) ; end vector (format nil "Error - input signal is mono. ~% ~% For testing purposes, input signal must be in stereo, with identical signals in both channels. ~% ~% To create stereo input signal, select new stereo track from Project Menu in Audacity pre-1.3, otherwise from Track Menu in Audacity 1.3.x. Then create (load) a signal such as white noise or a tone from the Generate Menu and run the convolve test on that audio. ~% ~% after convolve test, original signal is in left channel, output convolved result is in right channel. ~% ~%") ) ; end if ) ; end choice=1 apply convolution test (t ; choice=2 display tap values (format nil "The list of tap values is: ~% ~a ~% " array1) ) ; end choice=2 display tap values ) ; end cond #| sss Changes/features: local: let for testing: comb generator using individual samples |# |