Event \type \set sync

hey,
i have been using PmonoArtic with Pfindur inside Pspawner for scheduling events so far and have to restructure the setup to Synth + Pbind with Event \type \set instead because of some detailed reasons.

The PmonoArtic, Pfindur inside Pspawner Setup would look like this:

(
SynthDef(\pluck, {
	var trig = \trig.tr(1);
	var lfoRate = \lfoRate.kr(1);
	var sig, lfo;
	lfo = LFSaw.ar(lfoRate * (1 + (LFNoise2.kr(lfoRate) * 0.5)));
	sig = SinOsc.ar(lfo.linexp(-1, 1, 100, 8000)) + SinOsc.ar(lfo.linexp(-1, 1, 1000, 4000));
	sig = Pluck.ar(sig, trig, 0.1, \freq.kr(50).reciprocal, \dec.kr(0.1), \coef.kr(0.5));
	sig = sig * \amp.kr(0.25);
	Out.ar(\out.kr(0), sig);
}).add;
)

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

(
Pdef(\pluckL,
	PmonoArtic(\pluck,
		\legato, 1.0,
		\dur, 1/12,
		\freq, 125,
		\dec, 0.2,
		\coef, 0.5,
		\lfoRate, 0.3,
		\amp, 0.125,
		\out, 0,
	)
);

Pdef(\pluckR,
	PmonoArtic(\pluck,
		\legato, 1.0,
		\dur, 1/12,
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\lfoRate, 0.2,
		\amp, 0.125,
		\out, 1,
	)
);

Pdef(\player,
	Pspawner({ |sp|
	
		sp.par(Pfindur(12, Pdef(\pluckR)));
		sp.seq(Pfindur(12, Pdef(\pluckL)));
		
		sp.wait(12);	
		sp.suspendAll;
	})
).play(t, quant:1);
)

Here is the attempt to use Synth + Pbind with Event \type \set

(
Tdef(\task,
	
	l = Synth(\pluck, [
		\freq, 125,
		\dec, 0.2,
		\coef, 0.5,
		\lfoRate, 0.3,
		\amp, 0,
		\out, 0
	]);
	
	r = Synth(\pluck, [
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\lfoRate, 0.2,
		\amp, 0,
		\out, 1,
	]);
	
);

Pdef(\pluckL,
	Pbind(
		\type, \set,
		\id, l.nodeID,
		\instrument, \pluck,
		\args, 0,

		\dur, 1/12,
		\freq, 125,
		\dec, 0.3,
		\coef, 0.5,
		\lfoRate, 0.3,
		\amp, 0.1,
		\out, 0,
));

Pdef(\pluckR,
	Pbind(
		\type, \set,
		\id, r.nodeID,
		\instrument, \pluck,
		\args, 0,

		\dur, 1/12,
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\lfoRate, 0.2,
		\amp, 0.1,
		\out, 1,
));

Pdef(\player,
	Pspawner({ |sp|
		
		Tdef(\task);
		
		sp.par(Pfindur(12, Pdef(\pluckR)));
		sp.seq(Pfindur(12, Pdef(\pluckL)));
		
		sp.wait(12);	
		sp.suspendAll;
	})
).play(t, quant:1);
)

1.) How can i make the Synth and the Pbind with Event \type \set run in sync? I was trying to use Tdef or a Routine. At the moment they are not running in sync, you can hear that when evaluating the code. the pitch always starts differently compared to the PmonoArtic approach.

2.) when using Pfindur i can easily end the streams. when now using the Synth + Event \type \set approach you also have to start and stop the Synth individually (which is intended). how would you go about that in the Pspawner setup below? so the synth starts and stops exactly at the same time the Pfindur does.

3.) Im also not sure how to go about the arguments. I think the Synth doesnt need any arguments at all. it should pick up all the arguments from the Pbind and just make sure the Stream will never die when im not telling it explicitly to do so.

thanks :slight_smile:

1 Like

You’ll need to understand messaging latency for this: Scheduling and Server timing | SuperCollider 3.12.2 Help

hjh

Something like this?..

Pdef(\player,
	Pspawner({ |sp|
		
		Tdef(\task);
		
		sp.par(Pfindur(12, Pdef(\pluckR)));
		sp.seq(Pfindur(12, Pdef(\pluckL)));

        l.release;
        r.release;
		
		sp.wait(12);	
		sp.suspendAll;
	})
).play(t, quant:1);

hey, thank you for helping me out.
ive looked at the helpfile and made a first attempt.
The scheduling is accurate i think.
But the problem is that i would like to specify the Pdefs outside of the Pspawner, when doing so i get a Node not found error because the nodeID which im referencing to is not exisiting on the server before the Synth are executed.
what can i do about that?

(
Pdef(\player,
	Pspawner({ |sp|
		
		s.makeBundle(s.latency, { l = Synth(\pluck); });
		s.makeBundle(s.latency, { r = Synth(\pluck); });
		
		sp.par(Pfindur(12, Pdef(\pluckL,
			Pbind(
				\type, \set,
				\id, l.nodeID,
				\instrument, \pluck,
				\args, 0,
				
				\dur, 1/12,
				\freq, 125,
				\dec, 0.3,
				\coef, 0.5,
				\lfoRate, 0.3,
				\amp, 0.1,
				\out, 0,
		))));
		
		sp.seq(Pfindur(12, Pdef(\pluckR,
			Pbind(
				\type, \set,
				\id, r.nodeID,
				\instrument, \pluck,
				\args, 0,
				
				\dur, 1/12,
				\freq, 130,
				\dec, 0.3,
				\coef, 0.5,
				\lfoRate, 0.2,
				\amp, 0.1,
				\out, 1,
		))));
		
		l.release;
		r.release;
		
		sp.wait(12);	
		sp.suspendAll;
	})
).play(t, quant:1);
)

hey, thanks for your help.
for release i would need a gated envelope right? ive added one.

to create a resource and use it in a pattern you can use Pproto

https://doc.sccode.org/Classes/Pproto.html

in the makeFunction you would create the synth nodes and then have access to them in the pattern. That should solve the initial synchronization issue i believe. The Pproto has a cleanupFunc - but i seem to recall it doesn’t actually work (i could be wrong). So if you want to stop the synths outside of the pattern you just need to assign the synths to global variables the way you are now.

thank you very much. i have had a look at the helpfile of Pproto and managed to get it running with my initial example:

(
SynthDef(\pluck, {
	var trig = \trig.tr(1);
	var sig, lfo, gainEnv;
	gainEnv = EnvGen.ar(Env.asr(0.01, 1, 1), \gate.kr(1), doneAction: Done.freeSelf);
	lfo = LFSaw.ar(0.3 * (1 + (LFNoise2.kr(0.3) * 0.5)));
	sig = SinOsc.ar(lfo.linexp(-1, 1, 100, 8000)) + SinOsc.ar(lfo.linexp(-1, 1, 1000, 4000));
	sig = Pluck.ar(sig, trig, 0.1, \freq.kr(50).reciprocal, \dec.kr(0.1), \coef.kr(0.5));
	sig = sig * \amp.kr(0.25) * gainEnv;
	Out.ar(\out.kr(0), sig);
}).add;
)

(
Pdef(\pluckL,
	Pbind(
		#[type, id, msgFunc], Pkey(\pluckLCtrl),
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 125,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 0,
));

Pdef(\pluckR,
	Pbind(
		#[type, id, msgFunc], Pkey(\pluckRCtrl),
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 1,
));

a = Pproto({
	~pluckL = (type: \on, instrument: \pluck).yield;
	~pluckLCtrl = [\set, ~pluckL[\id], ~pluckL[\msgFunc] ];
	
},
Pdef(\pluckL)
);

b = Pproto({
	~pluckR = (type: \on, instrument: \pluck).yield;
	~pluckRCtrl = [\set, ~pluckR[\id], ~pluckR[\msgFunc] ];
	
},
Pdef(\pluckR),
);
)

(
Pdef(\player,
	Pspawner({ |sp|
		
		sp.par(Pfindur(12, a));

		sp.seq(Pfindur(12, b));

		sp.suspendAll;
	})
).play;
)

But i think its not working with my setup:

one of the problems is that the Synth are released from the server when Pproto ends. can i adjust the cleanupfunction, so the Synths stay alive?
EDIT: i have read some of the threads about the user defined Pproto cleanup function. this seems to be a bit too advanced for my understanding.

the other one is that im using a function for gradually changing the keys of the Pdefs inside Pspawner and i cant access them if i have to wrap the Pdef in a Pproto and put the Pproto inside the Pfindur instead of the Pdef itself. thats also the reason for not merging the pluckR and pluckL with a Ppar.

damn…

not sure if this helps…

this will start a synth when the pattern starts and keep it sounding after the pattern has ended. to prevent the synth from sounding slightly before the pattern starts you can initialize the amp to 0 and then set it to the desired volume with the pattern…

(
Pdef(\a, 
    Pproto({
        l = Synth(\default, [\amp, 0]);
        ~id = l.nodeID;
    }, Pbind(
        \type, \set,
        \args, 0,
        \amp, 0.1,
        \degree, Pshuf( (0..5), inf )
    ))
)
)

(
Pdef(\spanwer, Pspawner({|sp|
    sp.seq( Pdef(\a).finDur(12) );
    \wait.postln;
    sp.wait(4);
    \release.postln;
    l.release;
    \done.postln;
}))
)

Pdef(\spanwer).play
Pdef(\spanwer).stop

thanks so much for your help. the synths stay alive thats really great :slight_smile:


(
SynthDef(\pluck, {
	var trig = \trig.tr(1);
	var sig, lfo, gainEnv;
	gainEnv = EnvGen.ar(Env.asr(0.01, 1, 1), \gate.kr(1), doneAction: Done.freeSelf);
	lfo = LFSaw.ar(0.3 * (1 + (LFNoise2.kr(0.3) * 0.5)));
	sig = SinOsc.ar(lfo.linexp(-1, 1, 100, 8000)) + SinOsc.ar(lfo.linexp(-1, 1, 1000, 4000));
	sig = Pluck.ar(sig, trig, 0.1, \freq.kr(50).reciprocal, \dec.kr(0.1), \coef.kr(0.5));
	sig = sig * \amp.kr(0.25) * gainEnv;
	Out.ar(\out.kr(0), sig);
}).add;
)

(
Pdef(\pluckL,
	Pbind(
		\type, \set,
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 125,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 0,
	)
);

Pdef(\pluckR,
	Pbind(
		\type, \set,
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 1,
	)
);

a = Pproto(
	{
		l = Synth(\pluck, [\amp, 0]);
		~id = l.nodeID;		
	},
	Pdef(\pluckL)
);

b = Pproto(
	{
		r = Synth(\pluck, [\amp, 0]);
		~id = r.nodeID;		
	},
	Pdef(\pluckR)
);
)

(
Pdef(\player,
	Pspawner({ |sp|

		sp.par(Pfindur(12, a));

		sp.seq(Pfindur(12, b));
		
		\wait.postln;
		sp.wait(4);
		\release.postln;
		l.release;
		r.release;
		\done.postln;
	})
).play;
)

but i cant access the keys of the Pbinds inside Pspawner when wrapping them in Pproto.
so i have to keep the synths and the Pbinds separately and put the Pdef with the Pbind \type \set inside the Pfindur and not the Pproto.

so i think i will have to work on my other version and be able to put the Pdefs outside the Pspawner:

(
Pdef(\player,
	Pspawner({ |sp|

		s.makeBundle(s.latency, { ~pluckL = Synth(\pluck); });
		s.makeBundle(s.latency, { ~pluckR = Synth(\pluck); });

		sp.par(Pfindur(12, Pdef(\pluckL,
			Pbind(
				\type, \set,
				\id, ~pluckL.nodeID,
				\instrument, \pluck,
				\args, 0,

				\dur, 1/12,
				\freq, 125,
				\dec, 0.3,
				\coef, 0.5,
				\amp, 0.125,
				\out, 0,
		))));

		sp.seq(Pfindur(12, Pdef(\pluckR,
			Pbind(
				\type, \set,
				\id, ~pluckR.nodeID,
				\instrument, \pluck,
				\args, 0,

				\dur, 1/12,
				\freq, 130,
				\dec, 0.3,
				\coef, 0.5,
				\amp, 0.125,
				\out, 1,
		))));

		~pluckL.release;
		~pluckR.release;

		sp.suspendAll;
	})
).play;
)

okay i think i can chain the Pdef(\pluckL) with Pbind(\id, ~pluckL.nodeID)
probably this is sloppy, but it works with the other functions Im using and i think its in sync.
any further ideas?

(
SynthDef(\pluck, {
	var trig = \trig.tr(1);
	var sig, lfo, gainEnv;
	gainEnv = EnvGen.ar(Env.asr(0.01, 1, 1), \gate.kr(1), doneAction: Done.freeSelf);
	lfo = LFSaw.ar(0.3 * (1 + (LFNoise2.kr(0.3) * 0.5)));
	sig = SinOsc.ar(lfo.linexp(-1, 1, 100, 8000)) + SinOsc.ar(lfo.linexp(-1, 1, 1000, 4000));
	sig = Pluck.ar(sig, trig, 0.1, \freq.kr(50).reciprocal, \dec.kr(0.1), \coef.kr(0.5));
	sig = sig * \amp.kr(0.25) * gainEnv;
	Out.ar(\out.kr(0), sig);
}).add;
)

(
Pdef(\pluckL,
	Pbind(
		\type, \set,
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 125,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 0,
));

Pdef(\pluckR,
	Pbind(
		\type, \set,
		\instrument, \pluck,
		\args, 0,
		
		\dur, 1/12,
		\freq, 130,
		\dec, 0.3,
		\coef, 0.5,
		\amp, 0.125,
		\out, 1,
));
)

(
Pdef(\player,
	Pspawner({ |sp|

		s.makeBundle(s.latency, { ~pluckL = Synth(\pluck); });
		s.makeBundle(s.latency, { ~pluckR = Synth(\pluck); });

		sp.par(Pfindur(12, Pdef(\pluckL) <> Pbind(\id, ~pluckL.nodeID) ));
		sp.seq(Pfindur(12, Pdef(\pluckR) <> Pbind(\id, ~pluckR.nodeID) ));
		
		\wait.postln;
		sp.wait(4);
		\release.postln;
		~pluckL.release;
		~pluckR.release;
		\done.postln;

		sp.suspendAll;
	})
).play;
)
1 Like