your magic formulas for amp reduction when adding audio signals

phiol's icon

Hi all,
As the title indicates, I am curious to know what common practices or "rules of thumb" you guys use in this situations of adding signals together and wanting to avoid distortion clipping. This is common in many patching situations but is most true when using poly~.

I always "cheated" by using omx.peak~ or omx.comp~ but wanted to what the equation was.
I know amp is a log and so never used dividing the number of voices.
I also know that audio signals to add up at their maximum power , they need to align perfectly which rarely happens

I searched the forum and found and found a few things.
1. peter castine suggests: https://cycling74.com/forums/polyphony-varies-amplitude
Try sqrt(1), sqrt(1/2), sqrt(1/3)...

2. reference https://cycling74.com/forums/mixing-four-audio-signals-into-one
STEFAN TIEDJE suggests :
I'd say yes, each doubling of channels would require a attenuation of
about 3 dB, even if there is a theoretical chance that all hit at the
same sample a full volume, this chance is very minimal and gets
exponentially smaller the more signals you mix....

3. Tim Place’s tap.elixir~ <— want to get formula. is noisy and would like to avoid using 3rd party externals and also your are limited to 20 voices.

Here Below is a patch I made for testing.
there are 6 input sources of the same duduk.aif sample.
all explanations are included in the patch.
note: I did not use poly~ on purpose so that everything is more clear for you.

Thanks a lot in advance

phiol

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

phiol's icon

bump

Jean-Francois Charles's icon

It's an interesting question. It would be complicated if it were about loudness, and how we perceive added sounds.
It becomes simple when we stick to your words: "adding signals together and wanting to avoid distortion clipping".
Take a sine wave with full amplitude going all the way from -1 to 1.
Take the same sine wave, same phase. Add them together, what's the max amplitude? Well, -2 to +2, right?
Add a third one, what are the peaks? -3 and +3. Etc.
So, to make absolutely sure you avoid clipping in all situations, you have to just divide the added signals by the number of signals (-6 dB for 2 signals added up, -12 dB for 4 signals added together).

Now, when it comes to perception, you might prefer to do the "-3dB" rule, or the "sqrt" rule, but note what Stefan mentioned: there is a chance that all signals hit at the same sample a full volume, which would result in clipping. That's also what Brandon explained on FB.

phiol's icon

mmmm. interesting.
would it be possible to do something in gen~ where could apply this formula
Somme de grandeurs d'après les niveaux en dB
Somme de deux signaux indépendants L1 > L2

taken here
https://fr.wikipedia.org/wiki/D%C3%A9cibel

thanks

again , would be interesting to know how tim place's tap.elixir~ works.
I contacted c74 last friday but have not had a reply yet.

phiol

Jean-Francois Charles's icon

Just had a look at the tap.elixir external. It looks like it really just divides the amplitude by how many signals are there. The code is here: https://github.com/tap/TapTools/blob/a4c2a0572102ff727d7fd89b3805ef64bc574dce/source/tap.elixir%7E/tap.elixir%7E.cpp
See this excerpt in the elixir_doit() method:
if (x->elixir_toggle[i] != 0)
x->elixir_mult[i] = 1.0 / n;

If I read the code correctly, n is the number of active input signals. If you want to be 100% sure to avoid clipping, that's what you're going to do, divide by how many signals. If you want the "perception" to be "correct", then you will raise the volume to your liking, but either keep some overhead, or use a limiter/compressor.

phiol's icon

I appreciate you input Jean Francois.
Using the omx.peaklim and dividing the signal~ by the n amount of sig used is basically what I always did but as you say , the perception result seems to lower the sound way to fast and as you mention I would have to raise it . Thing is, I want this to be dynamic and especially when using this approach with poly~.

I'm curious to know, what do you do when using poly~ with dynamic voice amount.
Do you ever divide the signal amplitude by the amount of voices used ? or use the -3dB rule.
or the log10 rule or.......
I always used omx.peaklim and forget about it.

thanks again

phiol

Roman Thilenius's icon

in theory it is 1/n.

but of course this only makes sense when all signals are having an ideal peak level already, i.e. not to loud but close to 1.

in practice something like srt(1/n) works well, but to avoid clipping you will still have to use a limiter.

phiol's icon

thanks for your input
the best result I've had in the journey has been

1/n with a scaling factor on 1. where using [scale~ 1 24 1. 0.9] so the level doesn't diminish too much. it works great with 24 voices. almost no noticeable amp level lost.

thanks

Jean-Francois Charles's icon

And to answer Phiol on what I do when I have poly~ with dynamic voice amount, well, it turns out it's something I have not used much. My audio poly~s have usually a fixed number of voices.
Also, I started with never using compression, only relatively recently adding a limiter on an output. On Mac, I've been using AU Peak Limiter, by the way.