Spectral Processor Normalisation - what am I doing wrong?

Share your Audacity/Nyquist plug-ins here, or test drive the latest plug-ins submitted by Audacity users.

After testing a plug-in from this forum, please post feedback for the plug-in author.
Post Reply
essessandess
Posts: 5
Joined: Mon Dec 29, 2014 11:06 am
Operating System: Please select

Spectral Processor Normalisation - what am I doing wrong?

Post by essessandess » Thu May 24, 2018 8:41 am

Hi,

Here's
specprocnorrm_mr.ny
(904 Bytes) Downloaded 12 times
a simple spectral processor, based on a comment in this forum. I'm having trouble getting the 'normalize' function to work. I'm sure I'm doing something wrong, but can't see it. Any ideas, anyone?

Thanks in advance.

Martin

steve
Site Admin
Posts: 47974
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu
Contact:

Re: Spectral Processor Normalisation - what am I doing wrong

Post by steve » Thu May 24, 2018 9:31 am

I often find it easiest to initially develop plug-ins for mono only, then once it is working, expand it to also work with stereo. Taking that approach, let's look at your "normalize" function:

You have:

Code: Select all

(defun normalize (signal)
(setf x (if (arrayp signal)
(max (peak (aref signal 0) ny:all) (peak (aref signal 1) ny:all))
(peak signal ny:all)))
(scale (/ norm-level x) signal))
which can be read more easily with appropriate indentation:

Code: Select all

(defun normalize (signal)
  (setf x (if (arrayp signal)
              (max (peak (aref signal 0) ny:all)
                   (peak (aref signal 1) ny:all))
              (peak signal ny:all)))
  (scale (/ norm-level x) signal))
"(if (arrayp signal)" is saying; "if the signal is an array [stereo sounds are arrays], then do the first thing, otherwise [signal is mono] do something else"

So for a mono signal, we could rewrite it as:

Code: Select all

(defun normalize (signal)
  (setf x (peak signal ny:all))
  (scale (/ norm-level x) signal))
So "signal" is the mono signal that we pass to the function, "x" is the peak level of the signal, but what is "norm-level"?
The reason that your "normalize"function fails, is because you have not defined what "norm-level" is.
This can be seen from the first line of the debug output (run the effect with the Debug button to see the debug output):

Code: Select all

error: unbound variable - NORM-LEVEL
if continued: try evaluating symbol again
Function: #<Closure-NORMALIZE: #42eebc0>
Arguments:
  #<Sound: #407c758>
Function: #<FSubr-IF: #42f6698>
Arguments:
  (ARRAYP S)
  (VECTOR (NORMALIZE (LOWPASS8 (MULT MUMU (HIGHPASS8 (AREF S 1) 30) (HZOSC MIRR)) FREQ)) (NORMALIZE (LOWPASS8 (MULT MUMU (HIGHPASS8 (AREF S 0) 30) (HZOSC MIRR)) FREQ)))
  (NORMALIZE (LOWPASS8 (MULT MUMU (HIGHPASS8 S 30) (HZOSC MIRR)) FREQ))
1> 

How to do it correctly:

Let's say that we have a signal with a peak level of "0.8" [such a signal may be easily generated with "Generate menu > Tone" or "Generate > Noise"].
We can calculate the peak level of the sound like this:

Code: Select all

(setf peak-level (peak <sound> ny:all))
where:
"<sound>" is the mono audio that we are processing,
"peak" is the function that we are using http://www.cs.cmu.edu/~rbd/doc/nyquist/ ... l#index727
"peak-level" is the variable that takes the value returned by the "peak" function.

If we are using the new plug-in syntax (default in all recent versions of Audacity), then for a mono track, the variable "*track*" represents the selected audio, so we can write:

Code: Select all

(setf peak-level (peak *track* ny:all))
Running this in the Nyquist Prompt ("legacy syntax" should be disabled / not selected), then for our generated tone, we should see a return value very close to 0.8.

Now let's say that we want to scale this to a peak amplitude of 0.5.
To do this, we need to scale the audio by a factor of: "<target-amlitude> / <current-amplitude>"

The "scale" function multiplies each sample value by the specified amount, so we could write:

Code: Select all

(scale *track* (/ 0.5 0.8))
or identically:

Code: Select all

(mult *track* (/ 0.5 0.8))
Running the above code, you should see that the amplitude is now 0.5.

Putting this into a function, we can write the general case:

Code: Select all

(defun normalize (signal target)
  (setf old-level (peak signal ny:all))
  (mult signal (/ target old-level)))
and to use this function, we need to "call the function", and pass it two parameters; the signal, and the target level. For example:

Code: Select all

(setf target-amplitude 0.5)

(defun normalize (signal target)
  (setf old-level (peak signal ny:all))
  (mult signal (/ target old-level)))

(normalize *track* target-amplitude)
or we could set the target level with a slider:

Code: Select all

(setf target-amplitude 0.5)

(defun normalize (signal target)
  (setf old-level (peak signal ny:all))
  (mult signal (/ target old-level)))

(normalize *track* target-amplitude)
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

essessandess
Posts: 5
Joined: Mon Dec 29, 2014 11:06 am
Operating System: Please select

Re: Spectral Processor Normalisation - what am I doing wrong

Post by essessandess » Thu May 24, 2018 10:41 am

<embarrassed>Thanks for this detailed and informative answer. I now see that I copied and pasted the function without including the 'norm-level' control from earlier in the code. Doh! I need that Captain Piccard 'Slap Head' image... Code in haste, repent at leisure. </embarrassed>

Post Reply