S.options,OutputBusChannels

Excute reverb and then the bleep , you won’t hear reverb
Now , change the bleepinstrument out argument on the last line from ‘out’ to 32 , or rename out to ‘trout’ :slight_smile: and you will hear a reverb !
Why is that ?



//bleepsintrument
(
{
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out,sig);//////////////change  out to 32 
}.play
)

////REverb
(
{
	arg in=32,out=0;
	var sig;
	sig=In.ar(in,1);
	sig=FreeVerb.ar(sig,0.8,0.8,0.2)!2;
	Out.ar(out,sig);
}.play
)

///




the Pbind is setting the out control on the synths it generates! As Jamshark explained.

Pbind uses a default Event which has \out set to 0.

so you need to add \out,32 to the Pbind if you want the resulting synths to send to that bus

In my last example I am not using Pbinds , out arguments always defaults to zero while they have been assigned 32 ,
I either have to type in 32 in the Out.ar OR rename the out arg to a different name , then it will adopt the assigned value
Please , See last code
First screenshot shows out 0 while arg out = 32 in arg. declaration , so this has to be wrong , right ?
The last two screenshots show a correct output since I have either typed in 32 manually or renamed the out argument



No one ?
Please see last screenhots

I’m not sure specifically the mechanics of what’s causing it, but it seems that even with the play method, out is a reserved key, so it gets set. The workaround for this is either to use a diff arg name, which is probably not the best way, or to set out explicitly when playing the synth:

(
{
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out,sig);//////////////change  out to 32 
}.play(args: [out: 32])
)

Just note that in your example above, even with the routing working as you intend, you’ll need to evaluate the reverb first, unless you provide extra arguments in either the reverb’s or bleeps’s play method. This is because of how nodes are arranged by default on the server: Order of execution | SuperCollider 3.12.2 Help

Actually, I just saw why it’s playing by default on zero.

It’s because the play method for the Function class specifies the outbus as 0 by default.

(
a = {
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out,sig);//////////////change  out to 32 
}
)
a.class // -> Function

When creating Synths like this, you actually don’t need to explicitly provide an Out UGen…

// still works:
(
{
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	// Out.ar(out,sig);//////////////change  out to 32 
}.play
)

Under the hood, SuperCollider adds this UGen for you, taking the last line of your code, and wrapping it in an Out.ar(out, _your_last_line_of_code_).

If you explicitly provide the same thing, as you’re doing in your example, and if you use the same argument key: out, the Function’s mechanism overwrites whatever value unless you explicitly set it.

That’s why using a different argument name in its place achieves your desired result, it blocks the language from overwriting the value for out.

So the other way to do this:

(
{
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out,sig);//////////////change  out to 32 
}.play(outbus: 32)
)

Where outbus is what sets the value of out.

This is achieving a similar thing as the example in my previous post.

Check out the help page for Function, specifically looking at the play method.

Since the play method can work differently for different classes, it’s important to know which class your object belongs to. Hence me trying a.class.

Yes , I know about evaluating reverb first
Interesting find ., let’s see how it behaves with synthdefs
All I want to achieve is some internal routing , dry wet settings and then call it a day

When you call play on a Synth or SynthDef, it uses a different play method, so outbus will not work, but your technique of providing the out arg a default value will, no additional steps required.

(
SynthDef(\bleeps, {
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out.poll,sig);//////////////change  out to 32 
}).add
)
a = Synth(\bleeps)
// UGen(OutputProxy): 32

This is all due to the fundamental differences between a Function and SynthDef, and how they handle playing on the server.

As an aside, you can also do:

(
SynthDef(\bleeps, {
arg out=32;
	var freq,trig,sig;
	freq=LFNoise0.kr(20).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.50),trig)!2;
	Out.ar(out.poll,sig);//////////////change  out to 32 
}).play
)

Which is is like doing both add and play all in one step.

Got rid of the reverb , just kep the frequency shifter
Tied to Pdef, pbind sequencing the frequency shifter’s frequencies , but the sound keeps adding up,
Voices are not released for the effect , as expected since the effect has no done action .
But since it’s a stereo effect how come voices are added when sequenced from Pbind?

So another problem to tackle ,

(
SynthDef(\twoop,
{
|fmamt=1,modoffset=24,moatt=0.001,modrel=0.500,ampatt=0.001,amprel=0.800,pitch=48,outt=0.3,pan=0.2,feed=0.2,output=0|
var mod,modenv,ampenv,carr;

		mod=SinOscFB.ar((pitch+modoffset).midicps,feedback:feed)*fmamt;
		modenv=EnvGen.ar(Env.perc(moatt,modrel),doneAction:0);
		ampenv=EnvGen.ar(Env.perc(ampatt,amprel),doneAction:2);
		carr=SinOsc.ar(pitch.midicps,(mod*modenv))*ampenv*outt;
		carr=Pan2.ar(carr,pos:pan);
		Out.ar(bus:output,carr);
}).add
);
/////////
(
SynthDef(\revv,
{       | inbus=20,ff=50|
		var in;
		in=In.ar(inbus,2);
		in=FreqShift.ar(in,ff);
		Out.ar(0,in);
	}	
).add
)
//////////////
~reverb=Synth(\revv);
~reverb.free;
(
Pdef(\shifter,
	Pbind(\instrument,
		\revv,
		\dur,4,
		\inbus,20,
		\ff,Pseq([1000,50],inf),
		
		
	)
))
		





(
Pdef(
	\crt,
	Pbind(
		\instrument,
		\twoop,
		\pitch,Pseq([40,42,47,[45,52],37,34,31,28,40,42,47,[45,52],47,42,40,28,31,34,37],inf),
		\dur,Pseq([1/2,1,1/2,1/4,1/4,1/4,1/4],inf),
		\fmamt,Prand([2,1,3,4],inf),
		\modrel,Prand([0.425,0.525,0.500,0.550,1,0.625,0.500,0.5,2.8],inf),
		\modoffset,Prand([12,0,12,24],inf),
		\feed,Pwhite(0.3,0.5,inf),
		\pan,Prand([-0.3,0,0.3],inf),
		\amprel,Pwhite (0.08,0.5,inf),
		\output,20,
				)
			)
)
//////////
;
////////////////////			
Pdef(\shifter).stop;///////////FM
Pdef(\shifter).play(t);

Pdef(\crt).stop;///////////FM
Pdef(\crt).play(t);

	t=TempoClock(175/60).permanent_(true);

No, of course it does not. Synth arguments would be pointless if you can’t set them.

The trouble is that you didn’t set it.

To cut through some of the confusion: In my opinion (with 20 years behind it), the best practice for bus routing is:

  • SynthDef: Name the output bus argument out. Function:play: Do not add your own out.
  • Then, whatever is playing the synth is responsible for supplying the correct value for out.

The longer I do this, the more I find that I prefer simple rules with fewer exceptions. This is as clear and as exception-free as I can make it: when bus routing is important, always supply the bus number at the time of playing.

Do not write the desired bus as a SynthDef argument default and assume that this will always take effect. As you found, it doesn’t always work. That is, it’s not reliable. Because it’s not reliable, it’s not a good approach. Now, you could spend the next day trying to puzzle out why it isn’t reliable, or fighting with it to try to make it reliable, but the end result will be the same – you will just find that it isn’t reliable and that it will work better if you go with the above principle.

Another source of confusion is that { }.play manages its own output-bus argument and Out UGen. So you should not create these in this context. You do need them for SynthDef. You don’t need them for Function:play.

s.boot;

~rvbBus = Bus.audio(s, 2);

// Function:play, no out = YES
// note that the `play` method has an 'outbus' argument -- USE IT
// "but the function has no outbus" -- `play` created a control input for it, invisibly, don't worry about it
(
~rvb = { |inbus|
	var sig = In.ar(inbus, 2);
	FreeVerb2.ar(sig[0], sig[1], 0.4, 0.9, 0.2)
}.play(outbus: 0, args: [inbus: ~rvbBus]);
)

// SynthDef with out = YES
// note that I have written NO DEFAULT for out here
(
SynthDef(\boop, { |out, freq = 440, time = 0.1, amp = 0.1|
	var sig = SinOsc.ar(freq);
	var eg = EnvGen.ar(Env.perc(0.001, time), doneAction: 2);
	Out.ar(out, (sig * (eg * amp)).dup);
}).add;
)

// ... because the bus number will be given HERE
Synth(\boop, args: [out: ~rvbBus]);

// ... or here
(
p = Pbind(
	\instrument, \boop,
	\freq, Pexprand(200, 800, inf),
	\dur, Pexprand(0.05, 0.8, inf),
	\out, ~rvbBus
).play;
)

p.stop;

hjh

1 Like

“another problem to tackle” but you already know the answer to this one – if you’re going to Pbind-sequence the effect synths, then the effect needs an envelope with a doneAction. (So it isn’t a very big problem, is it?)

It’s true that there aren’t many examples in the help of fx synths being sequenced, but sequencing doesn’t work differently just because it’s an fx synthdef. You use the same rule that you’d use with other types of SynthDefs!

(
SynthDef(\revv, { |inbus = 20, ff = 50, gate = 1|
	var in;
	var eg = EnvGen.kr(Env.asr(0.01, 1, 0.01), gate, doneAction: 2);
	in = In.ar(inbus, 2);
	in = FreqShift.ar(in, ff);
	Out.ar(0, in * eg);
}).add
)
//////////////
~reverb=Synth(\revv);
~reverb.free;

(
Pdef(\shifter,
	Pbind(\instrument,
		\revv,
		\dur, 4,
		\legato, 1,
		\inbus, 20,
		\ff, Pseq([1000, 50], inf)
	)
).play
)

No pileup.

The next thing you’re going to run into is that source and fx synths will be interspersed this way. So it’s better to be explicit about order:

(
Pdef(\shifter,
	Pbind(\instrument,
		\revv,
		\dur, 4,
		\legato, 1,
		\inbus, 20,
		\ff, Pseq([1000, 50], inf),
		\addAction, \addToTail  // fx at the end
	)
).play
)

hjh

1 Like

So what would be the best way to keep an effect constantly active after creating the synthdef (with add method at the end )
Would it be like this , lke triggering an instance and then freeing it for bypassing the effect ?
~thiseffect=Synth(\reverbah).
~thiseffect.free

1 Like

This is an example of the constant annoyances that occur .
Analysing this synthdef gives an error because it does not recognize the argument name for bus:output.
Yesterday it worked because I posted it in this verry thread ., the code is correct

(
SynthDef(\twoop,
{
|fmamt=1,modoffset=24,moatt=0.001,modrel=0.500,ampatt=0.001,amprel=0.800,pitch=48,outt=0.3,pan=0.2,feed=0.2,output=0|
var mod,modenv,ampenv,carr;

		mod=SinOscFB.ar((pitch+modoffset).midicps,feedback:feed)*fmamt;
		modenv=EnvGen.ar(Env.perc(moatt,modrel),doneAction:0);
		ampenv=EnvGen.ar(Env.perc(ampatt,amprel),doneAction:2);
		carr=SinOsc.ar(pitch.midicps,(mod*modenv))*ampenv*outt;
		carr=Pan2.ar(carr,pos:pan);
		Out.ar(bus:output,carr);
}).add
);

Have a look at the “Order of execution” helpfile.

In short, you would probably like to put effects at the end of the chain with:
Synth(\reverbah, \addAction: addToTail);
or
Synth.tail(s, \reverbah);
and your source synths at the start of the chain with:
Synth(\player, \addAction: addToHead);
or:
Synth.head(s, \player);

The default addAction is addToHead.

You can also have a look at ReplaceOut.ar

The code is correct it just doesn’t like Out.ar first argument ,bus:output (output is a declared argument)
Change the Out.ar first argument to 0 and will work , or delete bus:
This all feels verry buggy
It’s like all of a sudden a filter wouldnt’ work because you explicitly wrote freq:1000 in it’s arguments .

See code two post above

No, that’s not the reason.

Once you put in one keyword argument (bus:), then all arguments after that must have keywords. This is because keyword addressing of arguments may alter the order of arguments, so after that, the only way to be sure which one you mean is to write all the keywords.

I’d suggest simply to leave out the keywords here. Out isn’t a complex UGen; it won’t impair readability to omit the names.

It is definitely not a bug.

I kinda think they are constant annoyances because you’re trying every possible permutation, seemingly randomly, which raises the probability of stumbling onto invalid combinations. I think, if you’re starting from a valid model and then changing stuff to see what happens, it’s necessary to accept that many of these evolutionary mutations will simply not work out.

hjh

I see about the placeholders , I sometimes use them and never run into that .
I don’t try stuff at random , the goal is to comprehend the bus routing and by doing so I run into problems which may relate to something completly different .
Everyone is using supercollider in different ways , granted that it might not seem verry methodological by just cherry picking the parts I want to learn .
I am verry close to throwing in the towel ( for the second time ) and just stick to sequencing synthdefs from hardware , but even then the knowledge of buss routing is fundamental .

I know about the basic stuff (started two years ago and and held on for a couple of months ) , made some great synthdefs etc…so the use of variables inside a dsp-synth context where there is a clear signal flow is nothing new and was pretty easy to grasp .
It’s just reaktor or max without wires ( I am purely talking about the audio generating stuff )
The real challenge is to incorpate this into the bigger picture .
Do I just want to use the stepsequencers , do I want to make complete pieces etc…still thinking about what exactly I want to do .
The sequencing and synthdef creation is going fine :slight_smile:

.

My opinion is, fwiw, that SC’s built in bus routing objects are too low level to be pleasant for normal usage. It’s possible to do mixing with them, but you have to rebuild architecture in various places. And it’s too easy to forget to include the bus and group objects in patterns. Too many ways to get it wrong.

For these reasons, I wrote a MixerChannel class (to avoid repeating architecture, and to support DAW-like signal routing, including sends), and a wrapper class for patterns that “binds” a pattern to resources upon which it depends.

Delegating routing to helper objects has made it all a lot easier for me.

hjh

1 Like

I was often making this mistake and couldn’t understand the error. Lost hours being confused.

when using keywords in an argument list, like SinOsc.ar(freq:500,mul:0.5), in that list you can mix and match only in one direction - once you use a keyword, you cannot use an argument without a keyword after it:

// keywords  example:
{ SinOsc.ar(freq:555, phase:0, mul:0.5) }.play

// example without keywords in argument list:
{ SinOsc.ar(555, 0, 0.5) }.play

// this is OK:
{ SinOsc.ar(555, mul:0.5) }.play

// this will throw an error
{ SinOsc.ar(freq:555, 0, 0.5) }.play

(edited)

It gets easier after some time. After months of regular work with SC you make less mistakes, you know more by heart, there’s then almost a muscle memory - it’s because you made the same mistake many times in short time so you remembered well enough to not make it more. It’s called learning. We all learn differently - some are faster, some of us are slower. I have found that persistence and regularity have been key in my progress. If I was playing around in SC for few days and then nothing for a month, two or three, I forgot a lot. But if I worked everyday a little, I remember more. Just my experience, maybe it helps you to know that some of us have gone through similar frustrations of making mistakes and not finding where we made the mistake. (some of my posts on this forum are a testament to that).

1 Like