Recording values from Pbind

Hi there -

I have a Pbind randomly spouting off random values between 0 and 6.

Pbindef(\f,\degree, Prand((0..6), inf), \dur, 0.1).play;

I would like to find a way to keep track of these values and store a count (let’s say the most recent 100 items) in an array.

How might I do this?

Any function you put in the \finish key is called just before the Event is played (this is usually for making final modifications to the event before playback, as the name implies). \callback is called just after the Event is played. So, you’re best off doing your recording in the \callback function. FWIW the function is called with the current event as the environment - nice because you can use ~environmentVariables to access Event keys, but it also makes it harder to refer to an array from the outside. But, here’s simple example:

(
~degreeHistory = List(); // use a list so you can modify it without making a copy

Pbind(
    \degree, Prand((0..6), inf),
    \degreeHistory, ~degreeHistory, // add it to your event so you can access inside \callback
    \callback, {
         ~degreeHistory.add(~degree)
    }
)
)

A slighly more well-factored version -

  1. Split your “recorder” Pbind into a separate object and compose with your pattern, to make things more reusable. One “base” history recorder, and one version for each event stream you want to record.
  2. Use the environment of the Pdef to store things like the event list - this is the easiest way to keep track of objects specific to a Pdef.
  3. Combine your \callback function with any \callback that was set previously (in the naive case above, you’ll overwrite whatever \callback was there - this is fine for most cases, but can occasionally bite you, so I like to do it this was as a matter of best practice)

(
// This expects two keys to be defined: ~history (the list) and ~recordKey (which key to record)
Pdef(\keyRecorder, Pbind(
	\callback, Pfunc({
		|event|
		event[\callback].addFunc({ // combine your record func with any previous callback that was there (it's okay if its nil)
			~history.add(currentEnvironment[~recordKey])
		}).postln;
	})
));

// Now you can construct different kinds of recorders
Pdef(\degreeRecorder, Pdef(\keyRecorder)).set(\recordKey, \degree, \history, List());
Pdef(\legatoRecorder, Pdef(\keyRecorder)).set(\recordKey, \legato, \history, List());
Pdef(\durRecorder, Pdef(\keyRecorder)).set(\recordKey, \dur, \history, List());

// <> compose it with your pbind.
Pdef(\somePattern, Pdef(\degreeRecorder) <> Pbind(
	\dur, 1/8,
	\scale, Scale.hexSus,
	\octave, 4,
	\legato, Prand([0.7, 1, 2], inf),
	\degree, Ptuple([
		Pseq([0, 0, -1, -1, 0, 0, 2, 3], inf),
		Pseq([5, 4, -2], inf).stutter(6),
	], inf)
)).play;
)

Pdef(\degreeRecorder).get(\history).postln;
5 Likes

Hi @scztt - and thanks for the examples. I’m not sure I entirely understand, though.

Both of these solutions seem much more complex than what I initially bargained for, which likely means I don’t understand something about Events very well.

The first example seems to work well, at first. Playing the pattern, the array ~degreeHistory seems to keep track of the notes. If I try to reset ~degreeHistory, though, using something like ~degreeHistory = List(); - I lose the connection to the Pbind, until restarting everything.

The second example seems more complex, so I will need to spend a little more time with it… but just to clarify, there’s no simple way to dump a certain number of keyed event items in an externally accessible array? My hope, ultimately, is to do something a little bit more durational - involving storage and retrieval of these moments - and having it bound to Pdefs is a little intimidating still…

Thanks again for the help!

Perhaps try List.clear?

The difference is between deleting all the items in the list and replacing the list altogether.

l = List.new; // store
r = { true.while({ l.add(10.rand); l.postln; 1.wait }) }.fork // add to store every second
l.clear // reset store
r.stop // stop writer

The PS class, in the miSCellaneous_lib quark, is another option:

(
Pbind(
    \degree, ~degreeHistory = PS(Prand((0..6), inf), bufSize: 10), // stores the last 10 values
    \dur, 0.1
).play;
)
// let it play for a second, then:
~degreeHistory.lastValues;