So I have been thinking about this a bit and another thread with the issue of creating stereo patches from mono objects and phasing issues reminded me to post something.
The patcher takes a naive view on how to order the processing of objects, so top to bottom, left to right.
So if we take something simple like this:
The patcher generates the following code:
/* <object calls> */
objectinstance_sine__1_i.dsp(0 , ZEROBUFFER, ZEROBUFFER, net0, PExch[PARAM_INDEX_sine__1_pitch].finalvalue);
objectinstance_mix__1_i.dsp(ZEROBUFFER, net0, net3Latch, net1Latch, net2, PExch[PARAM_INDEX_mix__1_gain1].finalvalue, PExch[PARAM_INDEX_mix__1_gain2].finalvalue, PExch[PARAM_INDEX_mix__1_gain3].finalvalue);
objectinstance_out__1_i.dsp(net2, net2, displayVector[3], displayVector[4]);
objectinstance_sine__2_i.dsp(0 , ZEROBUFFER, ZEROBUFFER, net3, PExch[PARAM_INDEX_sine__2_pitch].finalvalue);
objectinstance_sine__3_i.dsp(0 , ZEROBUFFER, ZEROBUFFER, net1, PExch[PARAM_INDEX_sine__3_pitch].finalvalue);
/* </object calls> */
/* <net latch copy> */
for (i=0; i<BUFSIZE; i++) {
net1Latch[i] = net1[i];
}
for (i=0; i<BUFSIZE; i++) {
net3Latch[i] = net3[i];
}
Now that code might look a bit nonsense to the non-programmers here but you can see it is processing in this order:
sine_1
mix_1
out_1
sine_2
sine_3
So that doesn’t really look right, how can it be mixing the three sine waves if only one sine wave has been generated!
It gets around this conundrum using some extra audio buffers, net1Latch
and net2Latch
. It copies the current buffers to the latch buffers and then uses those next time round
So it is using the current buffer for sine_1, and the previous latched buffers for sine_2 and sine_3 in the mixer, you can see them in the code:
objectinstance_mix__1_i.dsp(ZEROBUFFER, net0, net3Latch, net1Latch, net2, PExch[PARAM_INDEX_mix__1_gain1].finalvalue, PExch[PARAM_INDEX_mix__1_gain2].finalvalue, PExch[PARAM_INDEX_mix__1_gain3].finalvalue);
ZEROBUFFER, net0, net3Latch, net1Latch
are the inputs to the mixer, the ZEROBUFFER is just an empty buffer where the bus_in
input is not being used in the patch.
So sine_2 and sine_3 are in phase with each other but delayed, sine_3 is not in phase with them as it is not delayed.
So really we want to process things in this order:
sine_1
sine_2
sine_3
mix_1
out_1
Nice and neat, no need for any delayed buffers, everything in phase, no latency being introduced on some of the audio paths.
So I’m thinking of changing the way the patcher generates this code so they would be in that order.
So instead of top to bottom, left to right a “Directed Acyclic Graph (DAG)” would be used instead, for info start here: Directed acyclic graph - Wikipedia
The eagle eyed may see that this is not possible as we can have feedback in the patch, so I could feedback the mixer to the freq inputs of the sine waves:
So what we have now is a “Directed Cyclic Graph (DCG)” which is a bit more of a pain in the backside, but we can convert the DCG to a DAG by identifying feedback cycles and breaking them, we then add output nodes where these cycles happen (latched buffers) and we then add input nodes that use these latched buffers. Like magic it all should work.
So it’s a bit of work this, is it worth it, would people like it to work this way, would it break things, etc, etc?