Pbind passing arguments from variable?

Hello everyone.
I was wondering is it possible to somehow pass some pre-defined arguments into a Pbind?

I am certain my question becomes clear from the given exampe:


//this is how it is supposed to sounds
(
Pbind(
	\amp, Pseq([0.3,0.1,0.1,0.1],inf),
	\degree, Pseq([0,1,2,3],inf),
	\dur, 0.25,
).play;
)
//this is the way i want to make it sound like the previous one
(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
Pbind(
	\args, ~args,
	\dur, 0.25,
).play
)

So basically I want the Pbind to adapt somehow the \amp and \degree from the ~args argument.
Is that possible somehow?
Thank you very much!

Edit: found an even simpler way:

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
Pbind(
	\dur, 0.25,
	* ~args
).play
)

Other methods:

The standard way to do that is by pattern composition (Pchain or its shortcut <>):

(
~args = Pbind(\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf));
(~args <> Pbind(
	\dur, 0.25,
)).play
)

or

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
(Pbind(* ~args) <> Pbind(
	\dur, 0.25,
)).play
)

But if it’s important for you to have it inside the Pbind, you can modify the event from inside the Pbind and do what you want

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
Pbind(
	\args, ~args,
	\setter, Prout({ arg ev; 
		var strdict = ev[\args].asDict.collect(_.asStream);
		inf.do {
			var vals = strdict.collect(_.next(ev));
			ev.putAll(vals); 
			ev.postln; 
			ev = 1.yield; // Prout should always yield a value to avoid infinite loop
		}
	}),
	\dur, 0.25,
).play
)
3 Likes

Thank you very much!
That is the solution to my question!
However I still struggle to archive the thing i wanted to archive.
I actually wanted to be able to change the ~args on the fly and make the pattern adapt to it.

I guess something similar to

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
Pbind(
	\dur, 0.25,
	* Pfunc{~args}
).play
)

And in a later step to set:

~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([3,2,1,0],inf)];

And this should pick up at the same position, for the other args pattern, but change the \degree key for example.

I guess this would be possible somehow in the Prout way, but i still struggle to figure it out. Would be also grateful for a solution to this question in any way.

But thank you very much for the previous answer, it helped a lot already!

To dynamically change a value, use Pfunc. To dynamically change a value pattern, use Plazy. To dynamically change an event pattern, use Pdef.

Some examples:

// dynamically changing a value
(
s.waitForBoot({
	var pat;
	
	~duration = 1;
	
	pat = Pbind(
		\degree, Pseq([1,2,3], inf),
		\dur, Pfunc { ~duration },
	);
	
	pat.play;
})
)

// dynamically change ~duration
~duration = 0.1;
~duration = 0.5;





// dynamically changing a value pattern
(
s.waitForBoot({
	var pat;
	
	~degrees = [1,2,3];
	
	pat = Pbind(
		\degree, Pn(Plazy{ Pseq(~degrees,1) },inf),
		\dur, 0.3
	);
	
	pat.play;
});
)

// dynamically change ~degrees: change happens when previous pattern is fully played
~degrees = [4,5,6];
~degrees = [11,12,13,14,15,14];




// dynamically change a complete event pattern
(
s.waitForBoot({
	~degrees = [1,2,3];
	~pat = Pbind(
		\degree, Pn(Plazy{ Pseq(~degrees,1) },inf),
		\dur, 0.3
	);
	
	Pdef(\pat, ~pat);
	
	Pdef(\pat).play;
});
)

// dynamically change complete pattern
(
~pat = Pbind(
	\degree, Pwhite(0,12,inf),
	\dur, Prand([0.125, 0.25,0.5], inf)
);
Pdef(\pat, ~pat);
)


This is a very common confusion about variables.

Variables simply don’t work that way in SC. When you use a variable in an expression, it resolves immediately to its value. Downstream has no idea which variable it came from, so you can’t use the variable at that point to affect downstream behavior.

To be able to replace child patterns of a Pbind on the fly, I’d suggest Pbindef.

hjh

Well the problem with Pbindef is, that it does reset the order.

//start some pdef
Pdef(\x, Pbind(\dur, 0.3, \degree, Pseq([0,1,2,3,4,5,6,7,8,9],inf))).play;
//no matter at what point you trigger this, it starts always at 9
Pbindef(\x, \degree, Pseq([9,8,7,6,5,4,3,2,1,0],inf));

I’ve figured, this could be one way of solving it:

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];
Pbind(
	\args, ~args,
	\setter, Pn(Prout({arg ev;
		inf.do {
			|counter|
			var vals,strdict;
			strdict = ~args.asDict.collect(_.asStream);
			vals = strdict.collect(_.reset(ev));
			(1+counter).do{
				vals = strdict.collect(_.next(ev));
			};
			// strdict.postln;
			vals.postln;
			ev.putAll(vals);
			//ev.postln;
			ev = 1.yield;
		}
	})),
	\dur, 0.25,
).play
)
//alter it:
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([3,2,1,0],inf)];
//bring it back:
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf)];

But this solution is very bad because i do in counter.do{something next}, next a couple of times. which is bad for high numbers. still looking for someway to write this better

The problem with your solution is for each event you compute counter values, but it is only necessary to do it when you change ~args. One solution is to set ~args to nil after reading its value so when it’s set again, you can detect the change and forward the pattern only in this case. Another problem is counter will become very high with time but your pattern only have a few items repeating over and over. One solution is to limit the forwarding to 16 items if you know your patterns will not be longer.

(
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq([0,1,2,3],inf), \bla, \rah, \legato, 0.1];
Pbind(
	\setter, Prout({ arg ev; 
		var strdict, vals;
		var quant = 16;
		inf.do { arg idx;
			if(~args.notNil) {
				strdict = ~args.asDict.collect(_.asStream);
				~args = nil;
				( idx % quant ).do {
					vals = strdict.collect(_.next(ev));
				};
			};
			vals = strdict.collect(_.next(ev));
			ev.putAll(vals); 
			ev.postln; 
			ev = 1.yield; // should yield a value to avoid infinite loop
		}
	}),
	\dur, 0.25,
).play
)

~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq((9..0),inf), \bla, \rah, \legato, 0.1];
~args = [\amp, Pseq([0.3,0.1,0.1,0.1],inf),\degree, Pseq((0..9),inf), \bla, \rah, \legato, 0.1];

not well tested but seems to work (will fail if you start the pattern when ~args is nil, but you can add a if for this case)

1 Like

Yea makes all sense with the divergent counter values. Also thank you very much with this Prout approach!
I think I came up with a solution for myself where I initiate an ~args array with different patterns and _.next(ev) them all with every iteration. Then i just have another argument to choose which entry in the ~args i would like to choose.
Thank you very much for going through with this problem with me :smiley: