Code: Select all
TYPE tTransp = ARRAY OF integer;
VAR transpositions : ARRAY OF tTransp;
// parameters declaration
var input : Tparameter; // midi input
var output : Tparameter; // midi output
var key1 : Tparameter; // output notes from keyboard 1
var key2 : Tparameter; // output notes from keyboard 2
var exp : Tparameter; // send out a volume control signal
var out1on : Tparameter; // enable output 1
var out2on : Tparameter; // enable output 2
var disable : Tparameter; // boolean control out for disabling VST if no keyboard is controlling it
var semi : TParameter; // transpose by semi-tone
var octave : TParameter; // transpose by octave
var split : Tparameter; // pitch below or above which notes are not sent
var upper : Tparameter; // send pitches above the split if on. otherwise send pitches below.
var outCH : Tparameter; // rechannelize input. Value of 0 leaves input channel unchanged
var exp1ch : integer;
var exp1cc : integer;
var exp2ch : integer;
var exp2cc : integer;
var exp1val : single;
var exp2val : single;
var outputCH : integer;
var bytecount : integer;
var midiLen : integer;
var midi : TMidi;
var transpose : integer;
var splitVal : integer;
var upperVal : integer;
var key1Val : integer;
var key2Val : integer;
var key1ch : integer;
var key2ch : integer;
var i : integer;
var channel : integer;
var noteCount : integer;
var disabled : boolean;
// initialisation
PROCEDURE init;
BEGIN
output := CreateParam('MIDIout',ptMidi); SetIsInput(Output,false);
key1 := CreateParam('key1', ptSwitch); SetIsOutput(key1,false);
key2 := CreateParam('key2', ptSwitch); SetIsOutput(key2,false);
split := CreateParam('split',ptMidiNoteFader); SetIsOutput(split,false);
upper := CreateParam('upper',ptSwitch); SetIsOutput(upper,false);
exp := CreateParam('expression',ptDataField); SetIsInput(exp,false);
out1on := CreateParam('out1 enable',ptDataField); SetIsInput(out1on,false);
out2on := CreateParam('out2 enable',ptDataField); SetIsInput(out2on,false);
disable := CreateParam('vstBypass',ptDataField); SetIsInput(disable,false);
input := CreateParam('MIDIin',ptMidi); SetIsOutput(Input,false);
semi := CreateParam('semi',ptDataField); SetIsOutput(semi,false);
octave := CreateParam('8va',ptDataField); SetIsOutput(octave,false);
outCH := CreateParam('outCH', ptDataField); SetIsOutput(outCH,false);
key1ch := 1;
key2ch := 2;
exp1ch := 1;
exp1cc := 4;
exp2ch := 2;
exp2cc := 3;
noteCount := 0;
SetArrayLength(transpositions, 2);
FOR i := 0 TO 1 DO // we are going to ignore midi data on any but the 2 keyboard channels...
SetArrayLength(transpositions[i], 128);
//default values and formats
SetDefaultValue(upper,1);
SetDefaultValue(key1,1);
SetDefaultValue(key2,1);
SetFormat(split,'%.0f');
SetMin(split,1);
SetMax(split,127);
SetDefaultValue(split,1);
SetFormat(semi,'%.0f');
SetMin(semi,-7);
SetMax(semi,7);
SetDefaultValue(semi,0);
SetFormat(octave,'%.0f');
SetMin(octave,-4);
SetMax(octave,4);
SetDefaultValue(octave,0);
SetDefaultValue(outCH,1);
end;
PROCEDURE CreateOut(ch, msg, data1, data2 : integer);
BEGIN
midi.msg := byte(msg);
midi.data1 := byte(data1);
midi.data2 := byte(data2);
midi.channel := byte(ch);
SetMidiArrayValue(output, bytecount, midi);
END; // CreateOut
PROCEDURE processNoteOns;
BEGIN
//writeln('in noteon loop');
IF (((channel = key1ch) AND (key1Val = 1)) OR ((channel = key2ch) AND (key2Val = 1)))
AND (((midi.data1 >= splitVal) AND (upperVal = 1)) OR ((midi.data1 < splitVal) AND (upperVal = 0)))
THEN BEGIN
transpositions[channel - 1][midi.data1] := transpose; // only works if keyboard ch's are 1 and 2....
midi.data1 := midi.data1 + transpose;
midi.channel := outputCH;
SetMidiArrayValue(output, bytecount, midi);
//noteCount := noteCount + 1; // increase count of held notes
END;
END; //process Noteons
PROCEDURE processNoteOffs;
BEGIN
midi.data1 := midi.data1 + transpositions[channel - 1][midi.data1]; // Retrieve stored transpose and add to NoteOff
midi.channel := outputCH;
SetMidiArrayValue(output, bytecount, midi);
//noteCount := noteCount - 1; // decrease count of held notes
writeln('in notes off = ' + intToStr(noteCount));
END; //processNoteoffs
PROCEDURE processSustain;
BEGIN
IF (midi.data2 < 64) THEN //send sus up on all instruments, selected or not...
BEGIN
midi.channel := outputCH;
SetMidiArrayValue(output, bytecount, midi);
END
ELSE IF (((channel = 1) AND (key1Val = 1)) OR ((channel = 2) AND (key2Val = 1))) THEN
BEGIN
IF (midi.data2 >= 64) THEN //send sus down only on selected instruments
BEGIN
midi.channel := outputCH;
SetMidiArrayValue(output, bytecount, midi);
END;
END;
END; // process sustain
PROCEDURE disableVST; // not used yet
BEGIN
disabled := ( (key1val = 0) AND (key2val = 0));
// IF (disabled) THEN
// wait until all notes are off before doing this--how??
// and don't undo it when notes are back on!
// IF (noteCount = 0) THEN
// BEGIN
// CreateOut(outputCH, 208, 0, 0); //reset aftertouch
// CreateOut(outputCH, 224, 0, 64); //reset pitchbend
// CreateOut(outputCH, 176, 1, 0); //reset mod wheel
// setValue(disable, 1);
// setValue(out1on, 0);
// setValue(out2on, 0);
// END
// ELSE BEGIN
// setValue(disable, 0);
// END
// ELSE
setValue(disable, 0);
END; // disable vst
PROCEDURE processExpression1;
BEGIN
exp1val := (midi.data2)/128;
setValue(exp, exp1val);
END;
PROCEDURE processExpression2;
BEGIN
exp2val := (midi.data2)/128;
setValue(exp, exp2Val);
END;
PROCEDURE processControllers;
BEGIN
SetMidiArrayValue(output, bytecount, midi);
END;
// main
BEGIN
// set variables from inputs
transpose := trunc(GetValue(semi) + ((getValue(octave) * 12)));
splitVal := trunc(getValue(split));
upperVal := trunc(getValue(upper));
key1Val := trunc(getValue(key1));
key2Val := trunc(getValue(key2));
outputCh := trunc(getValue(outCH));
// disable the VST if nothing is controlling it
disableVST;
setValue(out1on, key1val);
setValue(out2on, key2val);
midiLen := GetLength(input);
IF (midiLen > 0) THEN
BEGIN
SetLength(output, midiLen);
// process midi
FOR bytecount := 0 TO (midiLen - 1) DO
BEGIN
GetMidiArrayValue(input, bytecount, midi);
channel := midi.channel;
IF ((midi.msg = 144) AND (midi.data2 > 0))
THEN BEGIN // Noteon
processNoteons;
END
ELSE IF ((midi.msg = 128)
OR ((midi.msg = 144) AND (midi.data2 = 0))) THEN
BEGIN // NoteOff
processNoteoffs;
END
ELSE IF (midi.msg = 176) AND (midi.data1 = 64) THEN
BEGIN
processSustain;
END
ELSE IF (midi.msg = 176) AND (midi.channel = exp1ch) AND (midi.data1 = exp1cc) THEN
BEGIN
processExpression1;
END
ELSE IF (midi.msg = 176) AND (midi.channel = exp2ch) AND (midi.data1 = exp2cc) THEN
BEGIN
processExpression2;
END
ELSE IF (midi.msg = 176) THEN
BEGIN
processControllers;
END;
END;
END
// no midi in this block....
ELSE BEGIN
SetLength(output, 0);
END;
END.-e
