Apply gain to several files so the loudest one gets normalized to 1. ?

chapelier fou's icon

Sorry, I didn't find a better title for this question !

But let's say you have 8 audio files loaded in 8 buffers, and you want to find the one with the loudest amplitude peak, normalize it at max, get the corresponding gain, and apply that gain to the 7 other files ?

pdelges's icon

You can get the peak using [mxj buf.Op] (max message), find the biggest one of your buffers, get the ratio to normalize it, and multiply all buffers values with this ratio (multiply message).

chapelier fou's icon

Thanks, is it an external ?

Pedro Santos's icon
chapelier fou's icon

Thanks,

I'd rather find a way without installing it, any ideas ?

Well, except going through all sounds with peek~ and compare maximums, as it could be using too many resources.

TFL's icon

To get the peak of multiple samples maybe the easiest is using javascript. Here's an example for one sample:

Max Patch
Copy patch and select New From Clipboard in Max.

double_UG's icon

there is this array.frombuffer (array.tobuffer) object. But I cant get it work.

Max Patch
Copy patch and select New From Clipboard in Max.

chapelier fou's icon

Thank you Double_UG and TFL !

TFL's icon

My mehtod has mistakes, and [array.frombuffer] returns an array of arrays (one sub-array per channel). @flatsinglechannel 1 returns a flat array only if the buffer has one channel.

Here are both approaches corrected:

Max Patch
Copy patch and select New From Clipboard in Max.

TFL's icon

Instead of two [array.foreach] as I did above, using a combination of [array.max] and [array.min] is about 5 times faster (about as fast as the js approach):

Max Patch
Copy patch and select New From Clipboard in Max.

chapelier fou's icon

This is so cool. It both gives me a good introduction to arrays and directly solves my problem, thanks !

pdelges's icon

Interesting use of the [array.] family.

But my quick tests show that [mxj buf.Op] is much faster than [array.*] and v8. It makes really a huge difference with long files.

Max Patch
Copy patch and select New From Clipboard in Max.

TFL's icon

No Java here either :(

Adding a [peek~] + [peak] approach for the sake of it (spoiler: not good):

Max Patch
Copy patch and select New From Clipboard in Max.

chapelier fou's icon

Unrelated, but related question....

I've got the peak analysis and gain calculation of my (actually 14) files, and this part seems ok with the CPU, but applying the gain to the 14 stereo buffers (4-30seconds each) causes CPU spikes. As there's no way to get a bang out of the buffer when the gain has been applied, I'm out of ideas to quickly sequentially normalize them all (without setting an arbitrary, reasonable delay).

TFL's icon

You could apply the gain dynamically by multiplying the output of whatever you use to read your buffers, instead of changing the buffers data.

Source Audio's icon

why not condition audio files before using them in max in first place ?

chapelier fou's icon

@TFL : brilliant, why didn’t I think of that ?

@Source Audio : because I’ve already made thousands of files. I’m talking about hundreds of 14 file folders that are loaded manually during the performance

TFL's icon

because I’ve already made thousands of files. I’m talking about hundreds of 14 file folders that are loaded manually during the performance

You could process all of them in a batch using your max patch, you don't mind CPU spikes if you don't play audio. It seems like apply gain is synchronous so you could [t b b], right b go to the apply message, left b to write and you get your file written as soon as the gain is applied. write is asynchronous though, but once the process is done you get a bang from the [buffer~] right outlet that you can use to read the next file and repeat.