There’s somewhere a change in the functions.
I have tested it on a selection of three tracks,* and my own code results in…
Highest RMS is 0.362093 (-8.82359 dB)
Highest peak is 0.977234
Dynamic range (crest factor) based on highest RMS is 9 with 7039536 samples
…while your code returns:
Highest RMS is 0.563 (-5.0 dB).
Highest peak is 0.977 (-0.2 dB).
Crest factor based on highest values: 1.74 (4.8 dB).
Since I’m still trying to get my head around your code (way beyond my beginner’s level
) I can’t say right now what the problem might be.
Let’ try and break down your code:
number-to-string function
This one’s easy enough to understand, as we’ve already talked about it here. A function to format a number with two arguments:
- The number to format
- A number of digits indicating the number of post-comma decimals
peaks2 function
This one already trickier, as it has some features I’m not yet familiar with. sig seems to be a placeholder variable for whatever sound you want to feed to it, and it is my understanding that chosing the string sig is rather a personal choice than obligatory. In our plugin it eventually corresponds to track.
But the other argument means nothing to me: &key (maxlen ny:all) - well actually, I already came across maxlen for peak, it limits the evaluation to maxlen=x samples. (high 0) I believe resets the variable to 0 at each calling of the function.
(if (arrayp sig) does check wheter the track is stereo or mono or indeed a track with x channels…
dotimes creates a loop, once for each channel as (length sig) will return the number x of channels, because sig = track will be an array of x mono tracks.
The rest is “simple” peak expression voodoo 
I just don’t understand why there’s a high as a result expression in (dotimes (i (length sig) high).
mean-sq function
I must admit that I am perplexed by this function. It contains some error management (error…) and the code to calculate RMS. Why have you chosen the operator snd-avg over rms? My guess is that this operator allows a better control over the window size but I must admit I haven’t understood snd-avg and the blocksize and stepsize. I mean, the concept: yes, but not what it actually does.
rms2 function
(cond…) does (to me) the same as (if (arrayp sig) except allowing for a third option in case someone feeds something other than sound to this function.
I don’t get why rms has rate and window-size as optional arguments when “window size is 1/rate seconds” (I know I’m missing something, probably again the understanding of window-size and its relation to rate).
Doesn’t this function simply calculate the RMS?
peak-rms function
“Simply” calculates the RMS across multiple tracks
The remaining code seems to me straight-forward enough! (Did I really say that?)
- The Alan Parsons Project - Tales Of Mystery And Imagination, early 2000s pressing of the 1987 remix: tracks “The Fall of the House of Usher (instrumental): III Intermezzo”, “07. The Fall of the House of Usher (instrumental): II Arrival” and “10. The Fall of the House of Usher (instrumental): V Fall”