Synth output should be a flat array

When sending a two-channel signal to a Ugen than expects one channel (e.g. Pan2, GVerb), the output is a nested array:

[ [ a BinaryOpUGen, a BinaryOpUGen ], [ a BinaryOpUGen, a BinaryOpUGen ] ]

while you get the warning:

WARNING: Synth output should be a flat array.

Node proxies automatically flatten the array to a four-element array ([ a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ]) which is not ideal since two of the channels are assigned to extra buses.

Manually this can be fixed, for example:


(
y = {
	var x, left=[], right=[];
	
	x = Pan2.ar(SinOsc.ar([100,101]));
	x.postln;
	x.do({
		arg array;
		left.add(array[0]);
		right.add(array[1]);
	});
	
	x = [Mix.ar(left), Mix.ar(right)];
	x.postln;
};
)

{y}.play;

Is there perhaps a Ugen that does explicitly this job?

Does anybody know how the method {}.play handles this situation?

Perhaps see flop and sum.

flop is a synonym for multiChannelExpand.

Pan2.ar(SinOsc.ar([100, 400], 0), 0, 0.1) // L=100 R=400

Pan2.ar(SinOsc.ar([100, 400], 0), 0, 0.1).sum // L&R=100+400

Pan2.ar(SinOsc.ar([100, 400], 0), 0, 0.1).flop.sum // L=100 R=400

Ps. Ctrl+i (in ScIde) or C-cC-: (in Emacs) are very helpful things!

Thanks, the .flop.sum does the trick!

Another thing that might come up is when you have an array of this structure

[ [L, L, ...], [R, R, ...] ]

This can be squished to stereo with .collect(_.sum).

Play wraps the output in a Mix if it isn’t flat. asBuffer, however will just take the first index of each sub array. Personally I think an exception should be thrown if you output a nested array as I can’t think of any instances where you would actually need that.

3 Likes

You can also use Splay to spread an array of any size across the stereo field, it is nice and quick and works like a charm if you don’t feel the need to be specific about the exact panning of each element and just want a nice spread.