Hello everyone!
I have noticed a weird behavior of the AudioControl
and InFeedback
UGens.
If you run this code, you’ll notice that the last audio cycle will run twice, generating a “double” dropout:
(
s.waitForBoot({
SynthDef(\test, {
Out.ar(\out.ir(0), { SinOsc.ar(2) * EnvGen.ar(Env([1, 1], [0.2]), doneAction:2) })
}).add;
s.sync;
~bus = Bus.audio(s);
Pbind(
\instrument, \test,
\dur, 1,
\out, ~bus.index,
\addAction, \addToHead
).play;
~reader = { \in.ar }.play(args:[ \in, 'a' ++ ~bus.index]);
{ In.ar(0) }.plot(0.5);
})
)
This happens because the AudioControl
UGen (as well as the InFeedback
one) only check if the bus has been touched in the current audio cycle. In my opinion, it should probably take into consideration if the bus has been touched in the previous audio cycle aswell, in order to avoid this “repetition” effect.
I have compiled a custom UGen that does this, and it seems to me to handle the behavior better. It basically works just like In
when the ~reader
Synth
is later in the chain, and just like InFeedback
when the ~reader
Synth
is before in the chain (reading the previous audio cycle).
Pbind (\addToHead) -> ~reader:
-> ~reader Pbind (\addToTail) ->:
Would you think the current behavior of AudioControl
and InFeedback
is faulty as I do? Do you think it’s worth to make a PR to SuperCollider to fix this?
1 Like
Yes, would be great to fix this. I don’t see any reason to maintain backward compatibility for the doubled buffer.
hjh
Is it possible to .plot
when using InFeedback
or is this issue also causing some implication on the .plot
?
This sound here:
(
SynthDef("help-InFeedback", { arg out=0, in=0;
var input, sound;
input = InFeedback.ar(in, 1);
sound = SinOsc.ar(input * 1300 + 300, 0, 0.4);
Out.ar(out, sound);
}).play;
)
does not seems to be properly plotted here:
(
{
var input, sound;
input = InFeedback.ar(0, 1);
sound = SinOsc.ar(input * 1300 + 300, 0, 0.4);
sound;
}.plot(1/10);
)
I strongly suspect plot
diverts it from the actual bus since you can’t hear it. So you need consider what you In
there and the huge mess that control namespaces are right now. Look at plot
's implementation to see how it changes the out
. It turns out that it doesn’t, just ignores it, meaning it writes nothing to it anymore.
The actual implementation, after going though some wrappers, is in Function.asBuffer
. What that does is
var val = SynthDef.wrap(this);
/// .......
RecordBuf.perform(RecordBuf.methodSelectorForRate(rate), val, bufnum, loop: 0);
So nothing gets written to bus 0 anymore, in your example, or to any out
for that matter. So you can’t use plot with feedback like that, unless you use a LocalIn
and LocalOut
.
You can probably write a version of plot
and asBuffer
that writes to a “private” bus automatically, to make that work. Left as an exercise to the reader, for now, esepecially because you’d need to know how out
was declared by the user, without this kind of unifying patch.
1 Like
It’s probably just easier to use plotNRT for something like that, which will work because it uses a separate server to render, no SynthDef.wrap
headaches.
(
~plotNRT.({
var input, sound;
input = InFeedback.ar(0, 1);
sound = SinOsc.ar(input * 1300 + 300, 0, 0.4);
sound;
}, 1/10);
)
Gets me this:
1 Like
Great, thanks! Maybe this .plotNRT
should be incorporated on the main branch to allow these plotting possibilities + some doc improvement to alert users about that…