Re: Audacity-Nyquist wish list - Peak level

Currently the only data passed from Audacity to Nyquist is the selected audio data (in the global variable “s”)
Due to the problems* in Audacity-Nyquist for calculating the peak level for long tracks, it would be a very useful feature if the peak level of the audio was also sent to Nyquist in an additional global variable.

User case:
It is desirable for many plug-ins to normalize the output. Many of the plug-ins on the Audacity web-site will automatically attempt to normalize the output (or have an option to do so). The method for doing this is to calculate the peak level, then scale the output by the inverse of the peak level.

(mult sound (/ (peak sound NY:ALL)))

Unfortunately this method will cause Audacity to crash when applied to very long tracks due to running out of memory.
There is currently no known method of calculating the peak level while retaining the availability of the audio data without loading the audio data into RAM in full, so the maximum length that can be normalised without making Audacity crash or hang is limited by the amount of available RAM.

The closest method to solving this problem is described here: http://www.cs.cmu.edu/~music/nyquist/debug-plugin.html
The main disadvantage of this method (apart from its complexity) is that it requires normalisation to be done in two passes (running the effect twice).

If Audacity passed to Nyquist the peak level along with the audio, then this problem would alleviated (though not “solved”).

Following an off-forum discussion with Edgar:

The Audacity “Amplify…” effect calculates the peak value on-the-fly

I see no reason why this cannot be done from within the Nyquist .c source code someplace right at the beginning of the initialization of the process and stored in some global Nyquist variable.

Audacity must do this extremely quickly as the value is displayed almost instantly when the Amplify effect is opened, even with really long selections.

Regarding Nyquist’s access to the sound we have two global variables - “s” (the sound or in the case of stereo tracks an array of sounds), and the global “LEN” (the length in samples). I doubt that the developers would be keen on adding more global variables without a lot of discussion (probably not keen at all), however in Nyquist I can do this:

(putprop 's
  (if (arrayp s)
     (vector (peak (aref s 0) ny:all)(peak (aref s 1) ny:all))
     (peak s ny:all))
   'peak)

with comments:

(putprop 's   ; add a property to symbol 's'
  (if (arrayp s)   ; if 's' is a stereo array
    (vector (peak (aref s 0) ny:all)(peak (aref s 1) ny:all)) ; create an array with the peak values
    (peak s ny:all))   ; else just the one peak value
  'peak)   ; property name

What this does is to put the calculated peak amplitude value (per channel) as a property called ‘peak’ in the symbol ‘s’.

The peak amplitude may then be conveniently read with:

(get 's 'peak)

The BIG problem with this is that the Nyquist function (peak ) is slow and memory hungry so cannot be used for long selections as Audacity will freeze/crash if it runs out of RAM.

My proposal is that since Audacity can calculate the peak value extremely quickly (and without running into memory problems), that Audacity does the calculation and adds the property ‘peak’ to the global ‘s’ at the time that it sets the value of 's’.

How feasible is this?
If this could be done it would benefit perhaps 50% of Nyquist effects.

If you look at an AUP file you will see lots of bits like this:

It appears that Audacity is already calculating the +/1 peak and rms value for each blockfile. So all the Amplify effect has to do is glean this information from the AUP file.

+1 for adding the “peak” property.

– Bill

I have absolutely no idea where the “bundle of information” is created and stuffed into the symbol “s”. Audacity must be doing this in the c source code and passing it along to the Nyquist interpreter but that code is so obscure (the variable and function names are meaningless) that is almost impossible to figure out what is going on or to search for relevant sections of code with a search feature of the text editor. If someone familiar with this code wants to point me in the right direction, coding the actual calculation is just a matter of cut and paste of a few lines.