Posted: 07 Feb 2016, 01:38
I'm using this script to do my midi input processing. It's working great (although I haven't tested all the features yet) but it's giving me stuck midi notes. It's missing both note0ns and noteoffs with a good bit of regularity.
Just wondering if one of the script gurus can look it over, and make sure I'm putting the appropriate parts of it in process() and callback() or if there are any other red flags that would cause concern.
Thanks in advance for any thoughts.
[c]/////////////////////////////////////////////////////////////////////////////
// TO DO:
// Disable transpose for drum channel, but send out midi CC4 instead
// We must account for two keyboards--the bass split should only affect
// a keyboard that is assigned to bass. How do we do that????
//
//
/////////////////////////////////////////////////////////////////////////////
VAR midiIN, clearIN, midiOUT, transposeIN, bassOn1IN,bassOn2IN,orgRechIN : tParameter;
var splitIN : Tparameter;
var rhBassIN: Tparameter;
var handsIN: Tparameter;
var isBassIN : Tparameter;
var isDrumIN: Tparameter;
VAR transpositions : ARRAY OF integer;
VAR noteONs : ARRAY OF boolean;
VAR midi : tMidi;
VAR midiCount, transpose, i , orgRech : integer;
VAR clearing, newTranspose: boolean;
var splitval: integer;
var rhBass,hands,isBass, bassOn1, bassOn2, isDrum: boolean;
PROCEDURE Init;
BEGIN
midiIN := CreateParam('midi in', ptMidi); SetIsOutput(midiIN, FALSE);
clearIN := CreateParam('clear notes', ptButton); SetIsOutput(clearIN, FALSE);
transposeIN := CreateParam('transpose', ptDataFader); SetIsOutput(transposeIN, FALSE);
splitIN := CreateParam('split',ptMidiNoteFader ); SetIsOutPut(splitIN,false);
handsIN := CreateParam('hands on',ptSwitch); SetIsOutput(handsIN, false);
isBassIN := CreateParam('is bass ch',ptSwitch); SetIsOutput(isBassIN, false);
bassOn1IN := CreateParam('key1 bass',ptSwitch); SetIsOutput(bassOn1IN, false);
bassOn2IN := CreateParam('key2 bass',ptSwitch); SetIsOutput(bassOn2IN, false);
isDrumIN := CreateParam('is drum ch',ptSwitch); SetIsOutput(isDrumIN, false);
orgRechIN := CreateParam('org rech',ptDataFader); SetIsOutput(orgRechIN, false);
rhBassIN := CreateParam('RH bass',ptSwitch); SetIsOutput(rhBassIN, false);
midiOUT := CreateParam('midi out', ptMidi); SetIsInput(midiOUT, FALSE);
SetFormat(splitIN,'%.0f'); SetMin(splitIN,2); SetMax(splitIN,126); SetDefaultValue(splitIN,62);
SetFormat(transposeIN, '%.0f'); SetMin(transposeIN, -24); SetMax(transposeIN, 24);
SetMin(orgRechIN, 0); SetMax(orgRechIN, 2);
SetArrayLength(transpositions, 128);
SetArrayLength(noteONs, 128);
for i := 0 to 127 DO BEGIN
transpositions := 0;
noteOns := FALSE;
END;
clearing := FALSE;
newTranspose := FALSE;
END; // Init
procedure makeHands;
var note : integer;
begin
if hands then begin
note := midi.data1;
if note > 60 then midi.data1 := note - 12
else midi.data1 := note + 12;
end;
end;
procedure callback(n: integer);
BEGIN
IF (n = clearIN) and (getValue(clearIN) > 0) THEN clearing := TRUE
ELSE IF (n = transposeIN) THEN newTranspose := TRUE
ELSE IF (n = handsIN) or (n = splitIN) or (n = isBassIN) or (n = bassOn1IN) or (n = bassOn2IN) or (n = isDrumIN) or (n = rhBassIN) THEN
// if any of the split settings change, best clear existing notes!
BEGIN
splitval := round(getValue(splitIN));
rhBass := getValue(rhBassIN) > 0;
hands := getValue(handsIN) > 0;
isBass := getValue(isBassIN) > 0;
bassOn1 := getValue(bassOn1IN) > 0;
bassOn2 := getValue(bassOn2IN) > 0;
isDrum := getValue(isDrumIN) > 0;
orgRech := round(getValue(orgRechIN));
clearing := TRUE;
END;
END;
// process
procedure process;
var outCount,note,chan: integer;
var ccTrans: integer;
var newMidi: tMidi;
BEGIN
midiCount := GetLength(midiIN);
outCount := 0;
IF clearing then BEGIN
for i := 0 to 127 DO BEGIN
// send note off s
if noteONs := TRUE THEN BEGIN
midi.channel := 1; midi.msg := 128; midi.data1 := i; midi.data2 := 0;
setMidiArrayValue(midiOUT, outCount, midi);
outCount := outCount + 1;
noteONs := FALSE;
END;
END;
// send sus pedal off!
midi.channel := 1; midi.msg := 176; midi.data1 := 64; midi.data2 := 0;
setMidiArrayValue(midiOUT, outCount, midi);
outCount := outCount + 1;
setLength(midiOUT, outCount);
clearing := FALSE;
END
ELSE IF newTranspose then BEGIN
if isDrum then begin
transpose := round(getValue(transposeIN));
// create midi cc4 out for drum tuning
ccTrans := (round((transpose * 1.76) + 64));
//strace('____________CC TRANS = ' + intToStr(ccTrans));
newMidi.msg := 176; newMidi.channel := 1; newMidi.data1 := 4; newMidi.data2 := round(ccTrans);
SetMidiArrayValue(midiOUT, outCount, newMidi);
outCount := 1;
setLength(midiOUT, outCount);
end;
newTranspose := FALSE;
END
ELSE IF (midiCount > 0) THEN BEGIN
IF isDrum then transpose := 0 else transpose := round(getValue(transposeIN));
FOR i := 0 TO (midiCount - 1) DO BEGIN
GetMidiArrayValue(midiIN, i, midi);
note := midi.data1;
chan := midi.channel;
IF ((chan = 1) and (not bassOn1)) OR ((chan = 2) and not (bassOn2)) OR //ALLOW NOTES ABOVE AND BELOW IF KEYB IS NOT SUBJECT TO BASS
(((note >= splitVal) AND ((not isBass) OR (isbass AND rhBass))) //ABOVE SPLIT OUT
OR ((note < splitVal)) AND ((not isBass) OR (isbass AND not rhBass))) THEN BEGIN //BELOW SPLIT OUT
if (orgRech > 0) then midi.channel := orgRech; //if it's 0 leave ch unchanged
IF ((midi.msg = 144) AND (midi.data2 > 0)) THEN BEGIN // NoteOn
if hands then makeHands;
transpositions[midi.data1] := transpose; // Store transpose value used for NoteOn
noteOns[midi.data1] := TRUE;
midi.data1 := midi.data1 + transpose;
END
ELSE IF ( (midi.msg = 128)
OR ((midi.msg = 144) AND (midi.data2 = 0))) THEN BEGIN // NoteOff
if hands then makeHands;
if (not isDrum) then begin
midi.data1 := midi.data1 + transpositions[midi.data1]; // Retrieve stored transpose and add to NoteOff
noteOns[midi.data1] := FALSE;
end;
END;
SetMidiArrayValue(midiOUT, outcount, midi);
outCount := outCount + 1;
END;
END;
setLength(midiOUT, outCount);
END
ELSE BEGIN
SetLength(midiOUT, 0);
END;
END;
[/c]
Just wondering if one of the script gurus can look it over, and make sure I'm putting the appropriate parts of it in process() and callback() or if there are any other red flags that would cause concern.
Thanks in advance for any thoughts.
[c]/////////////////////////////////////////////////////////////////////////////
// TO DO:
// Disable transpose for drum channel, but send out midi CC4 instead
// We must account for two keyboards--the bass split should only affect
// a keyboard that is assigned to bass. How do we do that????
//
//
/////////////////////////////////////////////////////////////////////////////
VAR midiIN, clearIN, midiOUT, transposeIN, bassOn1IN,bassOn2IN,orgRechIN : tParameter;
var splitIN : Tparameter;
var rhBassIN: Tparameter;
var handsIN: Tparameter;
var isBassIN : Tparameter;
var isDrumIN: Tparameter;
VAR transpositions : ARRAY OF integer;
VAR noteONs : ARRAY OF boolean;
VAR midi : tMidi;
VAR midiCount, transpose, i , orgRech : integer;
VAR clearing, newTranspose: boolean;
var splitval: integer;
var rhBass,hands,isBass, bassOn1, bassOn2, isDrum: boolean;
PROCEDURE Init;
BEGIN
midiIN := CreateParam('midi in', ptMidi); SetIsOutput(midiIN, FALSE);
clearIN := CreateParam('clear notes', ptButton); SetIsOutput(clearIN, FALSE);
transposeIN := CreateParam('transpose', ptDataFader); SetIsOutput(transposeIN, FALSE);
splitIN := CreateParam('split',ptMidiNoteFader ); SetIsOutPut(splitIN,false);
handsIN := CreateParam('hands on',ptSwitch); SetIsOutput(handsIN, false);
isBassIN := CreateParam('is bass ch',ptSwitch); SetIsOutput(isBassIN, false);
bassOn1IN := CreateParam('key1 bass',ptSwitch); SetIsOutput(bassOn1IN, false);
bassOn2IN := CreateParam('key2 bass',ptSwitch); SetIsOutput(bassOn2IN, false);
isDrumIN := CreateParam('is drum ch',ptSwitch); SetIsOutput(isDrumIN, false);
orgRechIN := CreateParam('org rech',ptDataFader); SetIsOutput(orgRechIN, false);
rhBassIN := CreateParam('RH bass',ptSwitch); SetIsOutput(rhBassIN, false);
midiOUT := CreateParam('midi out', ptMidi); SetIsInput(midiOUT, FALSE);
SetFormat(splitIN,'%.0f'); SetMin(splitIN,2); SetMax(splitIN,126); SetDefaultValue(splitIN,62);
SetFormat(transposeIN, '%.0f'); SetMin(transposeIN, -24); SetMax(transposeIN, 24);
SetMin(orgRechIN, 0); SetMax(orgRechIN, 2);
SetArrayLength(transpositions, 128);
SetArrayLength(noteONs, 128);
for i := 0 to 127 DO BEGIN
transpositions := 0;
noteOns := FALSE;
END;
clearing := FALSE;
newTranspose := FALSE;
END; // Init
procedure makeHands;
var note : integer;
begin
if hands then begin
note := midi.data1;
if note > 60 then midi.data1 := note - 12
else midi.data1 := note + 12;
end;
end;
procedure callback(n: integer);
BEGIN
IF (n = clearIN) and (getValue(clearIN) > 0) THEN clearing := TRUE
ELSE IF (n = transposeIN) THEN newTranspose := TRUE
ELSE IF (n = handsIN) or (n = splitIN) or (n = isBassIN) or (n = bassOn1IN) or (n = bassOn2IN) or (n = isDrumIN) or (n = rhBassIN) THEN
// if any of the split settings change, best clear existing notes!
BEGIN
splitval := round(getValue(splitIN));
rhBass := getValue(rhBassIN) > 0;
hands := getValue(handsIN) > 0;
isBass := getValue(isBassIN) > 0;
bassOn1 := getValue(bassOn1IN) > 0;
bassOn2 := getValue(bassOn2IN) > 0;
isDrum := getValue(isDrumIN) > 0;
orgRech := round(getValue(orgRechIN));
clearing := TRUE;
END;
END;
// process
procedure process;
var outCount,note,chan: integer;
var ccTrans: integer;
var newMidi: tMidi;
BEGIN
midiCount := GetLength(midiIN);
outCount := 0;
IF clearing then BEGIN
for i := 0 to 127 DO BEGIN
// send note off s
if noteONs := TRUE THEN BEGIN
midi.channel := 1; midi.msg := 128; midi.data1 := i; midi.data2 := 0;
setMidiArrayValue(midiOUT, outCount, midi);
outCount := outCount + 1;
noteONs := FALSE;
END;
END;
// send sus pedal off!
midi.channel := 1; midi.msg := 176; midi.data1 := 64; midi.data2 := 0;
setMidiArrayValue(midiOUT, outCount, midi);
outCount := outCount + 1;
setLength(midiOUT, outCount);
clearing := FALSE;
END
ELSE IF newTranspose then BEGIN
if isDrum then begin
transpose := round(getValue(transposeIN));
// create midi cc4 out for drum tuning
ccTrans := (round((transpose * 1.76) + 64));
//strace('____________CC TRANS = ' + intToStr(ccTrans));
newMidi.msg := 176; newMidi.channel := 1; newMidi.data1 := 4; newMidi.data2 := round(ccTrans);
SetMidiArrayValue(midiOUT, outCount, newMidi);
outCount := 1;
setLength(midiOUT, outCount);
end;
newTranspose := FALSE;
END
ELSE IF (midiCount > 0) THEN BEGIN
IF isDrum then transpose := 0 else transpose := round(getValue(transposeIN));
FOR i := 0 TO (midiCount - 1) DO BEGIN
GetMidiArrayValue(midiIN, i, midi);
note := midi.data1;
chan := midi.channel;
IF ((chan = 1) and (not bassOn1)) OR ((chan = 2) and not (bassOn2)) OR //ALLOW NOTES ABOVE AND BELOW IF KEYB IS NOT SUBJECT TO BASS
(((note >= splitVal) AND ((not isBass) OR (isbass AND rhBass))) //ABOVE SPLIT OUT
OR ((note < splitVal)) AND ((not isBass) OR (isbass AND not rhBass))) THEN BEGIN //BELOW SPLIT OUT
if (orgRech > 0) then midi.channel := orgRech; //if it's 0 leave ch unchanged
IF ((midi.msg = 144) AND (midi.data2 > 0)) THEN BEGIN // NoteOn
if hands then makeHands;
transpositions[midi.data1] := transpose; // Store transpose value used for NoteOn
noteOns[midi.data1] := TRUE;
midi.data1 := midi.data1 + transpose;
END
ELSE IF ( (midi.msg = 128)
OR ((midi.msg = 144) AND (midi.data2 = 0))) THEN BEGIN // NoteOff
if hands then makeHands;
if (not isDrum) then begin
midi.data1 := midi.data1 + transpositions[midi.data1]; // Retrieve stored transpose and add to NoteOff
noteOns[midi.data1] := FALSE;
end;
END;
SetMidiArrayValue(midiOUT, outcount, midi);
outCount := outCount + 1;
END;
END;
setLength(midiOUT, outCount);
END
ELSE BEGIN
SetLength(midiOUT, 0);
END;
END;
[/c]