;version 1
>
No need to go all the way back to version 1. Audacity 2.0.6 fully supports version 3 plug-ins.
Better to use:
```text
;version 3
;control f “Center frequency” real “Hz” 440.0 20.0 20000.0
;control width “Bandwidth” real “octaves” 1.0 0.01 5.0
>
The ranges of these controls are excessive.
Your code is intended to apply multiple filters at harmonic intervals. For the default Audacity sample rate of 44100 Hz, any frequency above 11025 Hz will not have any harmonics before the physical limit of half the sample rate. Also a 5 octave bandwidth is going to stretch across multiple harmonics and 2.5 octaves below 22 kHz is less than 4 kHz. Generous but more reasonable ranges might be something like:
```text
;control f "Center frequency" real "Hz" 440.0 20.0 4000.0
;control width "Bandwidth" real "octaves" 0.1 0.01 1.0
;control amplify “Apply amplification” int “0=no 1=yes” 1 0 1
>
No need to use an "int" widget when a "choice" widget would be more appropriate. The multi-choice widget is supported in version 3 plug-ins and later.
Better to use:
```text
;control amplify "Apply amplification" choice "No, Yes" 1
(setf x (if (not (arrayp signal))
>
Why are you setting a value for "x"? You don't use the variable "x" anywhere.
And why are you testing for "not" an array? Better to test if it "is" an array, so rather than saying:
"If signal is not an array, do A, otherwise do B"
you can say:
"if signal is an array, do B, otherwise do A"
Your function "normalize" does not actually normalize. It just finds the peak level of the audio. If the audio is mono, the function returns the peak level. If the audio is stereo, it returns the maximum of the levels of each channel. This function would be better written as:
```text
(defun peak-level (signal level)
(if (arrayp signal)
(max (peak (aref signal 0) ny:all)
(peak (aref signal 1) ny:all))
(peak signal ny:all)))
(setq mysound s)
>
Why are you creating a global variable "mysound"? In version 3 plug-ins, "S" is a global variable holding the selected audio. It is unnecessary to create a new global variable that has the same value as "S".
\
<br>
> ```text
(setq r *sound-srate*)
Why are you creating a global variable “r”? You already have a global variable sound-srate which you can use directly, so your line:
(setq iter (truncate (/ (/ r f) 2)))
could be written as:
(setq iter (truncate (/ (/ *sound-srate* f) 2)))
but what is “iter”?
The name suggests that it is an iterator, but you have set it to half of (sample-rate / centre-frequency).
I presume that you want this value so that you can limit the number of times that you loop the filter - in other words, you want to know how many harmonics of “f” you can have without exceeding (sample-rate / 2).
Better to write this as:
(setq number-of-harmonics (truncate (/ (/ *sound-srate* 2) f)))
(defun EQ (mysound f iter)
>
"EQ" is a keyword in LISP (see: http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-099.htm)
While it is not an error to reuse it as a variable, it is potentially confusing to do so. Better to use a more descriptive name such as "equalize".
The variable "iter" has a confusing name because you are not using it as an iterator, but simply an integer for the maximum number of loops. Less confusing to call it something like "num" (an abbreviation of "number"), so I would write that line as something like:
```text
(defun equalize (mysound hz num)
(eq-band mysound (* f (1+ i)) (* width) (* gain))
>
OK, so here you are using the function (eq-band signal hz gain width) , but why have you used (* width) and (* gain)? That is meaningless.
As "width" and "gain" are global variables, set by controls, you can simply write:
```text
(eq-band mysound (* f (1+ i)) gain width))))
So here is that function rewritten:
(defun equalize (mysound hz num)
(dotimes (i num mysound)
(setf mysound
(eq-band mysound (* f (1+ i)) gain width))))
Note that the order of parameters is important. If you call eq-band with (eq-band signal hz width gain), then you will probably get an error, and certainly get the wrong result because the width and gain parameters are the wrong way round. Note also that “DOTIMES” counts from 0 to NUM, which means that the final loop will have a frequency greater than half the sample rate, which is an error. To avoid that error, use:
(dotimes (i (- num 1) mysound)
This next part has multiple problems:
; applying EQ
(if (= amplify 0)
(eq-band mysound f gain width)
(normalize (eq-band mysound f gain width) level))
>
I assume that what you are wanting to do, is to apply normalization to the processed audio if "Apply amplification" is set to "yes", but it does not do that. If the test (= amplify 0) is true, then this code applies EQ-BAND, but surely you want it to apply your looped filter which you called "EQ"?
If the test is false, then this code runs the function "normalize" (which as explained above does not actually normalize anything), and uses EQ-BAND as the "sound" parameter, whereas I expect that you actually want to use your "EQ" filter. So we could write this code like this, assuming that we fix the "normalize" function to actually normalize:
```text
(if (= amplify)
(normalize (equalize mysound f number-of-harmonics) level)
(equalize mysound f number-of-harmonics))
and we can correct the normalize function like this:
(defun normalize (signal level)
(setf peak-level
(if (arrayp signal)
(max (peak (aref signal 0) ny:all)
(peak (aref signal 1) ny:all))
(peak signal ny:all)))
(mult (/ level peak-level) signal))
The final part of your code:
(vector (eq (aref s 0) f iter)
(eq (aref s 1) f iter))
(eq s f iter))
>
This is unnecessary (and won't work as intended). As with most of the high level processing functions, the EQ-BAND function works with either mono or stereo sound.
So here's the full plug-in as code, and at the bottom below is a slightly tidier version as a downloadable file.
```text
;nyquist plug-in
;version 3
;type process
;name "Group EQ"
;action "Removing harmonics, ( this may take some time ) ..."
;control fc "Center frequency" real "Hz" 440.0 20.0 4000.0
;control width "Bandwidth" real "octaves" 0.1 0.01 1.0
;control gain "Gain" real "db" 0.0 -48.0 48.0
;control amplify "Apply amplification" choice "Yes,No" 0
;control level "Level" real "linear" 1.0 0.0 1.0
(defun normalize (signal level)
(setf peak-level
(if (arrayp signal)
(max (peak (aref signal 0) ny:all)
(peak (aref signal 1) ny:all))
(peak signal ny:all)))
(mult (/ level peak-level) signal))
(defun equalize (mysound hz num)
(dotimes (i (1- num) mysound)
(setf mysound
(eq-band mysound (* hz (1+ i)) gain width))))
(setq number-of-harmonics (truncate (/ (/ *sound-srate* 2) fc)))
(if (= amplify 0)
(normalize (equalize S fc number-of-harmonics) level)
(equalize S fc number-of-harmonics))
Groupeq.ny (1.71 KB)