desc:MIDI map to key
slider1:0<0,11,1{C,C#,D,D#,E,F,F#,G,G#,A,A#,B}>key
slider3:0<0,127,1>note range low (passthru other notes)
slider4:127<0,127,1>note range high (passthru other notes)
@init 
// maps a note to its nearest in-Cmaj note
tab2=16;
tab2[0]=0;
tab2[1]=2;
tab2[2]=2;
tab2[3]=4;
tab2[4]=4;
tab2[5]=5;
tab2[6]=5;
tab2[7]=7;
tab2[8]=7;
tab2[9]=9;
tab2[10]=11;
tab2[11]=11;

notetab=512;
memset(notetab,0,128);

@slider
key = slider1|0;

@block
while (
midirecv(ts,msg1,msg23) ? 
(
  m=msg1&240;
  note=msg23&127;
  (m == 8*16 || m==9*16) && note >= slider3 && note <= slider4 ? 
  (
    oldnote=note;
    note += 12-key;

    noteidx=note%12;
    octavebase=note-noteidx;
    note=octavebase + tab2[noteidx];
   
    note-=12-key;
    (m == 9*16 && msg23>=256) ? 
    (
      vel=(msg23/256)|0;
      note >= 0 && note < 128 ? (
        notetab[note]|=2^(12+ note-oldnote);
        midisend(ts,9*16,note+vel*256); // send note on
      );
    ) : (m == 8*16 || m == 9*16) ? (
      note >= 0 && note < 128 ? (
        a=notetab[note];
        mask = 2^(12+note-oldnote);
        (a&mask) ? ( notetab[note] = (a-=mask));
        !a ? midisend(ts,8*16,note); // send note off  
      );
    );
  ) : 
  (
    midisend(ts,msg1,msg23);
  );
  bla=1;
);
);
@sample
