MIDIdefs to store arrays

Hello all,
I’m writing a bunch of MIDIdefs to have a small midi controller transform arrays on the fly.
i bet my approach is pretty cumbersome but i wanted to start small :slight_smile:

one of the things i want to do is to be able to store an array for later recall. for which i thought i could use the same logic as this:

~a = [1, 2, 3]; // original array
~ab = ~a; // make a copy, new name
~ab; // test, same contents as ~a
~a = [1, 2, 3, 100, 800] // change ~a
~ab // still keeps old contents. success.

However, when i try with the MIDIdefs something goes wrong as the copy array, called ~bbb, does not seem to hold the values, as if they were being updated or something.

Here are 3 MIDIdefs: first one modifies the current array which serves as the note sequence, and the other 2 are supposed to do the storing and recalling of the array.

(
MIDIdef.cc(\cc5, {arg key, ccNum;
~position = rrand(0, ~nnn.size-1); ~da_one = ~nnn.at(~position); ~nnn.put(~position, (40..80).choose); Pdefn(\notes, Pseq(~nnn, inf));
~nnn.postln;
}, 5).permanent_(true);
);

(
MIDIdef.cc(\cc6, {arg key, ccNum;
~bbb = ~nnn; // saves current state of ~nnn by copying to a new array called ~bbb
	“SAVED!”.postln;
	~bbb.postln;
}, 6).permanent_(true);
);

(
MIDIdef.cc(\cc7, {arg key, ccNum;
Pdefn(\notes, Pseq(~bbb, inf)); // go back!
	“revert!”.postln;
	~bbb.postln;
}, 7).permanent_(true);
);

What am i missing?
Many thanks!

This is not making a copy, it’s just referencing the same array as ~nnn. To make a copy, you need to explicitly do ~nnn.copy or ~nnn.deepCopy.

Be careful using an array in Pseq that might get modified while the Pseq is running. This isn’t supported, and probably will not behave correctly. Another good place to make a .copy().

1 Like

Here’s a design pattern I use for swapping a fixed-size sequence during playback, without losing my place in the sequence (adapted a bit to your “save/recall” behavior):

(
~sequence = Array.fill(16, { [38, 43, 45].choose });
~oldSequence = ~sequence.copy;

// Store your sequence in a Pdefn
Pdefn(\sequence, ~sequence.copy);

// A pattern implementation of sequence.wrapAt(n) 
Pdefn(\notes, Pbinop(
	'wrapAt', 
	Pdefn(\sequence),
	Pseries()
));

// A Pbind to play the notes
Pdef(\player, Pbind(
	\tempo, 1.5,
	\dur, Prand([1, 1, 1, Rest(1)], inf) / 4,
	\legato, 2,
	\midinote, Pdefn(\notes)
)).play;
)

(
// Change one note
~oldSequence = ~sequence.copy;
~sequence[4] = 49;
Pdefn(\sequence, ~sequence.copy);
)

(
// Go back
~sequence = ~oldSequence;
Pdefn(\sequence, ~sequence.copy);
)

In particular, you don’t NEED to wrap ~sequence in Pdefn(\sequence) - but, this gives you the ability to do things like, for example, have a sequence-of-sequences:

Pdefn(\sequence, Pseq([
   ~sequence.copy,
   ~sequence.copy + 12
], inf).stutter(6));

Or quantize the sequence changes to every 2 beats:

Pdefn(\sequence, Pseq([
	~sequence.copy,
], inf).stutter(6)).quant_(2);

The very simplest expression (if you don’t want the extra layer of Pdefn wrapping) is:

Pdefn(\notes, Pfunc({ |index| ~sequence.wrapAt(index) }) <> Pseries())
4 Likes

Thanks for those tips and the whole workflow suggestion.
That all makes sense.
Massive face palm on the .copy bit too…!