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