Noob: addressing Synth created by Pbind outside of Pbind?

Hi, when I added a SynthDef, and assign the according synth to a variable, I can control synth arguments via the VARIABLE_NAME.set method.

This does not work when the synth is being created via a Pbind, even if I assign the Pbind to a variable and try the VARIABLE_NAME.set method.

Please, is there a way to make this happen? Thanks in advance!

The easiest way is to create a group, use the group in the Pbind, and then set the controls on the group.

hjh

2 Likes

Thank you, but I have to admit I had hoped there is a way to address the synth directly that has been created by using Pbind.

Please let me explain: When I create a synth on the server from a SynthDef I’ve previously added to the server, I can assign this synth to a variable in sclang like this:
y=Synth(\Add_Mix);

Now I can address this synth and change its argument like this:
y.set(\factor, 1.023);

In my current (naive and/or wrong) understanding, calling .play on a Pbind creates an EventStreamPlayer and also a synth on the server, based on the SynthDef I added to server and referenced in the Pbind (in case I don’t provide a SynthDef, a default synth will be created to play the events):

(
x=Pmono(
	\Add_Mix,
	\lager, Pseq([5, 0, 0.05], inf),
	\dur, Pseq([0.125,0.125,0.125,0.125,0.25,0.25], inf),
	\frequenz, Pseq([150, 1700, 290, 600, 50, 1300], inf),
	\factor, Pseq([1.02, 1.2, 1.1, 1.6, 1.3], inf)
);
)

I know that in order to talk to the EventStreamPlayer, I need to assign it to a variable, like this:

~myPlayer = x.play(TempoClock(140/60));
~myPlayer.stop;

But how can I assign the synth created by Pbind to a different variable, so that I can .set its arguments while the EventStreamPlayer is running? I tried to assign the name of the SynthDef to variable in the Pbind, but alas, no success.

In trying to find a solution, I found that
s.queryAllNodes;
shows me the ID of the synth created by a Pbind (and the group the synth is in, and the root node). Isn’t there a way to address a synth on the server if the synth’s ID is known? Or in other words: If I can directly address a synth I created with Synth() by assigning to a variable, why can’t I directly access the synth created by a Pbind?

If I may take even more of your time, please allow me some related follow-up questions (please let me know if shall better create separate topics for these):

  • I tried to understand groups by reading up in the documentation. I believe I understand so far, that
    (a) groups do contain synths and determine their processing order, as well that
    (b) there can be multiple groups and that their processing order can also be determined, and that
    (c) groups can be used to control arguments of all the synths in said group.
    But I did not yet find the syntax how to address a specific synth inside a group containing multiple synths.
  • When I do s.queryAllNodes; or IDE > Server > Show Node Tree while an EventStreamPlayer is playing my synth, I see the root node with the (default) group in it and inside it the synth. Why don’t I see the EventStreamPlayer?
  • How come that Pbind requires a keyword-value-pair for referencing the SynthDef
    \instrument, \SYNTHDEF_NAME,
    whereas Pmono insists on just being told the SynthDef name
    \SYNTHDEF_NAME, ?

Thanks much again in advance for your help!

Code Example
(
SynthDef(\Add_Mix,{
	| lager = 10.0 |
	var factor = 1.1, freq = 400;
	freq = NamedControl.kr(\frequenz, 500, lager);
	factor = NamedControl.kr(\factor, 1.1, lager);
	Out.ar(0,
	Splay.ar(
		SinOsc.ar(
			[freq,
			freq*factor,
			freq*factor*factor,
			freq*factor*factor*factor,
			freq*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor*factor*factor
			],
			mul: 0.2)))
}).add
)

(
x=Pmono(
	\Add_Mix,
	\lager, Pseq([5, 0, 0.05], inf),
	\dur, Pseq([0.125,0.125,0.125,0.125,0.25,0.25], inf),
	\frequenz, Pseq([150, 1700, 290, 600, 50, 1300], inf),
	\factor, Pseq([1.02, 1.2, 1.1, 1.6, 1.3], inf)
);
)

~myPlayer = x.play(TempoClock(140/60));
~myPlayer.stop;
~myPlayer.play;

The default event type \note creates one synth per event, not per pattern or per pattern player. This means there is no safe way to assume that you can store a single synth in a variable and represent all of the pattern player’s activity.

It’s a wrong assumption to begin with.

Pmono creates one synth. But you cannot assume this for every pattern.

Also note that events do not create Synth objects. They create synth (lowercase) nodes in the server but they bypass the Synth (capital) class. So there is nothing created for you that you can set.

Pmono’s synth – you can get the ID using the event’s callback function (Pattern Guide 08: Event Types and Parameters | SuperCollider 3.12.2 Help). Then you can use Synth.basicNew to create an object that you can set.

There is no server object “EventStreamPlayer” – it is strictly language side.

hjh

1 Like

Aha, thank you very much, this made a lightbulb go on in my head!

So each voice of polyphonic hardware synthesizer (the “world” I come from) is realized in SC as a monophonic synth on the SC server. So I need to have a group as a container for the individual monophonic synths that make up a polyphonic synthesizer.

But I wonder why I do have to create a new group to achieve this, when there is already the Group 1 - default group existing. I assume there simply is no way to do this, correct?

OK, I first create a group:
g = Group.new;
In the Node Tree I see a new group inside the default group – success!

Then I add my SynthDef:
SynthDef(\Add_Mix, {ADD_MIX_FUNCTION}).add;

Now I put the SynthDef into group g:
y=Synth(\Add_Mix, target: g);
And a synth appeared inside the group inside the default group – more success!

But the synth also starts to be audible right away, how can I prevent that? I want the sound first to appear when my pattern starts playing, not before.

Now on to using the group in the Pbind, I tried it like this:

(
Pmono(
	\g,
	\lager, Pseq([5, 0, 0.05], inf),
	\dur, Pseq([0.125,0.125,0.125,0.125,0.25,0.25], inf),
	\frequenz, Pseq([150, 1700, 290, 600, 50, 1300], inf),
	\factor, Pseq([1.02, 1.2, 1.1, 1.6, 1.3], inf)
).play;
)

This is where I hit a roadblock – regardless if I write \g or just g, SC tells me

ERROR: SynthDef g not found
FAILURE IN SERVER /s_new SynthDef not found
FAILURE IN SERVER /n_set Node 1072 not found

The Node Tree shows that node 1071 exists, but the Pbind tries to address 1072. Please, what am I doing wrong, how do I address a group in a Pbind? Thanks much in advance!

Code Example
g = Group.new;

(
SynthDef(\Add_Mix,{
	| lager = 10.0 |
	var factor = 1.1, freq = 400;
	freq = NamedControl.kr(\frequenz, 500, lager);
	factor = NamedControl.kr(\factor, 1.1, lager);
	Out.ar(0,
	Splay.ar(
		SinOsc.ar(
			[freq,
			freq*factor,
			freq*factor*factor,
			freq*factor*factor*factor,
			freq*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor*factor,
			freq*factor*factor*factor*factor*factor*factor*factor*factor*factor*factor
			],
			mul: 0.2)))
}).add
)

y=Synth(\Add_Mix, target: g);

(
Pmono(
	\g,
	\lager, Pseq([5, 0, 0.05], inf),
	\dur, Pseq([0.125,0.125,0.125,0.125,0.25,0.25], inf),
	\frequenz, Pseq([150, 1700, 290, 600, 50, 1300], inf),
	\factor, Pseq([1.02, 1.2, 1.1, 1.6, 1.3], inf)
).play(TempoClock(140/60));
)

Side note:

collect
( 
	11,	freq*(factor**_)
)
;
fill
(
	Array, 11, 
	{
		|n| freq*(factor**n)
	}
)
1 Like

Hi Wolfgang,

use the \group key in your Pbind to specify the group.

http://doc.sccode.org/Tutorials/A-Practical-Guide/PG_08_Event_Types_and_Parameters.html

Then all synths created by that Pbind (by the player playing the events generated from the Pbind …) will be in that group, so you can set synth params by setting group params, as James recommended.

Why do you want to set them like this, instead of from within the Pbind? I guess there could be good reasons, but without further context, it seems like you are trying to mix two different approaches, the declarative/pattern vs. the imperative/routine …

Cheers,
eddi
https://alln4tural.bandcamp.com

1 Like

@Rainer: Thanks for two different ways of condensing my verbose writing of all the frequencies, but I have to admit I don’t understand how these ways work yet, I will do some reading about collect and fill (especially how these ** work).

My background are analog hardware synthesizers, controlled by hardware step sequencers via control voltages. I usually set up a melodic sequence (= Pbind) which runs forever (well…almost) on its own, while I play parameters not controlled by the step sequencer (like Cutoff) with my hands (= .set) while the sequence is running.

I also may use a second step sequencer which is modulating e.g. Resonance, but I route its control voltage thru an attenuator, so that I can play the amount with which the step sequencer controls Resonance with my hands.

I am trying to learn how to replicate the basic structure of this in SC, but want to use the more exciting sonic capabilities of SC, and the more complex sequencing structure SC pattern offer.

This is why I am trying to have realtime access (ideally to both sound and sequences) while patterns are running.

Thank you very much for the explanation on how to address a group in a Pbind, I will try it out and report back!

@wolfgangschaltung One way to do this is by using a Pbind of type “\set”. Here is an example:

(
// create a synth and assign to variable:
~mysynth = Synth(\Add_Mix);

// set controls of this synth with Pbind of type "\set":
Pbind(
    \type, \set,
	\id, ~mysynth,
    \instrument, \Add_Mix,
    \args, #[],
	\lager, Pseq([5, 0, 0.05], inf),
	\dur, Pseq([0.125,0.125,0.125,0.125,0.25,0.25], inf),
	\frequenz, Pseq([150, 1700, 290, 600, 50, 1300], inf),
).play(TempoClock(140/60));
)

// once the Pbind is playing,
// set other synth controls yourself: 
~mysynth.set(\factor, 1.6);
~mysynth.set(\factor, 1.02);
~mysynth.set(\factor, 1.1);
1 Like

The ** just stands for exponentiation (repeated multiplication) - see the Symbolic Notations and Operators help files.

~freq = 430.54;

// the following produce equivalent results:
~freq * ~freq * ~freq;
~freq ** 3;     // base ** exponent
pow(~freq, 3);  // pow(base, exponent)    
~freq.cubed;

Rainer’s first solution 11.collect(freq * (factor**_)) uses the partial application syntax shortcut _ and is a more concise method of writing 11.collect({|n| freq * (factor**n)}). There are many different ways to write this type of expression, which all end up compiling to the same code in the end, but there are some nuances and limitations to using the _ in particular, which are mentioned in the Partial Application help file. Their second solution is using the very commonly used fill method of Array.

Ahh – this is my lightbulb moment in this thread.

I’m afraid my time is quite limited at the moment, but it occurs to me that (some of) your problems might stem from trying to model modules – whereas the things that you’re interacting with are the inputs to the modules.

One thing that differentiates modular inputs from synth arguments is that modular inputs are persistent, while synth argument values are forgotten when the synth node ends.

Another way to handle your requirement would be to find a mechanism that stores values on the server, independent of synth nodes – i.e., control buses.

If every input that you’re addressing interactively has a control bus, then you can set the value at any time. What’s missing, then, is a convenient way to map the synth inputs to the buses automatically, e.g.:

~buses = (
	filter1Freq: Bus.control(s, 1).set(2000),
	filter1Res: Bus.control(s, 1).set(1),
	...
);

~busArgs = ~buses.collect { |bus| bus.asMap };
~busArgArray = ~busArgs.asPairs;

… then ~busArgArray can be stitched onto a pattern using Pchain(myPattern, ~busArgArray) (though I would have to doublecheck the interaction between that and Pmono, no time just now).

That’s not quite developing this idea into a usable form, but maybe it’s helpful.

PS 1. These are idiosyncratic syntactic forms that may confuse other users. 2. The first won’t work; you can’t use partial application on more than one operator at once. You might get away with it in a SynthDef but it’s not a good habit to get into.

More typically:

11.collect { |n| freq * (factor ** n) }

// I typically write this as it leads to the right place in the documentation
Array.fill(11, { |n| freq * (factor ** n) })

hjh

2 Likes

Here is my approach:

  1. Start one synth and drives it with a Pbind
~fx=Synth(\delay, args: [\feedback,0], target:~effectGrp);
~fxp=Pbind(\type, \set, \id, ~fx.nodeID,  // <-- Address directtly the Synth
	\someargs, Pseq([Pseq((0,0.2..1).mirror,1),0],1).trace,
	\dur,4
).play;
)
  1. If you don’t want to have a static Synth, you can even store the latest synth played by the Pbind in a local variable.
y=Pbind(\instrument,\mySynth
	\dur,3,\degree,Prand(Scale.minor.degrees,inf));
~stream2=y.collect({|event| ~last=event; }).play; // <-- this is equal to y.play but it also the latest event in a variable ~last

~last is an Event. The latest Synth id is in ~last['id'][0]

This is an example where I’ve got 2 patterns playing independently. When the x reaches its end, it stops the y pattern, including the latest Synth played by y:

(
~last=nil;
~stream2=nil;

x=Pseq(
	[Pbind(\dur,2,\freq,Pn(220,2)),
		Pbind(\type,\off,\id,Pfunc({~stream2.stop;~last['id'][0]}) // release last synth and stop the pattern
			,\dummy,Pn(1,1)) // <-- to have this Pbind running only once
	]
);
y=Pbind(\dur,3,\degree,Prand(Scale.minor.degrees,inf));
)
(
x.play;
~stream2=y.collect({|event| ~last=event; }).play;
)

1 Like

Hi, sorry it took so long to respond, this week was crazy, today’s my first time with SC since almost one week (and oh, how quickly I forget things). First, thanks much to all who responded!

Second, I am now able to address the arguments of a monophonic synth both from a pattern and directly via .set, if I first create a synth, then adress this synth in the pattern (thanks to @PitchTrebler and @lgvr123). Here is…

…the code
(
~x = SynthDef(\_PMFB, {
	arg f=440, fb=0, amp=0.1;
	var signal;
	signal = SinOscFB.ar(freq: f, feedback: fb);
	signal = Pan2.ar(signal, amp);
	Out.ar(0, signal);
}).play;
)

(
~p = Pbind(
	\type, \set,
	\id, ~x,         // works fine
//	\id, ~x.nodeID,  // works fine as well
	\args, #[\f],
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2
).play;
)

~x.set(\fb,1);
~x.set(\fb,2);
~x.set(\fb,3);
~x.set(\fb,0);

~p.stop;
~p.start;

~x.free;
´´´

However, the “other way round” is still giving me headaches: If the monophonic synth is created by the pattern (Pmono), I can only change the arguments of this synth from a pattern, but not directly via .set. So I tried @jamshark70’s suggestion:

This works insofar, as the ID of the synth that Pmono created gets assigned to the local variable test, which gets posted with each event:

(
~x = SynthDef(\_PMFB, {
	arg f=440, fb=0, amp=0.1;
	var signal;
	signal = SinOscFB.ar(freq: f, feedback: fb);
	signal = Pan2.ar(signal, amp);
	Out.ar(0, signal);
}).add;
)

(
~p = Pmono(
	\_PMFB,
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, {var test; test = ~id; test.postln}
).play;
)

But as test is only a local variable, I can’t use it to create a Synth with the ID of the synth created by Pmono:

(
~y = Synth.basicNew(
	defName: \synth_created_by_pmono,
	server: s,
	nodeID: test //variable not defined
);
)

So I turned it into a global variable like this:

(
~p = Pmono(
	\_PMFB,
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, {var ~test; ~test = ~id; ~test.postln}
).play;
)

But unfortunately, this gives the…

…error message that the `~` is unexpected.
ERROR: syntax error, unexpected '~', expecting NAME or WHILE
  in interpreted text
  line 6 char 18:

  	\callback, {var ~test; ~test = ~id; ~test.postln}
                   ^
  ).play;
-----------------------------------
ERROR: Command line parse failed
-> nil

Please, what am I doing wrong? How can I access ~id correctly? Thanks much in advance!

It is normal. A ~test is a global variable, While the var defines a local variable.
So you should write \callback, {~test = ~id; ~test.postln}.
Nevertheless this will not work, because this will set the ~test variable of the event’s environment, while you aim at setting the one of the global environment.

[EDIT]

(
~p = Pmono(
	\default,
	\freq, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, { |event| ~test = event['id'][0]; ~test.postln}.inEnvir	
).play;
)

The inEnvir forces the function to be executed in the gloabl environment.
[END OF EDIT]

To be able to use the a set method you’ll need to have a Node object, while you have here a mere Node ID value.

So you have to instantiate a Node object for this nodeID like this:

~n=Node.basicNew(nodeID:~test);

Then you can do any setyou want on ~n.

1 Like

Here are three four different approaches you can try out to see if they are close to what you are looking for.

(added a fourth approach)

#1

// NodeProxy mono synth
(
Ndef(\monosynth, {
    var freq = \freq.kr(220);
    var trig = \trig.tr(1);
    var sig = Saw.ar(freq);
    var aeg = Env.perc(0.01, 0.2).ar(gate:trig);
    var ffreq = \cutoff.kr(2000) * aeg;
    var res = \res.kr(0.5).linlin(0, 1, 1, 0.01);
    sig = RLPF.ar(sig, ffreq, res);
    sig = sig * aeg;
    Splay.ar(sig);
})
)

Ndef(\monosynth)[10] = \set -> Pbind(\degree, Pseq([0, 1, 2, 3], inf), \dur, 0.25, \trig, 1)
Ndef(\monosynth).play
Ndef(\monosynth).stop

Ndef(\monosynth).set(\cutoff, 1000)
Ndef(\monosynth).set(\cutoff, 4000)

Ndef(\monosynth).set(\res, 0)
Ndef(\monosynth).set(\res, 0.5)
Ndef(\monosynth).set(\res, 0.7)

#2

(
SynthDef(\synth, {
    
    var freq = \freq.kr(220);
    var gate = \gate.kr(1);
    var sig = Saw.ar(freq);
    var aeg = Env.perc(0.01, 0.2).ar(gate:gate, doneAction:Done.freeSelf);
    var ffreq = \cutoff.kr(2000) * aeg;
    var res = \res.kr(0.5).linlin(0, 1, 1, 0.01);
    sig = RLPF.ar(sig, ffreq, res);
    sig = sig * aeg;
    sig = Splay.ar(sig);
    Out.ar(\out.kr(0), sig);
    
}).add
)

// control buses
Ndef(\cutoff, {\val.kr(1000)})
Ndef(\res, {\val.kr(0.5)})

// pattern
(
Pdef(\synth, Pbind(
    \instrument, \synth,
    \degree, Pseq([0, 1, 2, 3], inf), 
    \dur, 0.25,
    \legato, 0.1,
    \cutoff, Ndef(\cutoff),
    \res, Ndef(\res)
))
)

Pdef(\synth).play
Pdef(\synth).stop

// instead of controling the synth per se
// you are controling the buses used by the synth
Ndef(\cutoff).set(\val, 1000)
Ndef(\cutoff).set(\val, 4000)

Ndef(\res).set(\val, 0)
Ndef(\res).set(\val, 0.5)

#3

(
SynthDef(\monosynth, {
    
    var freq = \freq.kr(220);
    var trig = \trig.tr(1);
    var sig = Saw.ar(freq);
    var aeg = Env.perc(0.01, 0.2).ar(gate:trig);
    var ffreq = \cutoff.kr(2000) * aeg;
    var res = \res.kr(0.5).linlin(0, 1, 1, 0.01);
    sig = RLPF.ar(sig, ffreq, res);
    sig = sig * aeg;
    sig = Splay.ar(sig);
    Out.ar(\out.kr(0), sig);
    
}).add
)

~mono = Synth(\monosynth, [\trig, 0])
(
Pdef(\mono, Pbind(
    \type, \set,
    \id, Pfunc({ ~mono.nodeID }),
    \args, #[\freq, \trig],
    \degree, Pseq([0, 1, 2, 3], inf), 
    \dur, 0.25, 
    \trig, 1
))
)

Pdef(\mono).play
Pdef(\mono).stop

~mono.set(\cutoff, 1000)
~mono.set(\cutoff, 4000)

~mono.set(\res, 0)
~mono.set(\res, 0.5)
~mono.set(\res, 0.7)

#4

(
SynthDef(\monosynth, {
    
    var freq = \freq.kr(220);
    var trig = \trig.tr(1);
    var sig = Saw.ar(freq);
    var aeg = Env.perc(0.01, 0.2).ar(gate:trig);
    var ffreq = \cutoff.kr(2000) * aeg;
    var res = \res.kr(0.5).linlin(0, 1, 1, 0.01);
    sig = RLPF.ar(sig, ffreq, res);
    sig = sig * aeg;
    sig = Splay.ar(sig);
    Out.ar(\out.kr(0), sig);
    
}).add
)


(
Pdef(\mono, 
    Pfset({
        ~id = Synth(\monosynth, [\trig, 0]);
        // add a reference to the top environment
        // so the synth can be manipulated
        topEnvironment[\mono] = ~id
    }, 
    Pbind(
        \type, \set,
        \args, #[\freq, \trig],
        \degree, Pseq([0, 1, 2, 3], inf), 
        \dur, 0.25, 
        \trig, 1
    ))
)
)

Pdef(\mono).play
Pdef(\mono).stop

~mono.set(\cutoff, 1000)
~mono.set(\cutoff, 4000)

~mono.set(\res, 0)
~mono.set(\res, 0.5)
~mono.set(\res, 0.7)

You can also use Pdef set method to access synth parameters outside of a Pbind

(
SynthDef(\synth, {
    var freq = \freq.kr(220);
    var trig = \gate.kr(1);
    var sig = Saw.ar(freq);
    var aeg = Env.perc(0.01, 0.2).ar(gate:trig, doneAction:Done.freeSelf);
    var ffreq = \cutoff.kr(2000) * aeg;
    var res = \res.kr(0.5).linlin(0, 1, 1, 0.01);
    sig = RLPF.ar(sig, ffreq, res);
    sig = sig * aeg;
    sig = Splay.ar(sig);
    Out.ar(\out.kr(0), sig);
    
}).add
)

(
Pdef(\synth, 
    Pbind(
        \instrument, \synth,
        \degree, Pseq([0, 1, 2, 3], inf), 
        \dur, 0.25, 
        \legato, 0.1
    ))
)
)

Pdef(\synth).play
Pdef(\synth).stop

Pdef(\synth).set(\cutoff, 1000)
Pdef(\synth).set(\res, 0)

Pdef(\synth).gui


Pdef(\synth).set(\cutoff, 4000)
Pdef(\synth).set(\res, 0.5)
Pdef(\synth).set(\res, 0.7)

1 Like

Thank you for the explanation reg. event environment and global environment. I tried the following, which assigns the Node ID of the synth created by the pattern to the global variable a. I can access a outside the pattern and retrieve the correct Node ID, but even though the Synth object is created with the correct ID, I still can not access the argument fb.

(
~x = SynthDef(\_PMFB, {
	arg f=440, fb=0, amp=0.1;
	var signal;
	signal = SinOscFB.ar(freq: f, feedback: fb);
	signal = Pan2.ar(signal, amp);
	Out.ar(0, signal);
}).add;
)

(
~p = Pmono(
	\_PMFB,
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, {a = ~id; a.postln}
).play;
)

a; //contains the correct ID outside of the pattern, hooray!

(
~y = Synth.basicNew(
	defName: \_PMFB,
	server: s,
	nodeID: a //Creates a Synth with the ID of the synth created by the pattern
);
)

~y.set(\fb,1); //Fails to set the arg fb in the synth created by the pattern, user cries of frustration!

I also tried
~y=Node.basicNew(nodeID: a);
alas, no success either.

It feels like I came so close to get it done via this method, yet I fail. If there’s really no way to make it work this way, I will try the other methods kindly suggested by you and @droptableuser, but before that I would at least find out why the method above fails although it looks right.

This is really a rollercoaster ride. One day I’m like “I think I am slowly learning how to use SC” and the other day it’s like “I was wrong, I do not understand it”.

Thanks for helping me.

You probably missed my edit :wink: Have a look at it. And don’t worry. Learning SC is a really slow process…

Here is your code, taking into account my edit:

(
~x = SynthDef(\_PMFB, {
	arg f=440, fb=0, amp=0.1;
	var signal;
	signal = SinOscFB.ar(freq: f, feedback: fb);
	signal = Pan2.ar(signal, amp);
	Out.ar(0, signal);
}).add;
)

(
~p = Pmono(
	\_PMFB,
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, { |event| ~a = event['id'][0]; ~a.postln}.inEnvir
).play;
)

~a; 

(
~y = Synth.basicNew(
	defName: \_PMFB,
	server: s,
	nodeID: ~a //Creates a Synth with the ID of the synth created by the pattern
);
)

~y.set(\fb,0); 
1 Like

Thank you very much for putting me on the right track by being so kind to modify my code. So I ran your code (works, of course) and mine (didn’t work, of course) one after the other and paid attention to the post window, this is what I got (I omitted repetitions):

/////////////////////////////
// YOUR CODE'S POST OUTPUT //
/////////////////////////////
1009                     // ~a.postln
-> 1009                  // on ~a;
-> Synth('_PMFB' : 1009) // on Synth.basicNew
-> Synth('_PMFB' : 1009) // on .set message

///////////////////////////
// MY CODE'S POST OUTPUT //
///////////////////////////
[ 1014 ]                     // a.postln
-> [ 1014 ]                  // on a;
-> Synth('_PMFB' : [ 1014 ]) // on Synth.basicNew
-> Synth('_PMFB' : [ 1014 ]) // on .set message

So when my code
\callback, {a = ~id; a.postln}
assigns ~id to a, it actually assigns the array ~id with the size 1 to a, which explains the square brackets around the node ID in my post window, and why the created synth is useless.

So I changed the callback to assign a the value of the array at index 0
\callback, {a = ~id[0]; a.postln}
and now it works, what a great start into this day! :slight_smile:

Working Code
(
~x = SynthDef(\_PMFB, {
	arg f=440, fb=0, amp=0.1;
	var signal;
	signal = SinOscFB.ar(freq: f, feedback: fb);
	signal = Pan2.ar(signal, amp);
	Out.ar(0, signal);
}).add;
)

(
~p = Pmono(
	\_PMFB,
	\f, Pseq([200,400,600,800,1000], inf),
	\dur, 0.2,
	\callback, {a = ~id[0]; a.postln}
).play;
)

(
~y = Synth.basicNew(
	defName: \_PMFB,
	server: s,
	nodeID: a
);
)

~y.set(\fb,1);
~y.set(\fb,2);
~y.set(\fb,3);
~y.set(\fb,0);

Thank you, I doubt that I would have found the solution without your example running in comparison to mine. My lesson learned: Pay more and closer attention to the post window.

P.S. There’s a side effect about this approach (trying to address the synth created by a pattern by pulling its node ID) I need to keep in mind: The moment I stop and start a pattern, the restarted pattern creates a new synth with a new node ID, whereas the Synth created by Synth.basicNew is still using the old node ID.

P.P.S. Now I need to understand how to make the group approach mentioned by @jamshark70 and @alln4tural work. But first off to visit the parents!

Thank you for the four examples. Sorry that I did not get to these yet, but I was so obsessed to find out why my way of thinking wasn’t working. I will dive into learning about Pdef and Control busses after I understand how to use the \group key.

You could create a Synth in the callback function, instead of only saving the ID.

hjh

2 Likes