S.options,OutputBusChannels

I want to tackle internal routings but first I want to make sure I got things correct
As always , folliwing Eli’s fabulous tuts
I get 1024 , while in Ei’s example he gets 128 .
When it comes to inputs I get only 2 ,


More Issues ,
Why is= the declaration of the outputbus not recognized in the arguments ?
It appears at channel 0 while it should appear at channel 8
I am aware I should not hear anything , but the scope should show a signal at channel 8 while it doesn’t

(
SynthDef(\Sinner,
   {
   	arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,out=8;
   	var sig;
   	sig=SinOsc.ar(frequ,mul:amp);
   	sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
   	sig=Pan2.ar(sig,pos:pan);
   	Out.ar(out,sig);
}).add
)


~ward=Synth(\Sinner,[\frequency,200,\dec,5]);
(
Pdef(\test,
   Pbind(\instrument,
   	\Sinner,
   	\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
   	\dec,Pwhite(0.5,3,inf),
   	\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
   	\pan,Pwhite(-0.7,0.7,inf),
)
)
)
Pdef(\test).play
Pdef(\test).stop


But , if I type bus 8 directly in the Outgen then the scope shows it correctly

(
SynthDef(\Sinner,
	{
		arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,out=8;
		var sig;
		sig=SinOsc.ar(frequ,mul:amp);
		sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
		sig=Pan2.ar(sig,pos:pan);
		Out.ar(8,sig);
}).add
)

 
~ward=Synth(\Sinner,[\frequency,200,\dec,5]);
(
Pdef(\test,
	Pbind(\instrument,
		\Sinner,
		\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
		\dec,Pwhite(0.5,3,inf),
		\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
		\pan,Pwhite(-0.7,0.7,inf),
)
)
)
Pdef(\test).play
Pdef(\test).stop


If I rename the out arg to any other name , then it works , in this case the name is whynot

(
SynthDef(\Sinner,
	{
		arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,whynot=31;
		var sig;
		sig=SinOsc.ar(frequ,mul:amp);
		sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
		sig=Pan2.ar(sig,pos:pan);
		Out.ar(whynot,sig);
}).add
)

 
~ward=Synth(\Sinner,[\frequency,200,\dec,5]);
(
Pdef(\test,
	Pbind(\instrument,
		\Sinner,
		\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
		\dec,Pwhite(0.5,3,inf),
		\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
		\pan,Pwhite(-0.7,0.7,inf),
)
)
)
Pdef(\test).play
Pdef(\test).stop


Why is the reverb not sounding ?
It takes the input from bus 31 and should output a processed sound at bus 0

(
SynthDef(\Sinner,
	{
		arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,opb=31;
		var sig;
		sig=SinOsc.ar(frequ,mul:amp);
		sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
		sig=Pan2.ar(sig,pos:pan);
		Out.ar(opb,sig);
}).add
)
/////
(
SynthDef.new(\reverb,{
	arg in=31,out=0;
	var sig;
	sig=In.ar(in,1);
	sig=FreeVerb.ar(sig,0.5,0.8,0.2)!2;
	Out.ar(out,sig);
}).add
)
//////////////////

 

(
Pdef(\test,
	Pbind(\instrument,
		\Sinner,
		\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
		\dec,Pwhite(0.5,3,inf),
		\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
		\pan,Pwhite(-0.7,0.7,inf),
)
)
)
Pdef(\test).play
Pdef(\test).stop

Weird , why the out argument refuses to accept it’s declaration when it’s named out
Is that name reserved ,how come it accepts decalration when it’s renamed ?
Still , the routing into a SynthDef is still not working


You need to include \out in the Pbind as well.

The default event defines default values for some standard parameter names. The default \out is 0. This is a property of the event. Values in the event take precedence over values in the SynthDef.

Best practice is that the note player should be responsible for assigning the output bus, and not the SynthDef.

hjh

May be different in different environments. Also at some point, the default number of buses changed.

hjh

Still no reverb

(
SynthDef(\Sinner,
	{
		arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,out=128;
		var sig;
		sig=SinOsc.ar(frequ,mul:amp);
		sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
		sig=Pan2.ar(sig,pos:pan);
		Out.ar(out,sig);
}).add
)

/////
(
SynthDef.new(\reverb,
	{
	arg indio=128,out=0;
	var sig;
	sig=In.ar(128,1);
	sig=FreeVerb.ar(sig,0.5,0.8,0.2)!2;
	Out.ar(0,sig);
}).add
)
//////////////////

 

(
Pdef(\test,
	Pbind(\instrument,
		\Sinner,
		\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
		\dec,Pwhite(0.5,3,inf),
		\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
		\pan,Pwhite(-0.7,0.7,inf),
		\out,128,
)
)
)
Pdef(\test).play
Pdef(\test).stop

Edit , I need to trigger the reverb

(
SynthDef(\Sinner,
	{
		arg frequ=110,amp=0.5,att = 0.001 ,dec = 0.125,pan=0,out=128;
		var sig;
		sig=SinOsc.ar(frequ,mul:amp);
		sig=sig*EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
		sig=Pan2.ar(sig,pos:pan);
		Out.ar(out,sig);
}).add
)

/////
(
SynthDef.new(\reverb,
	{
	arg indio=128,out=0;
	var sig;
	sig=In.ar(128,1);
	sig=FreeVerb.ar(sig,0.5,0.8,0.2)!2;
	Out.ar(0,sig);
}).add
)
//////////////////

Synth(\reverb);

(
Pdef(\test,
	Pbind(\instrument,
		\Sinner,
		\dur,Pseq([0.5,0.25,0.5,0.25,0.5,0.25,0.5,Pwhite(0.01,0.125,16)],inf),
		\dec,Pwhite(0.5,3,inf),
		\frequ,Pseq([100,200,300,400,500,600,700,800,900,Pwhite(1000,2000,64)],inf),
		\pan,Pwhite(-0.7,0.7,inf),
		\out,128,
)
)
)
Pdef(\test).play
Pdef(\test).stop


And again not working

This means when using out as argument you can’t choose another outputbus ?
It always routes to bus zero when named ‘out’

(
{

arg out=31;
	var freq,trig,sig;
	freq=LFNoise0.kr(3).exprange(300,1200).round(300);
	sig=SinOsc.ar(freq)*0.25;
	trig=Dust.kr(2);
	sig=sig*EnvGen.kr(Env.perc(0.01,0.2),trig);
	Out.ar(out,sig);
}.play
)

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