Probably the answer is trivial, but I can’t understand why the first code “sounds” and the second doesn’t.
Thank you in advance.
// this works
(
var mix, s1, s2;
{
s1=SinOsc.ar(220,mul: 0.3);
s2=LFSaw.ar(110,mul: 0.3);
a = [s2, s1];
b = [s1, s2];
mix = Mix.new([a, b]).postln;
}.play;
)
// this does not work (I simply changed the order of the two signals in the array 'a')
(
var mix, s1, s2;
{
s1=SinOsc.ar(220,mul: 0.3);
s2=LFSaw.ar(110,mul: 0.3);
a = [s1, s2];
b = [s1, s2];
mix = Mix.new([a, b]).postln;
}.play;
)
Hello and welcome,
good catch, this looks like a bug in Mix.
(
// silent
{
var sig = SinOsc.ar(220, mul: 0.3);
Mix([sig, sig]);
}.play;
)
(
// ok
{
var sig = SinOsc.ar(220, mul: 0.3);
Mix([sig, sig * 2]);
}.play;
)
// compare
(
{
var sig = SinOsc.ar(220, mul: 0.3);
Mix(sig);
}.asSynthDef.dumpUGens;
)
// no Out here !
(
{
var sig = SinOsc.ar(220, mul: 0.3);
Mix([sig, sig]);
}.asSynthDef.dumpUGens;
)
Not a problem of Mix, it seems to be a weird bug in the UGen graph builder. I checked to exclude the possibility that something goes wrong in Function::play
// (1) ok
(
{
var x = SinOsc.ar(mul: 0.1);
x
}.play
)
(
SynthDef(\test_1, {
var x = SinOsc.ar(mul: 0.1);
Out.ar(0, x)
}).play
)
// (2) silent !
(
{
var x = SinOsc.ar(mul: 0.1);
x + x
}.play
)
(
SynthDef(\test_2, {
var x = SinOsc.ar(mul: 0.1);
Out.ar(0, x + x)
}).play
)
// (3) again sound !!
(
{
var x = SinOsc.ar(mul: 0.1);
x * x
}.play
)
(
SynthDef(\test_3, {
var x = SinOsc.ar(mul: 0.1);
Out.ar(0, x * x)
}).play
)
// (4) and here also sound !
// result multiplied with 0.1 only to avoid loud output
(
{
var x = SinOsc.ar();
x + x * 0.1
}.play
)
(
SynthDef(\test_4, {
var x = SinOsc.ar();
Out.ar(0, x + x * 0.1)
}).play
)
Just a guess, if it’s of the form (x * b) + (x * b)
, that would trigger a muladd optimization, which would remove the first *
and the +
in favor of a muladd. But here, there is only one *
so removing the “first” one also removes the “second.”
It depends how we are counting descendants of the *
UGen. If descendants are counted as number of target inputs, then the *
would have two descendants and the optimization should be skipped. If they’re counted as number of target UGens, then it would count one descendant, so it would look like a valid optimization (but it’s not).
I won’t quite put money on that but… check the count of descendants first.
A workaround would be to commute redistribute the multiplication:
var x = SinOsc.ar(mul: 0.1);
x + x // KO
var y = SinOsc.ar;
(y + y) * 0.1 // OK
(So this is another argument in favor of writing *
instead of using mul
.)
hjh
PS No access to github from my phone. I might check it myself later on the computer. Edit: Confirmed, this is exactly the problem. descendants
is a Set of unique UGens, not inputs. So it can’t detect the case of a UGen that feeds separately into two inputs of one other UGen.
I greet and thank you all.