Using Pbindef in real-time

Dear community,

Working with Pbindef is a great way for me to control multiple SynthDef. I (and my poor brain) appreciate the readability and flexibility of making each parameter dynamic and controlling overall complexity.
However, I’m working for a real-time interactive piece, where certain events (a midi note, for example) change patterns in mid-action or start a new one, and I can’t avoid having a delay.

With this example :

//A
(
Pbindef(\test,
	\dur, 0.1,
	\amp, 0.1,
	\midinote, Pfunc{50}.trace
).play(quant:0)
)

//B
(Pbindef(\test, \midinote, 75).play(quant:0));

by playing B after A, I can see around 10 events (sometimes less, it’s not always the same number) played before the new midinote. . Of course, I understand that what’s displayed in the interpreter isn’t quite the actual calculation, but the delay is audible and prohibitive in this type of setup. Do you have any advice on the best way to proceed? Thanks a lot!

It seems that Pdefn is much more responsive, but I don’t understand isn’t it as much:

//C
Pbindef(\test, \midinote, Pdefn(\mn_p, Pfunc{60}.trace));

//D
Pdefn(\mn_p, Pfunc{75}.trace);

Whereas Pbind can also react almost immediately.

//E
(~test_rt = Pbind(
	\dur, 0.05,
	\amp, 0.1,
	\midinote, Pseq((50..60), inf).trace).play);
//F
(~test_rt.stop;
~test_rt = Pbind(
	\dur, 0.05,
	\amp, 0.1,
	\midinote, Pseq((75..105), inf).trace).play);
//G
(~test_rt.stop;
~test_rt = Pbind(
	\dur, 0.05,
	\amp, 0.1,
	\midinote, Pseq((40..50), inf).trace).play);

It is because Pbindf takes longer to create an instrument-specific proxy, and has to recreate it for each new call?

Thanks for helping me understand these supercollider subtleties!

Do you want it to change the currently active synths? Like x.set(\freq, 10), or do you want it to affect the next created synth?

Excuse me Jordan, I’m not sure I understand your question. In this case, I would like to change patterns controlling active synths. The example here is very basic, but I think it illustrates the point.

When you change the contents of a pattern, it can only change the next event. Changes to a pattern’s components do not retroactively find previous events’ node IDs and update those synths’ parameters.

To change synths that are already running, you have to set nodes in the server. My post about the same topic, yesterday: Create a routine of Pdefs (or Tdefs?) - #5 by jamshark70

hjh

Thank you also for this feedback. I read the topic, I think that explains some problems I’ve had using Pbind in Ndef (I’m preparing another question about this), but, I’m sorry, I can’t find an explanation for the difference of responsivenes between Pdefn, Pbind and Pbindef. Normally all three wait the next event to activate their changes, but Pbindef waits much longer than the others.

Fix it this way:

(
Pbindef(\test,
	\dur, 0.1,
	\amp, 0.1,
	\midinote, Pfunc{50}.trace
).quant_(0).play
)

play(quant: 0) is only a temporary override of the Pbindef’s quant property. With your original code, Pbindef(\test).quant remains 1.0, so the \midinote update will be quantized to the next clock beat. If you want quant:0 to apply to all operations on the Pbindef, then you need to set it as a property of the Pbindef.

Or:

Pdef.defaultQuant
-> 1.0

Pdef.defaultQuant = 0;

(A Pbindef is a Pdef, just with the added behavior of being able to change the pairs dynamically.)

Pdefn also has a defaultQuant, but this is nil by default.

An important difference between Pdef and Pdefn is that a Pdef is intrinsically timed – it manages an event pattern, whose resulting events each have a dur. Pdefn is just a value. The only way it relates to time is by being used in an event pattern. So you’d expect that changing an outside-of-time value pattern would take effect immediately. It also makes sense that, in a lot of live-pattern-coding contexts, you’d want event patterns (Pdef) to sync to the beat – not every context, though, which is why it’s globally configurable.

hjh

Thank you so much for your clarifications, which are always so kind. Of course, I should have read the help better, but this information from the help browser had misled me :

PatternProxy.defaultQuant = value
set the default quantization value for the class. (default: nil)

Obviously, I’ve confused quant as a method for pattern and quant as a play argument. My understanding of SC keeps expanding ! Thank you again !

vrc

(But also, there’s PatternProxy.defaultQuant for Pdefn style, and EventPatternProxy.defaultQuant for Pdef/Pbindef – two of them because their relationships to time are different.)

hjh

1 Like