desc: Simple Expression Map version: 1.6 changelog: init author: zaibuyidao, Tale website: https://forum.cockos.com/showthread.php?t=240598 about: Use JSFX-Simple Expression Map to convert Program Change message to Keyswitches. slider1:12<0,127,1{0 C-2,1 C#-2,2 D-2,3 D#-2,4 E-2,5 F-2,6 F#-2,7 G-2,8 G#-2,9 A-2,10 A#-2,11 B-2,12 C-1,13 C#-1,14 D-1,15 D#-1,16 E-1,17 F-1,18 F#-1,19 G-1,20 G#-1,21 A-1,22 A#-1,23 B-1,24 C0,25 C#0,26 D0,27 D#0,28 E0,29 F0,30 F#0,31 G0,32 G#0,33 A0,34 A#0,35 B0,36 C1,37 C#1,38 D1,39 D#1,40 E1,41 F1,42 F#1,43 G1,44 G#1,45 A1,46 A#1,47 B1,48 C2,49 C#2,50 D2,51 D#2,52 E2,53 F2,54 F#2,55 G2,56 G#2,57 A2,58 A#2,59 B2,60 C3,61 C#3,62 D3,63 D#3,64 E3,65 F3,66 F#3,67 G3,68 G#3,69 A3,70 A#3,71 B3,72 C4,73 C#4,74 D4,75 D#4,76 E4,77 F4,78 F#4,79 G4,80 G#4,81 A4,82 A#4,83 B4,84 C5,85 C#5,86 D5,87 D#5,88 E5,89 F5,90 F#5,91 G5,92 G#5,93 A5,94 A#5,95 B5,96 C6,97 C#6,98 D6,99 D#6,100 E6,101 F6,102 F#6,103 G6,104 G#6,105 A6,106 A#6,107 B6,108 C7,109 C#7,110 D7,111 D#7,112 E7,113 F7,114 F#7,115 G7,116 G#7,117 A7,118 A#7,119 B7,120 C8,121 C#8,122 D8,123 D#8,124 E8,125 F8,126 F#8,127 G8}>keyswitch slider2:96<0,127,1>Velocity slider3:300<0,1000,1>Delay (ms) slider4:0<0,1,1{Staccato,Legato}>Mode in_pin:none out_pin:none @init cc = $xb0; pc = $xc0; note_on = $x90; note_off = $x80; head = tail = buf = 0; // delay note off queue program = -1; @slider delay = floor(slider3 / 1000 * srate + 0.5); @block while (midirecv(offset, msg1, msg2, msg3)) ( status = msg1 & $xf0; channel = msg1 & $x0f; note = msg2; velocity = msg3; status == cc && (msg2 == 0 || msg2 == 32) ? ( bank_lsb = msg3; bank_lsb == 0 ? ( bank_lsb = 96; ); slider2 = bank_lsb; status = 0; // don't passthrough ); status == pc ? ( // mode b program >= 0 ? midisend(offset, note_off + channel, program, 0); program = msg2; slider1 = msg2; midisend(offset, note_on + channel, program, bank_lsb); // mode a slider4 == 0 ? ( // delay note off tail[0] = offset + delay; tail[1] = note_off + channel; tail[2] = program; tail[3] = 0; tail += 4; program = -1; ); status = 0; // don't passthrough ); status > 0 ? midisend(offset, msg1, msg2, msg3); // passthrough other events ); // send any delayed events while (head < tail && head[0] < samplesblock) ( offset = head[0]; msg1 = head[1]; msg2 = head[2]; msg3 = head[3]; midisend(offset, msg1, msg2, msg3); head += 4; ); // decrement offset of remaining delayed events ptr = head; while (ptr < tail) ( offset = ptr[0]; offset -= samplesblock; ptr[0] = offset; ptr += 4; ); // if queue is empty then rewind head > buf && !(head < tail) ? head = tail = buf;