/*
BSmart General MIDI Controller
By Bryan Smart (bryansmart@bryansmart.com)
Last mod: 5/22/2014

This plug-in presents common MIDI controllers as automatable parameters.

An advantage over ReaControl is that this plug-in doesn't transmit its current values when a project is re-opened. This means that the plug-in's state won't match what is necessarily heard at project load, but it won't corrupt the settings of any softsynths in the chain, either.

History

5/22/2014
* Most GM synths preserve channel state across patch changes, so the plug-in no longer resets state/UI on a patch change.
* Renamed Program slider to Patch. Patch is the more familiar MIDI terminology for an instrument voice program.
* Renamed "Pan Position" slider to "Stereo Pan Position Slider" for greater clarity.
* Annotated Stereo Pan Position slider values for greater clarity.
* Changed the text of the plug-in description.
* Commented the code, now that it is stable.

*/

desc: BSmart General MIDI Controller
in_pin:none
out_pin:none
ext_noinit=1;

// Declare user interface widgets.

slider1:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>MIDI channel

slider2:0<0,127,1{0 XG Melodic Instruments,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120 GM Rhythm,121 GM/GS Melodic Instruments,122,123,124,125,126 XG Sound Effects,127 XG Rhythm}>Bank MSB
slider3:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Bank LSB
slider4:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Patch

slider5:100<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Volume
slider6:64<0,127,1{0 (hard-left),1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 (center),65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 (hard-right)}>Stereo Pan Position
slider7:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Reverb Level
slider8:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Chorus Level

slider9:64<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Filter Cut-Off Frequency
slider10:64<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Filter Resonance

slider11:64<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Attack Time
slider12:64<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Decay Time
slider13:64<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Release Time

slider14:1<0,1,1{Monophonic,Polyphonic}>Polyphony
slider15:0<0,1,1{Off,On}>Portamento
slider16:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Portamento Time

slider63:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Custom CC Number
slider64:0<0,127,1{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>Custom CC Value

@slider

// Handle a change to a user interface widget.

// Before starting, check to see if Reaper has reset the plug-in's variables.

setup_prev == 0 ? (
// Sliders are always preserved, so re-load prev values from those.
prev_msb = slider2;
prev_lsb = slider3;
prev_pgm = slider4;

prev_volume = slider5;
prev_pan = slider6;
prev_reverb = slider7;
prev_chorus = slider8;

prev_cutoff = slider9;
prev_resonance = slider10;

prev_attack = slider11;
prev_decay = slider12;
prev_release = slider13;

prev_poly = slider14;
prev_Portamento = slider15;
prev_portatime = slider16;

prev_custom_cc = slider63;
prev_custom_value = slider64;

setup_prev = 1;
);

// If the plug-in has been setup, then we can process changes in the UI.
setup_prev == 1 ? (
// First, load current parameter values from the UI widgets.
chan = slider1;

msb = slider2;
lsb = slider3;
pgm = slider4;

volume = slider5;
pan = slider6;
reverb = slider7;
chorus = slider8;

cutoff = slider9;
resonance = slider10;

attack = slider11;
decay = slider12;
release = slider13;

poly = slider14;
Portamento = slider15;
portatime = slider16;

custom_cc = slider63;
custom_value = slider64;

// Second, determine if any UI widgets have been changed since the last time we checked them.

msb != prev_msb || lsb != prev_lsb ? (
send_bank = 1;
send_pgm = 1;
);

pgm != prev_pgm ? (
send_pgm = 1;
);

volume != prev_volume ? send_volume = 1;
pan != prev_pan ? send_pan = 1;
reverb != prev_reverb ? send_reverb = 1;
chorus != prev_chorus ? send_chorus = 1;

cutoff != prev_cutoff ? send_cutoff = 1;
resonance != prev_resonance ? send_resonance = 1;

attack != prev_attack ? send_attack = 1;
decay != prev_decay ? send_decay = 1;
release != prev_release ? send_release = 1;

poly != prev_poly ? send_poly = 1;
portamento != prev_portamento ? send_portamento = 1;
portatime != prev_portatime ? send_portatime = 1;

custom_value != prev_custom_value ? send_custom_value = 1;

// Finally, save the current parameters, so that we can check them next time for changes.

prev_msb = msb;
prev_lsb = lsb;
prev_pgm = pgm;

prev_volume = volume;
prev_pan = pan;
prev_reverb = reverb;
prev_chorus = chorus;

prev_cutoff = cutoff;
prev_resonance = resonance;

prev_attack = attack;
prev_decay = decay;
prev_release = release;

prev_poly = poly;
prev_portamento = portamento;
prev_portatime = portatime;

prev_custom_value = custom_value;
);

@block
// This plug-in doesnt modify MIDI events, so forward all buffered events to the next plug-in in the chain.
while (
midirecv(ts,msg1,msg23) ? midisend(ts,msg1,msg23);
); 

// Test each send flag to determine if its message needs to be sent.

send_bank ? (
midisend(0,$xB0 + chan,(msb * 256)|0);
midisend(0,$xB0 + chan,(32 +(lsb * 256))|0);
send_bank = 0;
);

send_pgm ? (
midisend(0,$xC0 + chan,pgm|0);
send_pgm = 0;
);

send_volume ? (
midisend(0,$xB0 + chan,(7 +(volume * 256))|0);
send_volume = 0;
);

send_pan ? (
midisend(0,$xB0 + chan,(10 +(pan * 256))|0);
send_pan = 0;
);

send_reverb ? (
midisend(0,$xB0 + chan,($x5B +(reverb * 256))|0);
send_reverb = 0;
);

send_chorus ? (
midisend(0,$xB0 + chan,($x5D +(chorus * 256))|0);
send_chorus = 0;
);

send_cutoff ? (
midisend(0,$xB0 + chan,($x4A +(cutoff * 256))|0);
send_cutoff = 0;
);

send_resonance ? (
midisend(0,$xB0 + chan,($x47 +(resonance * 256))|0);
send_resonance = 0;
);

send_attack ? (
midisend(0,$xB0 + chan,($x49 +(attack * 256))|0);
send_attack = 0;
);

send_decay ? (
midisend(0,$xB0 + chan,($x4B +(decay * 256))|0);
send_decay = 0;
);

send_release ? (
midisend(0,$xB0 + chan,($x48 +(release * 256))|0);
send_release = 0;
);

send_poly ? (
poly == 0 ? midisend(0,$xB0 + chan,$x7E | 0);
poly == 1 ? midisend(0,$xB0 + chan,$x7F | 0);
send_poly = 0;
);

send_portamento ? (
portamento == 0 ? midisend(0,$xB0 + chan,$x41 | 0);
portamento == 1 ? midisend(0,$xB0 + chan,($x41 +(127 * 256))|0);
send_portamento = 0;
);

send_portatime ? (
midisend(0,$xB0 + chan,(5 +(portatime * 256))|0);
send_portatime = 0;
);

send_custom_value ? (
midisend(0,$xB0 + chan,(custom_cc +(custom_value * 256))|0);
send_custom_value = 0;
);

