I’ve been trying to work out a basic last-note-priority legato voicing setup, and wondered if someone could take a moment to check this chunk of code makes some kind of sense…
(
var counter = 0;
var notes = Array.fill(128, {-1});
var voicer = { arg gate, note;
var previousnote,
result = Dictionary[\note -> 0, \gate -> false, \slide -> 0];
// Find array index containing highest value (most recent note)
var highestval = {
var tmp = -1;
notes.do({ arg item, i;
if(item > tmp, {tmp = i});
});
tmp;
};
if( gate === 1, {
// Note-on. We need to know if there is already one of more notes playing
// Gate is always going to be high on a note-on
result[\gate] = 1;
// Always set note to incoming note no.
result[\note] = note;
// Now we need to determine if the incoming note is legato
// Get previous note index
// This corresponds to the array index containing the highest value in the notes array
previousnote = highestval.value();
// Highest note index will be -1 if no other notes are playing
if( previousnote === -1, {
// Set gate slide low
result[\slide] = 0;
}, {
// Else this is a legato note, hold gate high and set slide high
result[\slide] = 1;
});
// Increment note-counter
counter = counter + 1;
// Set note-counter value at index note-number in notes array
notes[note] = counter;
}, {
// Note-off. We need to find if other notes are still being held here, too
// Unset just-released note in notes array
notes[note] = -1;
// Get previous note
previousnote = highestval.value();
// Highest note index will be -1 if no other notes are held
if( previousnote === -1, {
// Set gate and slide low
result[\gate] = 0;
result[\slide] = 0;
// Keep note at previous value to prevent weirdness on release
result[\note] = note;
}, {
// Else this is a legato note, hold gate high and set slide high
result[\gate] = 1;
result[\slide] = 1;
// Slide to next most recent note
result[\note] = previousnote;
});
});
result.postln;
};
// MIDI setup
MIDIClient.init;
MIDIIn.connectAll;
MIDIdef.noteOn(\noteon, { |vel, num|
voicer.value(1, num);
});
MIDIdef.noteOff(\noteoff, { |vel, num|
voicer.value(0, num);
});
)
I’d love to know if there’s a better way to do it. Keeping a 128-element array seems a bit OTT, and maybe some kind of ring-buffer type setup with a much shorter array would make more sense. I’m not sure how I’d approach that, however.
Also, a more basic SCLang question: is it possible to declare persistent variables within a function?
I feel it would be neater to tuck my notes array and counter inside the function declaration, but their state doesn’t seem to persist between calls to the function, if I do that.
I realise this isn’t how functions work in traditional functional programming, but since “everything’s an object” in SC, I thought maybe there was some way to make functions work in a more “object-ey” way.
Any/all comment appreciated.