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.
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 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:
(if (arrayp s)
(vector (peak (aref s 0) ny:all)(peak (aref s 1) ny:all))
(peak s ny:all))
(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.
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.