overlays-personal/pkgs/reaper/jsfx/midi/AS_Midi_monoizer

119 lines
3.7 KiB
Plaintext

desc:Midi Monoizer
/* Midi Monoizer (c)2019 by Andrew Shakinovsky andrew@afrittemple.com
I welcome comments or suggestions.
Description:
Insert this before a VSTi in the chain. It will prevent multiple midi notes from
sounding at the same time. When a note is playing and another note is received,
a note-off is sent for the first note before(*) the new note is sent. This is akin
to typical monosynths when you are holding a key and then press and release another
key: the first key plays, then the second, and when you release the second, the first
key will play again. A lot of VSTi's behave in this way, but there are some that do
not, and that is where this becomes helpful.
(*) will be sent after the note on depending on the legato slider. If the legato slider
is no zero, the note off will be delayed by that many samples to allow the synth to
treat it as legato playing
*/
slider1:0<0,256>Legato Delay Samples
@init
stackptr=-1;
// array offsetting (there is only one local mem space)
stacknote=0;
stackvel=1024;
stackchan=2048;
nno_Off=0;
nno_Chan=0;
nno_Note=0;
@block
// play note off, applying legator delay
function note_off(pos, chan, note) (
// make sure it fits in this block given the delay
pos+slider1 < samplesblock ? (
midisend(pos+slider1,0x80 | chan, note);
) : (
// doesn't belong in this block, send it in the next block
nno_Off = 1 + ((pos+slider1) - samplesblock);
nno_Chan=chan;
nno_Note=note;
);
);
// do we have a note off to send?
nno_Off ? (
midisend(nno_Off,0x80 | nno_Chan, nno_Note);
nno_Off=0;
);
while (
// if we receive a message
midirecv(ofs, msg1, msg23) ? (
status = msg1 & 0xF0; // hi 4 bits
chan = msg1 & 0x0F; // low 4 bits
note = msg23 & 0xFF; //low order byte is note
velocity = msg23 >> 8; // high order byte is velocity
// if its a Note On
status == 0x90 && velocity ? (
// if we have items on stack
stackptr > -1 ? (
note_off(ofs, stackchan[stackptr], stacknote[stackptr]);
);
// push curent new note to stack
stackptr+=1;
stacknote[stackptr]=note;
stackvel[stackptr]=velocity;
stackchan[stackptr]=chan;
);
// if its a Note Off
status == 0x80 || (status == 0x90 && !velocity) ? (
// if the note doesn't match top of stack, remove it below in the stack
// shifting everything down (we don't care about it just get rid of it)
note != stacknote[stackptr] ? (
i=0;
rp=0;
while(i <= stackptr) (
stacknote[i]==note ? ( // if it matches the note, move our read position
rp += 1;
);
// copy source to target
stacknote[i] = stacknote[rp];
stackvel[i] = stackvel[rp];
stackchan[i] = stackchan[rp];
i += 1;
rp += 1;
);
// set new top of stack
stackptr-= (rp-i);
) : ( // otherwise, note matches top of stack ...
stackptr > -1 ? (
// pop stack
stackptr-=1;
// send note on for tos (if any)
midisend(ofs,0x90 | stackchan[stackptr],
(stackvel[stackptr] << 8) | stacknote[stackptr]);
);
);
):
// All Notes Off
status == 0xB0 && cc == 123 & n ? (
stackptr=-1; // discard all
);
// send original incoming message, but if it's a note off, apply delay
msg1 ? (
status == 0x80 || (status == 0x90 && !velocity) ? (
note_off(ofs, chan, note);
):(
midisend(ofs, msg1, msg23);
);
);
); // if we recv a msg (otherwise the while will exit)
); // while