Audiobus(server,numchann)

SynthDef(\myFx, { |bus, mix|
    var sig = In.ar(bus, 2);
    var wet = ... your fx processing...;
    ReplaceOut.ar(bus, XFade2.ar(sig, wet, mix * 2 - 1));
}).add;

I usually start with a template like this. All other options will be more complicated IMO.

hjh

I don’t get why there is the same bus arg for the Replace.out ,wouldn’t 0 be suffice to route the effect to the main out ?
When I set the out of an effects to the same arg as it’s input ( like yo do in your example ) I hear nothing because the effect stays on that bus
Here’s a simple distortion effect
Set out to arg.bus and you won’t hear the processed sound

`
(
SynthDef(\dister,
   {|amt=1,bus,gain=0.4|
   	var sig;
   	sig=In.ar(bus,2);
   	sig=(sig*amt).tanh;
   	sig=sig*gain;
   	sig=Out.ar(0,sig);
}).add
)

~distro=Synth(\dister,[\bus,~grunge,\amt,10,\gain,0.5])
~distro.set(\amt,0.5);
~distro.set(\amt,10,\gain,0.3);
~distro.set(\amt,6,\gain,0.3);
~distro.free


~grunge=Bus.audio(s,2)`


IMO the simplest way to write fx inserts is to keep them on the same bus.

Then use another synth for the routing.

You’re probably thinking that another synth for routing is a complication. Actually I find that a more modular design ends up being simpler to use and debug. This is consistent with general findings in computer science.

I spelled it all out in the other thread, with a complete demonstration. Actually I wrote that thread for you.

hjh

Am I right in thinking that the oscilloscope busses actually show the signal that is GOING INTO the bus and not leaving the buss ( so processed )
For demonstration purposses I kept it as simple as possible
A synthdef saw wave going into a Synthdef hp filter
Synthdef saw out=nr 10
Synthdef hpfilter effect in =10
Looking at the scope on bus 10 we clearly see an unfiltered signal
The actual processed output appearing in the speakers is clearly filtered

(
SynthDef(\filter,
	{
		|in,vol=0.5,cutoff=800,reso=0.5|
		var sig;
		sig=In.ar(in,2);
		sig=RHPF.ar(sig,freq:cutoff,rq:reso);
		sig=sig*vol;
		Out.ar(0,sig)
}).add
)

///////
~filtah=Synth(\filter,[\cutoff,200,\reso,0.1,\in,10])
~filtah.set(\cutoff,1200,\reso,0.2)
~filtah.free

/////
(
SynthDef(\saw,
{ |out,freq=60,vol=0.5,att=0.001,dec=0.250|
var sig,env;
sig=SawDPW.ar(freq.midicps)*vol;
env=EnvGen.ar(Env([0,1,0],[0.001,0.250],[0,-5]),doneAction:2);
sig=sig*env!2;
Out.ar(out,sig);
}).add
)
////
~yoda=Synth(\saw)
~yoda.free;
/////
(
Pdef(\seq,
	Pbind(\instrument,
		\saw,
		\dur,0.125,
		\freq,Pseq([48,51,49,55,52],inf),
		\out,10,
	)
)
)
//
Pdef(\seq).play
Pdef(\seq).stop
///

Could you please answer why your last posted effect code has the same argument for both input and output ?
If I do that , the effects stays on that bus

This is explained in the other thread, which describes my approach in full – Bus routing: ddwMixerChannel's approach

I took time to write that up because I see you struggling with this for like a week, and I thought it might help to describe a known, working approach from the ground up, which you could take bits of and imitate. It’s right there, waiting for you to take a look…

hjh

A week ? now let’s not exaggerate :slight_smile: ,it’s two days since I started exploring busses
I just thought there was something wrong because of the activity on channel 2-3 , it now works pretty well .
I haven’t even looked into groups etc…
Thanks for the write up ,about the mixer ,much appreciated

Really got a hold of the busses
For me the easiest is just to provide a Xfade ugen in the synthdef too xfade between processed and wet
Here I created 1 comdelay Synthdefeffect
Three variations all having their own bus


//
(
SynthDef(\layla,
	{|mdt=0.250,dt=0.10,dect=0.1,modspeed=0.5,modamt=0.01,hpf=100,in,xfadecontrol=0|
		var sig ,modulator,processed;

		sig=In.ar(in,2);
		modulator=SinOsc.ar(modspeed)*modamt;
		processed=CombC.ar(sig,mdt,dt+modulator,dect);
		processed=HPF.ar(processed,hpf);
		processed=XFade2.ar(processed,sig,xfadecontrol);
		Out.ar(0,processed)
}).add)
///......
~comber=Synth(\layla,[\in,~speak])
~comber.free
(
~comber.set(
	\mdt,0.5,
	\dt,0.01 ,
	\dect,4,
	\modspeed,0.1,
	\modamt,0.001,
	\hpf,40,
	\xfadecontrol,0.9)
)
//...
(
~comber.set(
	\mdt,0.5,
	\dt,0.450 ,
	\dect,44 ,
	\modspeed,0.0,
	\modamt,0.000,
	\hpf,100,
	\xfadecontrol,0.8)
)//  long delay
//

~speak=Bus.audio(s,2)
~speak
//...
~kam=Synth(\layla,[\in,~answer])
(
~kam.set(
	\mdt,0.5,
	\dt,0.1 ,
	\dect,10 ,
	\modspeed,0.1,
	\modamt,0.03,
	\hpf,100,
	\xfadecontrol,0.7)//  long delay
)
~kam.free
~answer=Bus.audio(s,2)
~answer
///.....
~ploink=Synth(\layla,[\in,~phonetic])
~ploink.free
(
~ploink.set(
	\mdt,1,
	\dt,0.5 ,
	\dect,22 ,
	\modspeed,0.000,
	\modamt,0.03,
	\hpf,100,
	\xfadecontrol,0.8)//  long delay
)
~phonetic=Bus.audio(s,2)
/////

Ahhhh hahahaha – you’re quite right. It’s been a very busy thread – I guess to me it felt like a week’s worth of conversation.

Hmmmm… I think the way that you’re doing it, you’re losing some control over the dry/wet ratio.

For a mix parameter to mean what you think it means, you need to keep all the signal processing for the channel on the same bus, and XFade2 + ReplaceOut.

Also, your SynthDef(\layla) makes it impossible to run different effect synths in series.

hjh

But all the dry wet mixing is happening on the same bus
The xfade ugen is in the FX synthdef that processes incoming synths
Setting xfadecontrol to 1 =totally dry , 0=50/50% ,-1=totally wet and it all happens on the same bus .
Ofcourse the bus send it;s all to back to 0

Perhaps you’re mistaken with send efffects for pure wet mixing, in that case you’re right
Either way , the dry-wet mixing in my posted code is all happning on a dedicated bus .

The main synthdef effect has three variation synth effects (not sets ) which all have their dedicated bus
Just load any of your instrument through the posted code and you’ll see

I also suspect that the osciloscope only shows the audio that is going into that bus , not the actual processing of the audio ON that bus
Which I have demonstrated a few posts back
A dry saw wave goes to bus 10 , highpass filter synthdef receives on bus 10 for HIGH PASS filtering
The osciloscope still shows a saw wave with unfiltered harmonics on bus 10

About serial routing , I guess you’re right about that

Here’s the oscilsocope issue clearly demonstrated ( not using ~bus=Bus.audio)
Saw goes to bus 10 , and bus 10 clearly shows an UNFILTERED signal
Hp filter synthdef recieves on bus 10 and sends to bus 20
The filtered signal is showing on bus 20 , so in my opinion this shows that either the filtering is happening on bus 10 but the osciloscope only shows the ingoing signal BEFORE processing .
Or the processing is happening on bus 20 .

Xfade in the set line crossfades between totally unfiltered and filtered , question is on what BUS is the filtering happening ?

(
SynthDef(\filter,
	{
		|in,vol=0.5,cutoff=800,reso=0.5,xfade=(-1)|
		var sig,processed;
		sig=In.ar(in,2);
		processed=RHPF.ar(sig,freq:cutoff,rq:reso);
		processed=XFade2.ar(processed,sig,pan:xfade);
		Out.ar(0,processed)
}).add
)

///////
~filtah=Synth(\filter,[\cutoff,1200,\reso,0.1,\in,10,\xfade,-1])
~filtah.set(\cutoff,1500,\reso,0.2,\xfade,-1)
~filtah.free

/////
(
SynthDef(\saw,
{ |out,freq=60,vol=0.5,att=0.001,dec=0.250|
var sig,env;
sig=SawDPW.ar(freq.midicps)*vol;
env=EnvGen.ar(Env([0,1,0],[0.001,0.250],[0,-5]),doneAction:2);
sig=sig*env!2;
Out.ar(out,sig);
}).add
)
////
~yoda=Synth(\saw)
~yoda.free;
/////
(
Pdef(\seq,
	Pbind(\instrument,
		\saw,
		\dur,0.125,
		\freq,Pseq([48,51,49,55,52],inf),
		\out,10,
	)
)
)
//
Pdef(\seq).play
Pdef(\seq).stop

No, this is due to a mistake in your routing strategy. (Referring to Audiobus(server,numchann) - #45 by gentleclockdivider )

What would be required for bus 10’s contents to be altered?

The only way this can happen is if something writes to that bus.

Now where in your code is anything writing back to bus 10?

That’s right… Nowhere. You’re currently hardcoding a target of 0 (which btw will prevent you later from implementing submixes). So of course bus 10 can show only the dry signal.

This brings us back around to my model, where I had effect synths doing ReplaceOut back onto the same bus. In my approach, the scope would show the final signal in the channel’s bus.

See, I didn’t make that suggestion because “I kinda like it but other ways are just as good.” I do it this way because it really works better – conceptually simpler, modularized, expandable – than other ways. Yeah, I realize I’m tooting my own horn here, but I put a lot of thought into it at the beginning of my time with SC, and it’s paid off massively over the years in terms of not fighting with buses. I’d be very happy if others benefited from that experience.

hjh

ok , I appreciate your mixing model but I don’t want to get ahead of something which I clearly still struggle with
I don’t want to use other people’s implementations (no matter how good they are ) unless I understand it 100% , it would feel like cheating to me .

But at the same time I get the result I expect because I can actually hear what to expect ( dry wet mixing ) , so this means the bus routing is NOT intuitive at all !

Question 1 : So where is the filtering happening then on my previous post ( saw goes to 10 , filtereffect takes from 10 and out to 0)

Question 2 :On which bus does an effectsynthdef reside when it takes input from 10 and routes back to bus 0

Question 3 .: I create two audio busses ~foo=Bus.audio . the host shows info → Bus(audio, 14, 2, localhost) ,
and ~bar =Bus(audio, 16, 2, localhost)
To which bus does the synthdef sends it signal when out=~foo ?
Question 4 Which bus does synthdef EFFECT processes when it takes input from ~foo
Question 5 .Which Bus does synthdef EFFECT sits on when it takes input from ~bar and out is set to 0
Question 6 , When I set a synthdefEFFECT to in ~bar , and out=~bar I hear nothing , why ?

Answer1 = bus 0
Answer2=bus 10
Answer 3=bus 14
Answer4=bus 14
Answer 5=takes from bus 16 and sends to bus 0
Questin 6:because is sends the signal back to it’s receiving bus =16, and stays there

Could you tell me if all these answers are wrong ?

Let me put it in slightly different terms.

As you’re discovering, the field of possible mistakes with bus routing is very large.

My suggestions are intended to reduce the size of the field of possible mistakes.

It’s a valid learning approach, actually: like, if your piano teacher corrects your suboptimal fingering and you ask why??? And you don’t understand why, right now, but months or years later, you think back to it and… ohhhh… there was a reason.

And maybe at that point, you would be able to find an alternative that works just as well. But you don’t have to find that alternative today.

Synths don’t reside on buses.

They read from and write to buses.

Rethink all of the questions from this perspective.

Kinda late here, night night.

hjh

O.k I think I’ve got it
These are two examples of serial effects routing
The first piece of code is simply using output numbers
Synthdef saw goes into filter then in delay ,delay goes to output
you can varry the crossfade
Order of execution
Execution of busses is not necessary ( in this example )
First execute synthdef layla and ~comber=synth
The execute filter synthdef and ~filtah=Synth
This will bring the filter on top of the group , so first filtering then delay
You can alter the filter frequency by executing ~filtah.set second line , or set xfade in the
first ~comber.set line to +1 to let the filtered signal through but unnafected by delay
Lastly execute saw +pbind

~filterbus=Bus.audio(s,2)///bus 4
~filterbus
~delaybus=Bus.audio(s,2)//bus 6
~delaybus
~testbus=Bus.audio(s,2)//bus 8
~testbus

(
SynthDef(\filter,//takes saw input and filters it the sends it to ~delaybus
	{
		|in,out,vol=0.5,cutoff=800,reso=0.5,xfade=(-1)|
		var sig,processed;
		sig=In.ar(in,2);
		processed=RHPF.ar(sig,freq:cutoff,rq:reso);
		processed=XFade2.ar(processed,sig,pan:xfade);
		Out.ar(out,processed)
}).add
)
//...


(
SynthDef(\layla,///takes input from the filtered signal and sends it to bus 0
	{|mdt=0.250,dt=0.10,dect=0.1,modspeed=0.5,modamt=0.01,hpf=100,in,xfadecontrol=0,out|
		var sig ,modulator,processed;

		sig=In.ar(in,2);
		modulator=SinOsc.ar(modspeed)*modamt;
		processed=CombC.ar(sig,mdt,dt+modulator,dect);
		processed=HPF.ar(processed,hpf);
		processed=XFade2.ar(processed,sig,xfadecontrol);
		Out.ar(out,processed)
}).add)
///......

~comber=Synth(\layla,[\in,12,\out,0,\dt,0.222,\dect,2,])///delay
~comber.set(\mdt,0.5,\dt,0.25 ,\dect,4,\modspeed,0.001,\modamt,0.001,\hpf,40,\xfadecontrol,-1)//crossfade between -1 totally wet delay or 1 no delay
~comber.set(\in,12,\out,0)
~comber.set(\in,~delaybus,\out,0)
~comber.set(\in,~testbus,\out,0)
~comber.set(\in,18,\out,0)
~comber.set(\in,20,\out,0)
~comber.free

~comber.set(\mdt,0.5,\dt,0.25 ,\dect,4,\modspeed,0.001,\modamt,0.001,\hpf,40,\xfadecontrol,-1)//crossfade between -1 totally wet delay or 1 no delay

///////
~filtah=Synth(\filter,[\cutoff,2000,\reso,0.1,\in,10,\out,12,\xfade,-1])//crossfade between a filter saw =(-1) or a dry saw =1
~filtah.set(\cutoff,3500,\reso,0.3,\xfade,-1,\out,0,\xfade,-1,\in,10,\out,12)
~filtah.set(\cutoff,15000,\reso,0.3,\xfade,-1,\out,~testbus,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,14,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,16,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,18,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,20,\xfade,-1)
~filtah.free
/////Unfiltered saw goes to filterbus
(///execute last !
Pdef(\seq,
	Pbind(\instrument,
		\saw,
		\dur,Pseq([1/4,1/4,1/2],inf),
		\freq,Pseq([48,50,53,57],inf),
		\dec,Pseq([0.120,0.050,0.200,0.050,0.725,0.125,0.01,0.02,0.02,0.02,0.02,0.5],inf),
		\out,10,
	)
)
)
//
t=TempoClock(96/60).permanent_(true)
Pdef(\seq).play(t)
Pdef(\seq).stop


//////////////


/////
(
SynthDef(\saw,
{ |out,freq=60,vol=0.5,att=0.001,dec=0.0250|
var sig,env;
sig=SawDPW.ar(freq.midicps)*vol;
env=EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
sig=sig*env!2;
Out.ar(out,sig);
}).add
)
////







The second piece of code is identical but using busses , so executing busses first , rest is thesame

~filterbus=Bus.audio(s,2)///bus 4
~filterbus
~delaybus=Bus.audio(s,2)//bus 6
~delaybus
~testbus=Bus.audio(s,2)//bus 8
~testbus

(
SynthDef(\filter,//takes saw input and filters it the sends it to ~delaybus
	{
		|in,out,vol=0.5,cutoff=800,reso=0.5,xfade=(-1)|
		var sig,processed;
		sig=In.ar(in,2);
		processed=RHPF.ar(sig,freq:cutoff,rq:reso);
		processed=XFade2.ar(processed,sig,pan:xfade);
		Out.ar(out,processed)
}).add
)
//...


(
SynthDef(\layla,///takes input from the filtered signal and sends it to bus 0
	{|mdt=0.250,dt=0.10,dect=0.1,modspeed=0.5,modamt=0.01,hpf=100,in,xfadecontrol=0,out|
		var sig ,modulator,processed;

		sig=In.ar(in,2);
		modulator=SinOsc.ar(modspeed)*modamt;
		processed=CombC.ar(sig,mdt,dt+modulator,dect);
		processed=HPF.ar(processed,hpf);
		processed=XFade2.ar(processed,sig,xfadecontrol);
		Out.ar(out,processed)
}).add)
///......

~comber=Synth(\layla,[\in,~delaybus,\out,0,\dt,0.222,\dect,2,])///delay
~comber.set(\in,12,\out,0)
~comber.set(\in,~delaybus,\out,0)
~comber.set(\in,~testbus,\out,0)
~comber.set(\in,18,\out,0)
~comber.set(\in,20,\out,0)
~comber.free

~comber.set(\mdt,0.5,\dt,0.325 ,\dect,4,\modspeed,0.001,\modamt,0.001,\hpf,40,\xfadecontrol,-1)//crossfade between -1 totally wet delay or 1 no delay

///////
~filtah=Synth(\filter,[\cutoff,2000,\reso,0.1,\in,~filterbus,\out,~delaybus,\xfade,-1])//crossfade between a filter saw =(-1) or a dry saw =1
~filtah.set(\cutoff,3500,\reso,0.3,\xfade,-1,\out,0,\xfade,-1,\in,~filterbus,\out,~delaybus)//change frequency
~filtah.set(\cutoff,15000,\reso,0.3,\xfade,-1,\out,~testbus,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,14,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,16,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,18,\xfade,-1)
~filtah.set(\cutoff,1200,\reso,0.3,\xfade,-1,\out,20,\xfade,-1)
~filtah.free
/////Unfiltered saw goes to filterbus
(///execute last !
Pdef(\seq,
	Pbind(\instrument,
		\saw,
		\dur,Pseq([1/4,1/4,1/2],inf),
		\freq,Pseq([48,50,53,57],inf),
		\dec,Pseq([0.120,0.050,0.200,0.050,0.725,0.125,0.01,0.02,0.02,0.02,0.02,0.5],inf),
		\out,~filterbus,
	)
)
)
//
t=TempoClock(96/60).permanent_(true)
Pdef(\seq).play(t)
Pdef(\seq).stop


//////////////


/////
(
SynthDef(\saw,
{ |out,freq=60,vol=0.5,att=0.001,dec=0.0250|
var sig,env;
sig=SawDPW.ar(freq.midicps)*vol;
env=EnvGen.ar(Env([0,1,0],[att,dec],[0,-5]),doneAction:2);
sig=sig*env!2;
Out.ar(out,sig);
}).add
)
////




I know why it has been such a hassle because I have totally not been paying attention to the order of execution with serial routing ( previous code has comments for that reason )
Sometimes it was just silent other times it was not , absolutely crucial to first execute the effect that has to be last (bottom) in the chain .
I know , essential stuff …order of execution and groups is up next :slight_smile:

Last question then I am done
I have no problem with serial routing when using multiple busses like this
A test signal goes into ringmod effect , it’s then filtered and finally reverberated which goes to bus 0
Just simple in out buss , all we got to do is make sure is execution order
Idiot proof, but it works

~tester=Synth(\test,[\out,~ringbus])
~ringer=Synth(\ringmod,[\freq,4,\amt,1,\in,~ringbus,\out,~filterbus,\xfade,-1])
~filtah=Synth(\filter,[\cutoff,2000,\reso,0.1,\xfade,-1,\in,~filterbus,\out,~revbus])
~reverberate=Synth(\reverb,[\mix,0,\room,0.5,\in,~revbus,\out,0])

Now , is it possible to have serial effects routing on the same bus , adhering the order of execution
So the block graph looks like
1

All effects are set to ~awesome bus , reverberate has 0 as output
So far I haven’t managed to get the same result as with multiple busses
Just a simple yes or no is enough , I’ll investigate further

`~tester=Synth(\test,[\out,~awesomebus])
~ringer=Synth(\ringmod,[\freq,4,\amt,1,\in,~awesomebus,\out,~awesomebus,\xfade,-1])
~filtah=Synth(\filter,[\cutoff,2000,\reso,0.1,\in,10,\out,12,\xfade,-1,\in,~awesomebus,\out,~awesomebus])
~reverberate=Synth(\reverb,[\mix,0,\room,0.5,\in,~awesomebus,\out,0])`

Order of execution still applies when using separate busses. If you execute the synths in the wrong order in the first example things will still not work.

The good way to handle this is to provide an argument for the addAction key when declaring your Synths, or using one of the addAction methods. I like addAfter for serial routing

~tester=Synth(\test, [\out,~ringbus])
~ringer=Synth.addAfter(~tester, \ringmod,[\freq,4,\amt,1,\in,~ringbus,\out,~filterbus,\xfade,-1])
~filtah=Synth.addAfter(~ringer, \filter,[\cutoff,2000,\reso,0.1,\xfade,-1,\in,~filterbus,\out,~revbus])
~reverberate=Synth.addAfter(~filtah, \reverb,[\mix,0,\room,0.5,\in,~revbus,\out,0])
 

You can use the same technique when routing to busses, or not. This begins to guarantee correct order of execution.

I think you might be getting results when using the same bus for everything, versus patching from one module’s output bus to another’s input bus if you’re not using ReplaceOut.

Try your series patch, but swap all the Outs for ReplaceOut (except for your \test Synth). I think it should sound the same as your first example

Yes , I am now well aware that order of execution matters with separate busses, see yesterday’s post
Thanks

Time machine:

SynthDef(\myFx, { |bus, mix|
    var sig = In.ar(bus, 2);
    var wet = ... your fx processing...;
    ReplaceOut.ar(bus, XFade2.ar(sig, wet, mix * 2 - 1));
}).add;

I usually start with a template like this.

I don’t get why there is the same bus arg for the Replace.out

… and now you understand.

Anyway ReplaceOut onto the same bus.

hjh