hi
including the mailing list again, as i guess that you already know what
i am talking about...
Andy Farnell wrote:
>
> A patch with N contributory signals, like an additive synth.
> The mix is (s1 + s2 + s3 ... sN) / N
> If each voice has a small DC offset then the sum will eventually drift
> outside the bounds -1.0 +1.0. When it happens in Pd the output goes silent.
what you are describing is valid for _any_ signal addition (whether it
uses throw~/catch~, an explicit [+~] or implicit addition by connecting
several signal-cords to a single inlet~.
apart from that it is not true at all.
if each voice has a small DC offset of µ (for the lack of epsilon on my
keyboard), where µ is max(abs(DCn)) then the sum of the offsets will be
µ*N and since you are normalizing by N the resulting offset will be µ
(since µ is actually an upper boundary of the real offsets, the real
resulting offset will be guaranteed to be no more than µ)
>
> In some systems a certain safe way of working is to just add carelessly,
> do the division and then use a single DC trap at the end to remove any
> accumulated error in the sum.
>
> Most times this works fine in Pd.
>
> Otherwise you'd need N divisions and N [hip~] all before the sum which
> is expensive.
how come you assume a difference in the 2 approaches?
since [hip~] is a linear-time-invariant system, applying it to the sum
of the signals should yield the same result as applying it to each
signal and then summing them.
the differences are mainly in needed CPU-power; and you might get
different artefacts due to floating-point precision.
>
> But sometimes, with at least 8 normalised signals, you get silence
> at the [catch~ sum] even though there seems to be headroom.
what do you need by "headroom"?
"headroom" is usually used when a signal must not go beyond a certain
threshold and you want to make sure that you stay clear off this
threshold; this is important when dealing with fixed-point numbers,
(e.g. as used by dacs on soundcards)
there is nothing comparable with floating-point numbers. Pd uses
floating point numbers throughout to represent signals. if you add to
in-phase signals of amplitude 1, you will get a new signal of amplitude
2. no problem.
the only problem arises is, when you send this signal to the [dac~],
which acts as a link to a fixed-point unit (your soundcard), and thus
superimposes the limitations of this device to the signal it receives:
it will clip the signal between -1..+1 and quantize to whatever your
audio API needs. if your signal has a DC offset above +1 (or below -1)
then you will hear nothing.
(and of course there are other problems with floating point, like adding
a very big signal to a very low signal; or adding 10^8 0dbFS signals)
but this really has nothing to do with [catch~] and applies to all
adding of signals.
>
> I went looking at the dsp_add() function trying to clarify the way Pd
> sums many signals. And also considered creation order issues and
> which blocks are being summed...
adding signals is usualy done by applying the "+" operator to
corresponding samples :-)
>
> Replicating the problem is hard, but I had one just last week, a complex
> musical patch (rjdj) that stopped working when you mixed in some more channels.
> (though each individual channel seemed fine and had only tiny drift)
so what was the output of the [catch~] bus?
if you still have a version of this non-working patch lying around i
would be happily have a look at it.
>
> In the end a hack I found always works is to use delay buffers
> to replace throw/catch pairs.
but a delay-buffer is a replacement for [send~]/[receive~] and not for
[throw~]/[catch~]. it is a 1-to-n distribution rather than a n-to-1
summation.
>
> Another possible solution is to stage the bus, so have, say 8 signals throw
> to bus-submix1 and another to bus-submix2 and then combine the two submix
> buses.
that's even more confusion.
why would several stages lower the effect (rather than enlarge it)?
>
> Maybe someone more familiar with the code can speculate what is going on?
>
unfortunately my eee's speakers will not output much below 130 Hz so i
cannot fully appreciate your patch now...
however, attached is a slightly modified version with the sole purpose
of proving that the two parts create the same result.
(the only non-obvious part is the order-forcing of throw~-before-catch~
in order to make the 2 patches play sample-synchronously.
mfgasdr
IOhannes
#N canvas 0 0 1001 529 10;
#N canvas 0 0 916 353 direct 0;
#X obj 109 92 osc~ 400;
#X obj 110 133 *~;
#X text 105 63 a raised signal with DC offset;
#X obj 182 133 *~;
#X obj 181 92 osc~ 401;
#X obj 256 132 *~;
#X obj 255 91 osc~ 402;
#X obj 328 131 *~;
#X obj 327 90 osc~ 403;
#X obj 398 130 *~;
#X obj 397 89 osc~ 404;
#X obj 469 128 *~;
#X obj 468 87 osc~ 405;
#X obj 538 128 *~;
#X obj 537 87 osc~ 406;
#X obj 609 126 *~;
#X obj 608 85 osc~ 407;
#X obj 355 220 /~ 8;
#X obj 354 246 hip~ 1;
#X obj 334 275 outlet~;
#X obj 350 45 inlet;
#X connect 0 0 1 0;
#X connect 0 0 1 1;
#X connect 1 0 17 0;
#X connect 3 0 17 0;
#X connect 4 0 3 0;
#X connect 4 0 3 1;
#X connect 5 0 17 0;
#X connect 6 0 5 0;
#X connect 6 0 5 1;
#X connect 7 0 17 0;
#X connect 8 0 7 0;
#X connect 8 0 7 1;
#X connect 9 0 17 0;
#X connect 10 0 9 0;
#X connect 10 0 9 1;
#X connect 11 0 17 0;
#X connect 12 0 11 0;
#X connect 12 0 11 1;
#X connect 13 0 17 0;
#X connect 14 0 13 0;
#X connect 14 0 13 1;
#X connect 15 0 17 0;
#X connect 16 0 15 0;
#X connect 16 0 15 1;
#X connect 17 0 18 0;
#X connect 18 0 19 0;
#X connect 20 0 0 1;
#X connect 20 0 4 1;
#X connect 20 0 6 1;
#X connect 20 0 8 1;
#X connect 20 0 10 1;
#X connect 20 0 12 1;
#X connect 20 0 14 1;
#X connect 20 0 16 1;
#X restore 117 129 pd direct sum;
#N canvas 0 0 995 492 thrown 0;
#X obj 356 423 outlet~;
#X obj 558 82 inlet;
#N canvas 0 0 943 342 stage1 0;
#X obj 141 134 osc~ 400;
#X obj 142 175 *~;
#X obj 214 175 *~;
#X obj 213 134 osc~ 401;
#X obj 288 174 *~;
#X obj 287 133 osc~ 402;
#X obj 360 173 *~;
#X obj 359 132 osc~ 403;
#X obj 430 172 *~;
#X obj 429 131 osc~ 404;
#X obj 501 170 *~;
#X obj 500 129 osc~ 405;
#X obj 570 170 *~;
#X obj 569 129 osc~ 406;
#X obj 641 168 *~;
#X obj 640 127 osc~ 407;
#X obj 142 219 throw~ sum;
#X obj 213 245 throw~ sum;
#X obj 288 208 throw~ sum;
#X obj 359 234 throw~ sum;
#X obj 431 206 throw~ sum;
#X obj 502 232 throw~ sum;
#X obj 571 204 throw~ sum;
#X obj 640 230 throw~ sum;
#X obj 558 82 inlet;
#X obj 375 305 outlet~;
#X connect 0 0 1 0;
#X connect 0 0 1 1;
#X connect 1 0 16 0;
#X connect 2 0 17 0;
#X connect 3 0 2 0;
#X connect 3 0 2 1;
#X connect 4 0 18 0;
#X connect 5 0 4 0;
#X connect 5 0 4 1;
#X connect 6 0 19 0;
#X connect 7 0 6 0;
#X connect 7 0 6 1;
#X connect 8 0 20 0;
#X connect 9 0 8 0;
#X connect 9 0 8 1;
#X connect 10 0 21 0;
#X connect 11 0 10 0;
#X connect 11 0 10 1;
#X connect 12 0 22 0;
#X connect 13 0 12 0;
#X connect 13 0 12 1;
#X connect 14 0 23 0;
#X connect 15 0 14 0;
#X connect 15 0 14 1;
#X connect 24 0 0 1;
#X connect 24 0 3 1;
#X connect 24 0 5 1;
#X connect 24 0 7 1;
#X connect 24 0 9 1;
#X connect 24 0 11 1;
#X connect 24 0 13 1;
#X connect 24 0 15 1;
#X restore 355 223 pd stage1;
#N canvas 0 0 450 300 stage2 0;
#X obj 222 213 /~ 8;
#X obj 222 189 catch~ sum;
#X obj 223 237 hip~ 1;
#X obj 153 120 inlet~;
#X obj 223 259 outlet~;
#X connect 0 0 2 0;
#X connect 1 0 0 0;
#X connect 2 0 4 0;
#X restore 355 313 pd stage2;
#X text 378 271 just for order-forcing;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 0 0;
#X restore 223 128 pd thrown sum;
#X text 118 70 play with adding more throw signals until it breaks
;
#X obj 143 164 -~;
#X obj 143 186 env~;
#X floatatom 143 208 5 0 0 0 - - -;
#X obj 223 186 env~;
#X floatatom 223 208 5 0 0 0 - - -;
#X obj 93 186 env~;
#X floatatom 93 208 5 0 0 0 - - -;
#X msg 468 104 \; pd dsp 1;
#X obj 202 110 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X connect 0 0 3 0;
#X connect 0 0 8 0;
#X connect 1 0 3 1;
#X connect 1 0 6 0;
#X connect 3 0 4 0;
#X connect 4 0 5 0;
#X connect 6 0 7 0;
#X connect 8 0 9 0;
#X connect 11 0 0 0;
#X connect 11 0 1 0;