Welcome to %s forums

BrainModular Users Forum

Login Register

Internal MIDI error on script output

I need help on a Patch
Post Reply
woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 31 Oct 2017, 16:52

This one really has me pulling my hair out.

This is a complicated script. It sits in the first slot of every vst rack in my wkp, and decides which midi channel will be sent on to the vst, does note limiting, and rechannelizes the output to the vst. It also has smart transpose and can convert the transpose input to a CC for pitching drum sounds etc. If the value of input vstChIN is zero, then incoming midi messages are sent out with their original channel unchanged, for controlling multi-channel vsts. Otherwise they are rechannelized to the value of vstChIN.

It works perfectly! Except for one thing.

If (and ONLY if) the value of vstChIN = '0', I get a repeated internal error that fills up the trace, even if there is NO midi activity at all! The error shows up in the next patch down in the rack, gui.pat, which contains all the gui controls. The only midi in that patch is an input wired directly to a midi output to pass midi on to the 3rd patch which hosts the vst. The error looks like this:

Error : E901 patch process : Process of MIDI In (rack: 3) patch: gui.pat

It's not a malformed message as no messages are sent. It is happening as soon as the vstChIN changes to 0. The output of the script is cabled directly to a MIDI OUT module.

One hint that might be helpful. If HH is set to 'NO AUDIO' the error only occurs once.

If there are any script gurus that have any idea what may be going on, please let me know! I can't think of anything else to try at the moment.

Thanks as always!!!
=eric

Code: Select all

/////////////////////////////////////////////////////////////////////////////
//   vstChIN parameter value of 0 is causing error
//   Error : E901 patch process : Process of MIDI In (rack: 3)  patch: gui.pat //next patch down
/////////////////////////////////////////////////////////////////////////////

VAR midiIN, midiOUT : Tparameter;
// from NS 
var transposeIN: Tparameter;
var lowNoteIN  : Tparameter; 
var hiNoteIN   : Tparameter;
var chanIN     : Tparameter;
var statusOUT  : Tparameter;
var vstChIN    : Tparameter;
// from mixer
var handsIN    : Tparameter;  
var holdIN     : Tparameter;
var trackIN     : Tparameter; 
var enabledIN     : Tparameter; 
// from inst    
var transToCtlIN : Tparameter;
var resetClkIN    : Tparameter;
var resetVelIN    : Tparameter;
//arrays
var nSolosIN     : Tparameter;  
var noSusIN      : Tparameter;
var nsLowNotesIN  : Tparameter;
var nsHiNotesIN   : Tparameter; 

var resetClkOUT   : Tparameter;                    

var clearIN      : Tparameter;                            

VAR transpositions : ARRAY OF integer;
VAR noteONs : ARRAY OF boolean;

VAR midi : tMidi;                                               
VAR midiCount, transpose,transCtl,i, trackCount, trackNum,status : integer;
VAR newTranspose,hands,hold,resetClk,resetting: boolean;         
var lowNote,hiNote,nSoloLow,nSoloHi, inputCh, vstChan, vel, resetVel: integer; 
var nSolo, clearNotes, enabled,noSus: boolean;

PROCEDURE Init;                                                                                          
BEGIN
//from NS
    midiIN := CreateParam('midi in', ptMidi); SetIsOutput(midiIN, FALSE); 
    chanIN := CreateParam('midi chan', ptDatafield); SetIsOutput(chanIN, FALSE);
    lowNoteIN := CreateParam('low note', ptDataField); SetIsOutput(lowNoteIN, FALSE);    
    hiNoteIN := CreateParam('hi note', ptDataField); SetIsOutput(hiNoteIN, FALSE);
//from mixer    
    transposeIN := CreateParam('transpose', ptDataField);SetIsOutput(transposeIN, FALSE);
    handsIN := CreateParam('hands on',ptSwitch);  SetIsOutput(handsIN, false);     
    holdIN := CreateParam('hold on',ptSwitch);  SetIsOutput(holdIN, false); 
//from inst
    transToCtlIN := CreateParam('transToCtl',ptDatafield); SetIsOutput(transToCtlIN, false); 
    //ns array is an array [1..trackcount] of midi channels.  0 means either the chan is disabled, or it is not a ns channel
    nSolosIN := CreateParam('nsSolo arr',ptArray); SetIsOutput(nSolosIN, false);      
    nsLowNotesIN := CreateParam('ns low arr',ptArray); SetIsOutput(nsLowNotesIN, false);  
    nsHiNotesIN := CreateParam('ns high arr',ptArray); SetIsOutput(nsHiNotesIN, false);
    // what ch the inst wants.  0 for multichan... CAUSING ERROR!!!!!    
    vstChIN := CreateParam('vst chan', ptDatafield); SetIsOutput(vstChIN, FALSE);
    
    clearIN := CreateParam('clear notes',ptSwitch); SetIsOutput(clearIN, false); 
        
    resetClkIN := CreateParam('vel clock reset', ptDatafield); SetIsOutput(resetClkIN, FALSE); 
    resetVelIN := CreateParam('reset vel thresh', ptDatafield); SetIsOutput(resetVelIN, FALSE);     
    trackIN := CreateParam('track num', ptDatafield); SetIsOutput(trackIN, FALSE);     
    enabledIN := CreateParam('enable', ptDatafield); SetIsOutput(enabledIN, FALSE);    
    noSusIN := CreateParam('no sus', ptDatafield); SetIsOutput(noSusIN, FALSE); 
    
    resetClkOUT := CreateParam('reset clock', ptDatafield); SetIsInput(resetClkOUT, FALSE); 
    
    midiOUT := CreateParam('midi out', ptMidi); SetIsInput(midiOUT, FALSE);
    statusOUT := CreateParam('status', ptDatafield); SetIsInput(statusOUT, FALSE);     
 
    SetArrayLength(transpositions, 128);         
    SetArrayLength(noteONs, 128);                 
    for i := 0 to 127 DO BEGIN
        transpositions[i] := 0;
        noteOns[i] := FALSE;                    
    END;   
    clearNotes := FALSE;
    newTranspose := FALSE; 
    setLength(resetClkOUT,0);
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 setStatus;
var compromised : boolean;
BEGIN  
    compromised := false;                
    if not enabled THEN status := 0 
    ELSE
    BEGIN
        //check our own status
        trackCount := getLength(nSolosIN);
        //figure key range based on NS    
        nSolo := getDataArrayValue(nSolosIN,trackNum - 1) = inputCh;
        IF nSolo THEN
        BEGIN
            nSoloHI := trunc(getDataArrayValue(nsHiNotesIN, trackNum - 1));
            nSoloLow := trunc(getDataArrayValue(nsLowNotesIN, trackNum - 1));
            IF nSoloHI < hiNote THEN hiNote &#58;= nSoloHI;
            IF nSoloLow > lowNote THEN lowNote &#58;= nSoloLow; 
        END ELSE
        BEGIN  // reset the keyboard range...
        //strace&#40;'resetting keyboard range for channel ' + inttostr&#40;trackNum&#41;&#41;;
            hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
            lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;;
        END;
        //No notesoloing for FX &#40;ch 17&#41;
        IF &#40;inputCH = 17&#41; THEN
        BEGIN
          IF enabled THEN status &#58;= 1 ELSE status &#58;= 0;
        END
        //cannot be note solo in omni mode!
        ELSE IF &#40;inputCH > 0&#41; and nSolo THEN
        BEGIN
             //we are a note solo inst 
             //strace&#40;'note solo ON for track number ' + intToStr&#40;trackNum&#41;&#41;; 
             status &#58;= 2; 
        END
        ELSE BEGIN
            // compute status and nsInfo from arrays  
            nSoloHI &#58;= 0;
            nSoloLow &#58;= 127
            for i &#58;= 0 to trackCount - 1 do
            BEGIN
                if &#40;inputCH > 0&#41; and &#40;getDataArrayValue&#40;nSolosIN,i&#41; = inputCH&#41; then
                BEGIN  //we are note solo compromised.
                    //strace&#40;'note solo affecting track number ' + intToStr&#40;trackNum&#41;&#41;;
                    compromised &#58;= true;     
                    if &#40;getDataArrayValue&#40;nsHiNotesIN,i&#41; > nSoloHI&#41; then 
                        nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN,i&#41;&#41;;
                    if &#40;getDataArrayValue&#40;nsLowNotesIN,i&#41; < nSoloLow&#41; then 
                        nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN,i&#41;&#41;;
                END;
            END; 
            //strace&#40;'notesoloLow = ' + intToStr&#40;nSoloLow&#41;&#41;; 
            //strace&#40;'notesoloHi = ' + intToStr&#40;nSoloHi&#41;&#41;; 
            if compromised then status &#58;= 3 ELSE status &#58;= 1;
        END;
    END;
    setValue&#40;statusOUT,status&#41;
END;

procedure callback&#40;n&#58; integer&#41;;
BEGIN   
    //strace&#40;'n = ' + inttostr&#40;n&#41;&#41;;
    IF &#40;n = 0&#41;               THEN //ignore
    ELSE IF &#40;n = transposeIN&#41;     THEN newTranspose &#58;= TRUE                  
    ELSE IF &#40;n = trackIN&#41;         THEN trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;            
    ELSE IF &#40;n = transToCtlIN&#41;    THEN transCtl &#58;= trunc&#40;getValue&#40;transToCtlIN&#41;&#41;            
    ELSE IF &#40;n = resetClkIN&#41;      THEN resetClk &#58;= trunc&#40;getValue&#40;resetClkIN&#41;&#41; = 1
    ELSE IF &#40;n = resetVelIN&#41;      THEN resetVel &#58;= trunc&#40;getValue&#40;resetVelIN&#41;&#41;  
    ELSE IF &#40;n = noSusIN&#41;         THEN noSus &#58;= trunc&#40;getValue&#40;noSusIN&#41;&#41; > 0
    ELSE IF &#40;n = holdIN&#41;          THEN 
    BEGIN
        hold &#58;= trunc&#40;getValue&#40;holdIN&#41;&#41; = 1;
        //strace&#40;'hold setting clear notes if it is off'&#41;;
        //if we just turned of hold, clear notes
        IF NOT hold then clearNotes &#58;= TRUE; 
    END
    ELSE IF &#40;n = enabledIN&#41; THEN 
        BEGIN
            enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41; = 1;  

        //strace&#40;'enabled setting clear notes if not enabled and not hold'&#41;;            
            if  NOT enabled and NOT hold then clearNotes &#58;= TRUE;
            setStatus;
        END    
    //some other inst has changed, so we need to check status
    ELSE IF &#40;n = nsHiNotesIN&#41; OR &#40;n= nsLowNotesIN&#41; OR &#40;n = nSolosIN&#41; THEN setStatus 
    ELSE IF &#40;n = resetClkOUT&#41; OR &#40;n = midiOUT&#41; OR &#40;n = statusOUT&#41; THEN //why,it's an output??????
    ELSE BEGIN
        IF &#40;n = handsIN&#41;              THEN hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;
        ELSE IF &#40;n = vstChIN&#41;         THEN vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;
        ELSE IF &#40;n = lowNoteIN&#41;       THEN lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;
        ELSE IF &#40;n = hiNoteIN&#41;        THEN hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;
        ELSE IF &#40;n = chanIN&#41;          THEN inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        setStatus;
        clearNotes &#58;= TRUE;
        //strace&#40;'setting clearNotes to true via hands, outch, lownote hinote,  or chan'&#41;;        
                                
        
    END
END;                  

// process
procedure process;
var outCount,note,chan&#58; integer;                           
var ccTrans,countOffset&#58; integer;
var newMidi&#58; tMidi; 
var hasMidi&#58; boolean;
var minCH,maxCH,ch &#58; integer;           
BEGIN 
    IF &#40;vstChan = 17&#41; THEN  SetLength&#40;midiOUT, 0&#41; // no midi processing at all
    ELSE BEGIN      
    //should filter all but notes, sustain and pb prev to script
        midiCount &#58;= GetLength&#40;midiIN&#41;; 
        hasMidi &#58;= midiCount > 0;
        outCount &#58;= 0; 
        if resetting = true then begin
            resetting &#58;= false; //turn reset back off
            setValue&#40;resetClkOUT, 0&#41;; //null event for off
        end                                 
        IF clearNotes and &#40;vstChan < 17&#41; then BEGIN          
            //strace&#40;'clearing notes'&#41;;   
            //for omni sources, send noteoffs on every channel...    
            IF vstChan = 0 then BEGIN minCH &#58;= 1; maxCH &#58;= 16; END
                                ELSE BEGIN minCH = vstChan; maxCH &#58;= vstChan; END;
            FOR ch &#58;= minCH to maxCH DO 
            BEGIN
                for i &#58;= 0 to 127 DO  BEGIN
                  // send note off s  
                    if noteONs&#91;i&#93; &#58;= TRUE THEN BEGIN
                       midi.channel &#58;= ch; midi.msg &#58;= 128;  midi.data1 &#58;= i; midi.data2 &#58;= 0;
                       setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;
                       outCount &#58;= outCount + 1;
                       noteONs&#91;i&#93; &#58;= FALSE;  
                    END;
                END;
                // send sus pedal off!
                midi.channel &#58;= ch; midi.msg &#58;= 176; midi.data1 &#58;= 64; midi.data2 &#58;= 0;
            end                
            setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;            
            outCount &#58;= outCount + 1;  
            setLength&#40;midiOUT, outCount&#41;;  
            clearNotes &#58;= FALSE;
            //if we are clearing, we ignore other midi input for this cycle....            
        END  
        ELSE 
        BEGIN
            if newTranspose and &#40;vstChan < 17&#41; then 
            begin
    strace&#40;'in NEW TRANSPOSE'&#41;;
                IF &#40;transCtl = 0&#41; then transpose &#58;= round&#40;getValue&#40;transposeIN&#41;&#41;
                ELSE BEGIN
                    transpose &#58;= 0;
                    // create midi cc out for drum tuning &#40;cc value is transCtl&#41;
                    ccTrans &#58;= &#40;round&#40;&#40;transpose * 1.76&#41; + 64&#41;&#41;;  
                    //strace&#40;'____________CC TRANS = ' + intToStr&#40;ccTrans&#41;&#41;;  
                    newMidi.msg &#58;= 176; newMidi.channel &#58;= 1; newMidi.data1 &#58;= transCtl; newMidi.data2 &#58;= round&#40;ccTrans&#41;;
                    SetMidiArrayValue&#40;midiOUT, outCount, newMidi&#41;; 
                    outCount &#58;= outCount + 1; 
                END;
                newTranspose &#58;= FALSE;                                                        
            end;
            // filter everything but notes for this script! 
            //Hold keeps new notes from being triggered 
            IF hasMidi and &#40;hold = false&#41; and enabled and &#40;vstChan < 17&#41; THEN 
            BEGIN             
                countOffset &#58;= outCount;
                FOR i &#58;= 0 TO &#40;midiCount - 1&#41; DO 
                BEGIN
                    GetMidiArrayValue&#40;midiIN, i, midi&#41;;  
                    note &#58;= midi.data1; 
                    vel &#58;= midi.data2;
                    chan &#58;= midi.channel;       
                    IF &#40;inputCh > 0&#41; then midi.channel &#58;= vstChan;  //if midiCH is 0 leave unchanged 
                    IF  &#40;midi.msg = 224&#41; OR &#40;&#40;midi.msg = 172&#41; AND &#40;noSus = false&#41;&#41; THEN   
                    BEGIN 
                        //strace&#40;'message = ' + inttoStr&#40;midi.msg&#41;&#41;;
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;     
                    END 
                        //TODO&#58; how does this work with PB and SUS on multi ch sources?
                    ELSE IF &#40;inputCH > 0&#41; AND &#40;chan <> inputCH&#41; THEN  //ignore notes from other channels. 0 is omni.                    
                    ELSE IF &#40;note < lowNote&#41; or &#40;note > hiNote&#41; THEN //ignore notes outside range.  True for any status. Includes NS limiting
                    ELSE IF &#40;status = 3&#41; and &#40;nSoloLow <= note&#41; and &#40;note <= nSoloHI&#41; THEN //ignore note solo range on NS channel
                    //strace&#40;'tracknum = ' + inttostr&#40;trackNum&#41; +', nsolo lo = ' + inttostr&#40;nSoloLow&#41; + ', nSoloHI = ' + inttostr&#40;nSoloHi&#41; + ',note = ' + intToStr&#40;note&#41;&#41;;                    
                                                                                                     
                    ELSE 
                    BEGIN     
                        IF &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 > 0&#41;&#41; THEN 
                        BEGIN // NoteOn
                            if hands then makeHands;
                            if resetClk and &#40;vel > resetVel&#41; then
                            begin        
                            //strace&#40;'resetting------------------------------------- '&#41;;
                                setLength&#40;resetClkOUT,1&#41;;
                                setValue&#40;resetClkOUT,1&#41;;
                                resetting &#58;= true;
                            end;
                            transpositions&#91;midi.data1&#93; &#58;= transpose; // Store transpose value used for NoteOn 
                            noteOns&#91;midi.data1&#93; &#58;= TRUE;  
                            midi.data1 &#58;= midi.data1 + transpose;                
                        END
                        ELSE IF &#40;   &#40;midi.msg = 128&#41;
                                  OR &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 = 0&#41;&#41;&#41; THEN 
                        BEGIN // NoteOff
                            if hands then makeHands;
                            if &#40;transCtl = 0&#41; then 
                            begin
                                midi.data1 &#58;= midi.data1 + transpositions&#91;midi.data1&#93;; // Retrieve stored transpose and add to NoteOff
                                noteOns&#91;midi.data1&#93; &#58;= FALSE; 
                            end;            
                        END; 
                        //ELSE IF &#40;midi.msg = 172&#41; and &#40;midi.data1 = 64&#41; 
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;  
                                                    
                    END; 
                END;
                setLength&#40;midiOUT, outCount&#41;;
            END
            ELSE
            BEGIN
              SetLength&#40;midiOUT, 0&#41;;
            END;                                                                  
        END;
    END;
END;
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 01 Nov 2017, 06:50

well, to follow up:

I realized that I didn't really need to have an omni mode for the output, just for the input. So I eliminated the need for a value of 0 for the midi out to the vst, and just have an omni setting for the input. duh.

But now I am getting the issue when the input channel is 0 (for no rechannelization).

I realized that there were a number of variables that might not have been initialized in the setStatus method. I think I cleared that up, but the issue persists. So maybe I still missed one?

Well time for bed. Any help welcome.... I'll post again if I figure it out FWIW for future generations ;)

Here's the new code:

Code: Select all

/////////////////////////////////////////////////////////////////////////////
//   VST CH of 0 is causing error
//   Limit vst ch to 1 thru 16.  Use INPUT CH = 0 to stop channelization of messages!
/////////////////////////////////////////////////////////////////////////////
const STATUS_ENABLED = 1;
const STATUS_DISABLED = 0;
const STATUS_NOTESOLOED = 2; //a note solo instrument will mute other instruments on its channel over its key range
const STATUS_COMPROMISED = 3;//when all or part of the noterange is muted by a notesolo inst on another track

VAR midiIN, midiOUT &#58; Tparameter;
// from NS 
var transposeIN&#58; Tparameter;
var lowNoteIN  &#58; Tparameter; 
var hiNoteIN   &#58; Tparameter;
var chanIN     &#58; Tparameter;
var statusOUT  &#58; Tparameter;
var vstChIN    &#58; Tparameter;
// from mixer
var handsIN    &#58; Tparameter;  
var holdIN     &#58; Tparameter;
var trackIN     &#58; Tparameter; 
var enabledIN     &#58; Tparameter; 
// from inst    
var transToCtlIN &#58; Tparameter;
var resetClkIN    &#58; Tparameter;
var resetVelIN    &#58; Tparameter;
//arrays
var nSolosIN     &#58; Tparameter;  
var noSusIN      &#58; Tparameter;
var nsLowNotesIN  &#58; Tparameter;
var nsHiNotesIN   &#58; Tparameter; 

var resetClkOUT   &#58; Tparameter;                    

var clearIN      &#58; Tparameter;                            

VAR transpositions &#58; ARRAY OF integer;
VAR noteONs &#58; ARRAY OF boolean;        

VAR midi &#58; tMidi;                                               
VAR midiCount, transpose,transCtl,i, trackCount, trackNum,status &#58; integer;
VAR newTranspose,hands,hold,resetClk,resetting&#58; boolean;         
var lowNote,hiNote,nSoloLow,nSoloHi, inputCh, vstChan, vel, resetVel&#58; integer; 
var nSolo, clearNotes, enabled,noSus&#58; boolean;

PROCEDURE Init;                                                                                          
BEGIN
//from NS
    midiIN &#58;= CreateParam&#40;'midi in', ptMidi&#41;; SetIsOutput&#40;midiIN, FALSE&#41;; 
    //0 = OMNI, 17 = Disable Midi note Processing &#40;for normal fx&#41;
    chanIN &#58;= CreateParam&#40;'midi chan', ptDatafield&#41;; SetIsOutput&#40;chanIN, FALSE&#41;;
    lowNoteIN &#58;= CreateParam&#40;'low note', ptDataField&#41;; SetIsOutput&#40;lowNoteIN, FALSE&#41;;    
    hiNoteIN &#58;= CreateParam&#40;'hi note', ptDataField&#41;; SetIsOutput&#40;hiNoteIN, FALSE&#41;;
//from mixer    
    transposeIN &#58;= CreateParam&#40;'transpose', ptDataField&#41;;SetIsOutput&#40;transposeIN, FALSE&#41;;
    handsIN &#58;= CreateParam&#40;'hands on',ptSwitch&#41;;  SetIsOutput&#40;handsIN, false&#41;;     
    holdIN &#58;= CreateParam&#40;'hold on',ptSwitch&#41;;  SetIsOutput&#40;holdIN, false&#41;; 
//from inst
    transToCtlIN &#58;= CreateParam&#40;'transToCtl',ptDatafield&#41;; SetIsOutput&#40;transToCtlIN, false&#41;; 
    //ns array is an array &#91;1..trackcount&#93; of midi channels.  0 means either the chan is disabled, or it is not a ns channel
    nSolosIN &#58;= CreateParam&#40;'nsSolo arr',ptArray&#41;; SetIsOutput&#40;nSolosIN, false&#41;;      
    nsLowNotesIN &#58;= CreateParam&#40;'ns low arr',ptArray&#41;; SetIsOutput&#40;nsLowNotesIN, false&#41;;  
    nsHiNotesIN &#58;= CreateParam&#40;'ns high arr',ptArray&#41;; SetIsOutput&#40;nsHiNotesIN, false&#41;;
    // what ch the vst inst wants to see. If INPUT CH is 0 or 17, this doesn't matter!   
    vstChIN &#58;= CreateParam&#40;'vst chan', ptDatafield&#41;; SetIsOutput&#40;vstChIN, FALSE&#41;;
    
    clearIN &#58;= CreateParam&#40;'clear notes',ptSwitch&#41;; SetIsOutput&#40;clearIN, false&#41;; 
        
    resetClkIN &#58;= CreateParam&#40;'vel clock reset', ptDatafield&#41;; SetIsOutput&#40;resetClkIN, FALSE&#41;; 
    resetVelIN &#58;= CreateParam&#40;'reset vel thresh', ptDatafield&#41;; SetIsOutput&#40;resetVelIN, FALSE&#41;;     
    trackIN &#58;= CreateParam&#40;'track num', ptDatafield&#41;; SetIsOutput&#40;trackIN, FALSE&#41;;     
    enabledIN &#58;= CreateParam&#40;'enable', ptDatafield&#41;; SetIsOutput&#40;enabledIN, FALSE&#41;;    
    noSusIN &#58;= CreateParam&#40;'no sus', ptDatafield&#41;; SetIsOutput&#40;noSusIN, FALSE&#41;; 
    
    resetClkOUT &#58;= CreateParam&#40;'reset clock', ptDatafield&#41;; SetIsInput&#40;resetClkOUT, FALSE&#41;; 
    
    midiOUT &#58;= CreateParam&#40;'midi out', ptMidi&#41;; SetIsInput&#40;midiOUT, FALSE&#41;;
    statusOUT &#58;= CreateParam&#40;'status', ptDatafield&#41;; SetIsInput&#40;statusOUT, FALSE&#41;;     
 
    SetArrayLength&#40;transpositions, 128&#41;;         
    SetArrayLength&#40;noteONs, 128&#41;;                 
    for i &#58;= 0 to 127 DO BEGIN
        transpositions&#91;i&#93; &#58;= 0;
        noteOns&#91;i&#93; &#58;= FALSE;                    
    END;   
    clearNotes &#58;= FALSE;
    newTranspose &#58;= FALSE; 
    setLength&#40;resetClkOUT,0&#41;;
    //strace&#40;'INIT FINISHED--MIDIINPUTPROC'&#41;;
END; // Init

procedure makeHands;
var note &#58; integer;
begin 
    hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;;   
    if hands then begin
           note &#58;= midi.data1;  
           if note > 60 then midi.data1 &#58;= note - 12
                        else midi.data1 &#58;= note + 12;  
    end;  

end;

procedure setStatus;
var compromised &#58; boolean;
BEGIN     //status&#58;  0-off; 1-on; 2-noteSolo; 3-muted by noteSolo;
    compromised &#58;= false;
    status &#58;= STATUS_ENABLED;  
    //maybe these aren't always initialized????    
    vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;;
    inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
    enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;; 
    hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
    lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;;   
    
    if not enabled THEN status &#58;= STATUS_DISABLED 
    ELSE
    BEGIN
        //check our own status
        strace&#40;'CHECKING STATUS-----------------------------------------'&#41;;
        trackCount &#58;= getLength&#40;nSolosIN&#41;;
        //figure key range based on NS    
        nSolo &#58;= getDataArrayValue&#40;nSolosIN,trackNum - 1&#41; = inputCh;
        IF nSolo THEN
        BEGIN
            nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN, trackNum - 1&#41;&#41;;
            nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN, trackNum - 1&#41;&#41;;
            IF nSoloHI < hiNote THEN hiNote &#58;= nSoloHI;
            IF nSoloLow > lowNote THEN lowNote &#58;= nSoloLow; 
        END ELSE
        BEGIN  // reset the keyboard range...
        //strace&#40;'resetting keyboard range for channel ' + inttostr&#40;trackNum&#41;&#41;;
            hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
            lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;;
        END;
        //No notesoloing for FX &#40;ch 17&#41;
        IF &#40;inputCH = 17&#41; THEN
        BEGIN
          IF enabled THEN status &#58;= STATUS_ENABLED ELSE status &#58;= STATUS_DISABLED;
        END
        //cannot be note solo in omni mode!
        ELSE IF &#40;inputCH > 0&#41; and nSolo THEN
        BEGIN
             //we are a note solo inst 
             //strace&#40;'note solo ON for track number ' + intToStr&#40;trackNum&#41;&#41;; 
             status &#58;= STATUS_NOTESOLOED; 
        END
        ELSE BEGIN
            // compute status and nsInfo from arrays  
            nSoloHI &#58;= 0;
            nSoloLow &#58;= 127
            for i &#58;= 0 to trackCount - 1 do
            BEGIN
                if &#40;inputCH > 0&#41; and &#40;getDataArrayValue&#40;nSolosIN,i&#41; = inputCH&#41; then
                BEGIN  //we are note solo compromised.
                    //strace&#40;'note solo affecting track number ' + intToStr&#40;trackNum&#41;&#41;;
                    compromised &#58;= true;     
                    if &#40;getDataArrayValue&#40;nsHiNotesIN,i&#41; > nSoloHI&#41; then 
                        nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN,i&#41;&#41;;
                    if &#40;getDataArrayValue&#40;nsLowNotesIN,i&#41; < nSoloLow&#41; then 
                        nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN,i&#41;&#41;;
                END;
            END; 
            //strace&#40;'notesoloLow = ' + intToStr&#40;nSoloLow&#41;&#41;; 
            //strace&#40;'notesoloHi = ' + intToStr&#40;nSoloHi&#41;&#41;; 
            if compromised then status &#58;= STATUS_COMPROMISED ELSE status &#58;= STATUS_ENABLED;
        END;
    END;
    setValue&#40;statusOUT,status&#41;
END;

procedure callback&#40;n&#58; integer&#41;;
BEGIN   
    strace&#40;'MIDIINPUTPROC CALLBACK&#58;  n = ' + inttostr&#40;n&#41;&#41;;
    BEGIN
    hold &#58;= trunc&#40;getValue&#40;holdIN&#41;&#41; = 1;
    //strace&#40;'hold setting clear notes if it is off'&#41;;
    //if we just turned of hold, clear notes
    IF NOT hold then clearNotes &#58;= TRUE; 
    END
    IF &#40;n = 0&#41;               THEN //ignore
    ELSE IF &#40;n = transposeIN&#41;     THEN newTranspose &#58;= TRUE                  
    ELSE IF &#40;n = trackIN&#41;         THEN trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;            
    ELSE IF &#40;n = transToCtlIN&#41;    THEN transCtl &#58;= trunc&#40;getValue&#40;transToCtlIN&#41;&#41;            
    ELSE IF &#40;n = resetClkIN&#41;      THEN resetClk &#58;= trunc&#40;getValue&#40;resetClkIN&#41;&#41; = 1
    ELSE IF &#40;n = resetVelIN&#41;      THEN resetVel &#58;= trunc&#40;getValue&#40;resetVelIN&#41;&#41;  
    ELSE IF &#40;n = noSusIN&#41;         THEN noSus &#58;= trunc&#40;getValue&#40;noSusIN&#41;&#41; > 0
    ELSE IF &#40;n = holdIN&#41;          THEN 
    ELSE IF &#40;n = enabledIN&#41; THEN 
        BEGIN
            enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41; = 1;  

        //strace&#40;'enabled setting clear notes if not enabled and not hold'&#41;;            
            if  NOT enabled and NOT hold then clearNotes &#58;= TRUE;
            setStatus;
        END    
    //some other inst has changed, so we need to check status
    ELSE IF &#40;n = nsHiNotesIN&#41; OR &#40;n= nsLowNotesIN&#41; OR &#40;n = nSolosIN&#41; THEN setStatus 
    ELSE IF &#40;n = resetClkOUT&#41; OR &#40;n = midiOUT&#41; OR &#40;n = statusOUT&#41; THEN //why,it's an output??????
    ELSE BEGIN
        IF &#40;n = handsIN&#41;              THEN hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;
        ELSE IF &#40;n = vstChIN&#41;         THEN vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;
        ELSE IF &#40;n = lowNoteIN&#41;       THEN lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;
        ELSE IF &#40;n = hiNoteIN&#41;        THEN hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;
        ELSE IF &#40;n = chanIN&#41;          THEN inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        setStatus;
        clearNotes &#58;= TRUE;
        //strace&#40;'setting clearNotes to true via hands, outch, lownote hinote,  or chan'&#41;;        
                                
        
    END
END;                  

// process
procedure process;
var outCount,note,chan&#58; integer;                           
var ccTrans,countOffset&#58; integer;
var newMidi&#58; tMidi; 
var hasMidi&#58; boolean;
var minCH,maxCH,ch &#58; integer;           
BEGIN 
    //if input is 17&#91;disabled&#93;, bypass midi processing entirely
    IF &#40;inputCH = 17&#41; THEN  SetLength&#40;midiOUT, 0&#41; 
    ELSE BEGIN      
    //should filter all but notes, sustain and pb prev to script
        midiCount &#58;= GetLength&#40;midiIN&#41;; 
        hasMidi &#58;= midiCount > 0;
        outCount &#58;= 0; 
        if resetting = true then begin
            resetting &#58;= false; //turn reset back off
            setValue&#40;resetClkOUT, 0&#41;; //null event for off
        end                                 
        IF clearNotes then BEGIN          
            //strace&#40;'clearing notes'&#41;;   
            //for omni sources, send noteoffs on every channel... 
            //otherwise just send to the chan VST is receiving on   
            IF &#40;inputCh = 0&#41; then BEGIN minCH &#58;= 1; maxCH &#58;= 16; END
                                ELSE BEGIN minCH = vstChan; maxCH &#58;= vstChan; END;
            FOR ch &#58;= minCH to maxCH DO 
            BEGIN
                for i &#58;= 0 to 127 DO  BEGIN
                  // send note off s  
                    if noteONs&#91;i&#93; &#58;= TRUE THEN BEGIN
                       midi.channel &#58;= ch; midi.msg &#58;= 128;  midi.data1 &#58;= i; midi.data2 &#58;= 0;
                       setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;
                       outCount &#58;= outCount + 1;
                       noteONs&#91;i&#93; &#58;= FALSE;  
                    END;
                END;
                // send sus pedal off!
                midi.channel &#58;= ch; midi.msg &#58;= 176; midi.data1 &#58;= 64; midi.data2 &#58;= 0;
            end                
            setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;            
            outCount &#58;= outCount + 1;  
            setLength&#40;midiOUT, outCount&#41;;  
            clearNotes &#58;= FALSE;
            //if we are clearing, we ignore other midi input for this cycle....            
        END  
        ELSE 
        BEGIN
            if newTranspose then 
            begin
                //strace&#40;'in NEW TRANSPOSE'&#41;;
                IF &#40;transCtl = 0&#41; then transpose &#58;= round&#40;getValue&#40;transposeIN&#41;&#41;
                ELSE BEGIN
                    transpose &#58;= 0;
                    // create midi cc out for drum tuning &#40;cc value is transCtl&#41;
                    ccTrans &#58;= &#40;round&#40;&#40;transpose * 1.76&#41; + 64&#41;&#41;;  
                    //strace&#40;'____________CC TRANS = ' + intToStr&#40;ccTrans&#41;&#41;;  
                    newMidi.msg &#58;= 176; newMidi.channel &#58;= 1; newMidi.data1 &#58;= transCtl; newMidi.data2 &#58;= round&#40;ccTrans&#41;;
                    SetMidiArrayValue&#40;midiOUT, outCount, newMidi&#41;; 
                    outCount &#58;= outCount + 1; 
                END;
                newTranspose &#58;= FALSE;                                                        
            end;
            // filter everything but notes for this script! 
            //Hold keeps new notes from being triggered 
            IF hasMidi and &#40;hold = false&#41; and enabled THEN 
            BEGIN             
                countOffset &#58;= outCount;
                FOR i &#58;= 0 TO &#40;midiCount - 1&#41; DO 
                BEGIN
                    GetMidiArrayValue&#40;midiIN, i, midi&#41;;  
                    note &#58;= midi.data1; 
                    vel &#58;= midi.data2;
                    chan &#58;= midi.channel;       
                    IF &#40;inputCh > 0&#41; then midi.channel &#58;= vstChan;  //if midiCH is 0 leave unchanged 
                    IF  &#40;midi.msg = 224&#41; OR &#40;&#40;midi.msg = 172&#41; AND &#40;noSus = false&#41;&#41; THEN   
                    BEGIN 
                        //strace&#40;'message = ' + inttoStr&#40;midi.msg&#41;&#41;;
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;     
                    END 
                        //TODO&#58; how does this work with PB and SUS on multi ch sources?
                    ELSE IF &#40;inputCH > 0&#41; AND &#40;chan <> inputCH&#41; THEN  //ignore notes from other channels. 0 is omni.                    
                    ELSE IF &#40;note < lowNote&#41; or &#40;note > hiNote&#41; THEN //ignore notes outside range.  True for any status. Includes NS limiting
                    ELSE IF &#40;status = 3&#41; and &#40;nSoloLow <= note&#41; and &#40;note <= nSoloHI&#41; THEN //ignore note solo range on NS channel
                    //strace&#40;'tracknum = ' + inttostr&#40;trackNum&#41; +', nsolo lo = ' + inttostr&#40;nSoloLow&#41; + ', nSoloHI = ' + inttostr&#40;nSoloHi&#41; + ',note = ' + intToStr&#40;note&#41;&#41;;                    
                                                                                                     
                    ELSE 
                    BEGIN     
                        IF &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 > 0&#41;&#41; THEN 
                        BEGIN // NoteOn
                            if hands then makeHands;
                            if resetClk and &#40;vel > resetVel&#41; then
                            begin        
                            //strace&#40;'resetting------------------------------------- '&#41;;
                                setLength&#40;resetClkOUT,1&#41;;
                                setValue&#40;resetClkOUT,1&#41;;
                                resetting &#58;= true;
                            end;
                            transpositions&#91;midi.data1&#93; &#58;= transpose; // Store transpose value used for NoteOn 
                            noteOns&#91;midi.data1&#93; &#58;= TRUE;  
                            midi.data1 &#58;= midi.data1 + transpose;                
                        END
                        ELSE IF &#40;   &#40;midi.msg = 128&#41;
                                  OR &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 = 0&#41;&#41;&#41; THEN 
                        BEGIN // NoteOff
                            if hands then makeHands;
                            if &#40;transCtl = 0&#41; then 
                            begin
                                // Retrieve stored transpose and add to NoteOff
                                midi.data1 &#58;= midi.data1 + transpositions&#91;midi.data1&#93;; 
                                noteOns&#91;midi.data1&#93; &#58;= FALSE; 
                            end;            
                        END; 
                        //ELSE IF &#40;midi.msg = 172&#41; and &#40;midi.data1 = 64&#41; 
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;  
                                                    
                    END; 
                END;
                setLength&#40;midiOUT, outCount&#41;;
            END
            ELSE
            BEGIN
              SetLength&#40;midiOUT, 0&#41;;
            END;                                                                  
        END;
    END;
END;
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 01 Nov 2017, 07:32

the 'check status' method seemed suspicious, so I put it into a processIdle loop.

But I guess the problem is not there..... I am getting the error now immediately after a callback on n=1.

I am only getting the single error at the moment, not the stream. But it seems kind of random which happens (which I guess is to be expected if your script starts writing to memory illegally)

Code: Select all

/////////////////////////////////////////////////////////////////////////////
//   VST CH of 0 is causing error
//   Limit vst ch to 1 thru 16.  Use INPUT CH = 0 to stop channelization of messages!
/////////////////////////////////////////////////////////////////////////////
const STATUS_ENABLED = 1;
const STATUS_DISABLED = 0;
const STATUS_NOTESOLOED = 2; //a note solo instrument will mute other instruments on its channel over its key range
const STATUS_COMPROMISED = 3;//when all or part of the noterange is muted by a notesolo inst on another track

VAR midiIN, midiOUT &#58; Tparameter;
// from NS 
var transposeIN&#58; Tparameter;
var lowNoteIN  &#58; Tparameter; 
var hiNoteIN   &#58; Tparameter;
var chanIN     &#58; Tparameter;
var statusOUT  &#58; Tparameter;
var vstChIN    &#58; Tparameter;
// from mixer
var handsIN    &#58; Tparameter;  
var holdIN     &#58; Tparameter;
var trackIN     &#58; Tparameter; 
var enabledIN     &#58; Tparameter; 
// from inst    
var transToCtlIN &#58; Tparameter;
var resetClkIN    &#58; Tparameter;
var resetVelIN    &#58; Tparameter;
//arrays
var nSolosIN     &#58; Tparameter;  
var noSusIN      &#58; Tparameter;
var nsLowNotesIN  &#58; Tparameter;
var nsHiNotesIN   &#58; Tparameter; 

var resetClkOUT   &#58; Tparameter;                    

var clearIN      &#58; Tparameter;                            

VAR transpositions &#58; ARRAY OF integer;
VAR noteONs &#58; ARRAY OF boolean;        

VAR midi &#58; tMidi;                                               
VAR midiCount, transpose,transCtl, trackCount, trackNum,status &#58; integer;
VAR newTranspose,hands,hold,resetClk,resetting&#58; boolean;         
var lowNote,hiNote,nSoloLow,nSoloHi, inputCh, vstChan, vel, resetVel&#58; integer; 
var nSolo, clearNotes, enabled,noSus,statusChanged&#58; boolean;

PROCEDURE Init;
var i &#58; integer; 
BEGIN 
//from NS
    midiIN &#58;= CreateParam&#40;'midi in', ptMidi&#41;; SetIsOutput&#40;midiIN, FALSE&#41;; 
    //0 = OMNI, 17 = Disable Midi note Processing &#40;for normal fx&#41;
    chanIN &#58;= CreateParam&#40;'midi chan', ptDatafield&#41;; SetIsOutput&#40;chanIN, FALSE&#41;;
    lowNoteIN &#58;= CreateParam&#40;'low note', ptDataField&#41;; SetIsOutput&#40;lowNoteIN, FALSE&#41;;    
    hiNoteIN &#58;= CreateParam&#40;'hi note', ptDataField&#41;; SetIsOutput&#40;hiNoteIN, FALSE&#41;;
//from mixer    
    transposeIN &#58;= CreateParam&#40;'transpose', ptDataField&#41;;SetIsOutput&#40;transposeIN, FALSE&#41;;
    handsIN &#58;= CreateParam&#40;'hands on',ptSwitch&#41;;  SetIsOutput&#40;handsIN, false&#41;;     
    holdIN &#58;= CreateParam&#40;'hold on',ptSwitch&#41;;  SetIsOutput&#40;holdIN, false&#41;; 
//from inst
    transToCtlIN &#58;= CreateParam&#40;'transToCtl',ptDatafield&#41;; SetIsOutput&#40;transToCtlIN, false&#41;; 
    //ns array is an array &#91;1..trackcount&#93; of midi channels.  0 means either the chan is disabled, or it is not a ns channel
    nSolosIN &#58;= CreateParam&#40;'nsSolo arr',ptArray&#41;; SetIsOutput&#40;nSolosIN, false&#41;;      
    nsLowNotesIN &#58;= CreateParam&#40;'ns low arr',ptArray&#41;; SetIsOutput&#40;nsLowNotesIN, false&#41;;  
    nsHiNotesIN &#58;= CreateParam&#40;'ns high arr',ptArray&#41;; SetIsOutput&#40;nsHiNotesIN, false&#41;;
    // what ch the vst inst wants to see. If INPUT CH is 0 or 17, this doesn't matter!   
    vstChIN &#58;= CreateParam&#40;'vst chan', ptDatafield&#41;; SetIsOutput&#40;vstChIN, FALSE&#41;;
    
    clearIN &#58;= CreateParam&#40;'clear notes',ptSwitch&#41;; SetIsOutput&#40;clearIN, false&#41;; 
        
    resetClkIN &#58;= CreateParam&#40;'vel clock reset', ptDatafield&#41;; SetIsOutput&#40;resetClkIN, FALSE&#41;; 
    resetVelIN &#58;= CreateParam&#40;'reset vel thresh', ptDatafield&#41;; SetIsOutput&#40;resetVelIN, FALSE&#41;;     
    trackIN &#58;= CreateParam&#40;'track num', ptDatafield&#41;; SetIsOutput&#40;trackIN, FALSE&#41;;     
    enabledIN &#58;= CreateParam&#40;'enable', ptDatafield&#41;; SetIsOutput&#40;enabledIN, FALSE&#41;;    
    noSusIN &#58;= CreateParam&#40;'no sus', ptDatafield&#41;; SetIsOutput&#40;noSusIN, FALSE&#41;; 
    
    resetClkOUT &#58;= CreateParam&#40;'reset clock', ptDatafield&#41;; SetIsInput&#40;resetClkOUT, FALSE&#41;; 
    
    midiOUT &#58;= CreateParam&#40;'midi out', ptMidi&#41;; SetIsInput&#40;midiOUT, FALSE&#41;;
    statusOUT &#58;= CreateParam&#40;'status', ptDatafield&#41;; SetIsInput&#40;statusOUT, FALSE&#41;;     
 
    SetArrayLength&#40;transpositions, 128&#41;;         
    SetArrayLength&#40;noteONs, 128&#41;;                 
    for i &#58;= 0 to 127 DO BEGIN
        transpositions&#91;i&#93; &#58;= 0;
        noteOns&#91;i&#93; &#58;= FALSE;                    
    END;   
    clearNotes &#58;= FALSE;
    newTranspose &#58;= FALSE;
    statusChanged &#58;= FALSE;    
    setLength&#40;resetClkOUT,0&#41;;
    //strace&#40;'INIT FINISHED--MIDIINPUTPROC'&#41;;
END; // Init

procedure makeHands;
var note &#58; integer;
begin 
    hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;;   
    if hands then begin
           note &#58;= midi.data1;  
           if note > 60 then midi.data1 &#58;= note - 12
                        else midi.data1 &#58;= note + 12;  
    end;  

end;


procedure callback&#40;n&#58; integer&#41;;
BEGIN   
    strace&#40;'MIDIINPUTPROC CALLBACK&#58;  n = ' + inttostr&#40;n&#41;&#41;;
    IF &#40;n = 0&#41;               THEN //ignore
    ELSE IF &#40;n = transposeIN&#41;     THEN newTranspose &#58;= TRUE                  
    ELSE IF &#40;n = trackIN&#41;         THEN trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;            
    ELSE IF &#40;n = transToCtlIN&#41;    THEN transCtl &#58;= trunc&#40;getValue&#40;transToCtlIN&#41;&#41;            
    ELSE IF &#40;n = resetClkIN&#41;      THEN resetClk &#58;= trunc&#40;getValue&#40;resetClkIN&#41;&#41; = 1
    ELSE IF &#40;n = resetVelIN&#41;      THEN resetVel &#58;= trunc&#40;getValue&#40;resetVelIN&#41;&#41;  
    ELSE IF &#40;n = noSusIN&#41;         THEN noSus &#58;= trunc&#40;getValue&#40;noSusIN&#41;&#41; > 0
    ELSE IF &#40;n = holdIN&#41;          THEN
    BEGIN
        hold &#58;= trunc&#40;getValue&#40;holdIN&#41;&#41; = 1;
        //strace&#40;'hold setting clear notes if it is off'&#41;;
        //if we just turned off hold, clear notes
        IF NOT hold then clearNotes &#58;= TRUE;  
    END    
    ELSE IF &#40;n = enabledIN&#41; THEN 
        BEGIN
            enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41; = 1;  

        //strace&#40;'enabled setting clear notes if not enabled and not hold'&#41;;            
            if  NOT enabled and NOT hold then clearNotes &#58;= TRUE;
            statusChanged &#58;= true;
        END    
    //some other inst has changed, so we need to check status
    ELSE IF &#40;n = nsHiNotesIN&#41; OR &#40;n= nsLowNotesIN&#41; OR &#40;n = nSolosIN&#41; THEN statusChanged &#58;= true 
    ELSE IF &#40;n = resetClkOUT&#41; OR &#40;n = midiOUT&#41; OR &#40;n = statusOUT&#41; THEN //why,it's an output??????
    ELSE BEGIN
        IF &#40;n = handsIN&#41;              THEN hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;
        ELSE IF &#40;n = vstChIN&#41;         THEN vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;
        ELSE IF &#40;n = lowNoteIN&#41;       THEN lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;
        ELSE IF &#40;n = hiNoteIN&#41;        THEN hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;
        ELSE IF &#40;n = chanIN&#41;          THEN inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        statusChanged &#58;= true;
        clearNotes &#58;= TRUE;
        //strace&#40;'setting clearNotes to true via hands, outch, lownote hinote,  or chan'&#41;;                                              
    END;
END;   

procedure processIdle;
var compromised &#58; boolean;
var i &#58; integer;
BEGIN
    if &#40;statusChanged&#41; then
     
    BEGIN     
        compromised &#58;= false;
        status &#58;= STATUS_ENABLED;  
        //maybe these aren't always initialized????    
        vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;;
        inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41;; 
        hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
        lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;; 
        trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;;    
        
        if not enabled THEN status &#58;= STATUS_DISABLED 
        ELSE
        BEGIN
            //check our own status
            strace&#40;'CHECKING STATUS-----------------------------------------'&#41;;
            trackCount &#58;= getLength&#40;nSolosIN&#41;;
            //figure key range based on NS    
            nSolo &#58;= getDataArrayValue&#40;nSolosIN,trackNum - 1&#41; = inputCh;
            IF nSolo THEN
            BEGIN
                nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN, trackNum - 1&#41;&#41;;
                nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN, trackNum - 1&#41;&#41;;
                IF nSoloHI < hiNote THEN hiNote &#58;= nSoloHI;
                IF nSoloLow > lowNote THEN lowNote &#58;= nSoloLow; 
            END ELSE
            BEGIN  // reset the keyboard range...
            //strace&#40;'resetting keyboard range for channel ' + inttostr&#40;trackNum&#41;&#41;;
                hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
                lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;;
            END;
            //No notesoloing for FX &#40;ch 17&#41;
            IF &#40;inputCH = 17&#41; THEN
            BEGIN
              IF enabled THEN status &#58;= STATUS_ENABLED ELSE status &#58;= STATUS_DISABLED;
            END
            //cannot be note solo in omni mode!
            ELSE IF &#40;inputCH > 0&#41; and nSolo THEN
            BEGIN
                 //we are a note solo inst 
                 //strace&#40;'note solo ON for track number ' + intToStr&#40;trackNum&#41;&#41;; 
                 status &#58;= STATUS_NOTESOLOED; 
            END
            ELSE BEGIN
                // compute status and nsInfo from arrays 
                nSoloHI &#58;= 0;
                nSoloLow &#58;= 127
                for i &#58;= 0 to trackCount - 1 do
                BEGIN
                    if &#40;inputCH > 0&#41; and &#40;getDataArrayValue&#40;nSolosIN,i&#41; = inputCH&#41; then
                    BEGIN  //we are note solo compromised.
                        strace&#40;'note solo affecting track number ' + intToStr&#40;trackNum&#41;&#41;;
                        compromised &#58;= true;     
                        if &#40;getDataArrayValue&#40;nsHiNotesIN,i&#41; > nSoloHI&#41; then 
                            nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN,i&#41;&#41;;
                        if &#40;getDataArrayValue&#40;nsLowNotesIN,i&#41; < nSoloLow&#41; then 
                            nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN,i&#41;&#41;;
                    END;
                END; 
                strace&#40;'notesoloLow = ' + intToStr&#40;nSoloLow&#41;&#41;; 
                strace&#40;'notesoloHi = ' + intToStr&#40;nSoloHi&#41;&#41;; 
                if compromised then status &#58;= STATUS_COMPROMISED ELSE status &#58;= STATUS_ENABLED;
            END;
        END;  
        
                strace&#40;'MADE IT THIS FAR------------------------'&#41;; 
        setValue&#40;statusOUT,status&#41;
    END;
    statusChanged &#58;= false;
END;               

// process
procedure process;
var outCount,note,chan&#58; integer;                           
var ccTrans,countOffset&#58; integer;
var newMidi&#58; tMidi; 
var hasMidi&#58; boolean;
var minCH,maxCH,ch,i &#58; integer;           
BEGIN 
    //if input is 17&#91;disabled&#93;, bypass midi processing entirely
    IF &#40;inputCH = 17&#41; THEN  SetLength&#40;midiOUT, 0&#41; 
    ELSE BEGIN      
    //should filter all but notes, sustain and pb prev to script
        midiCount &#58;= GetLength&#40;midiIN&#41;; 
        hasMidi &#58;= midiCount > 0;
        outCount &#58;= 0; 
        if resetting = true then begin
            resetting &#58;= false; //turn reset back off
            setValue&#40;resetClkOUT, 0&#41;; //null event for off
        end                                 
        IF clearNotes then BEGIN          
            //strace&#40;'clearing notes'&#41;;   
            //for omni sources, send noteoffs on every channel... 
            //otherwise just send to the chan VST is receiving on   
            IF &#40;inputCh = 0&#41; then BEGIN minCH &#58;= 1; maxCH &#58;= 16; END
                                ELSE BEGIN minCH = vstChan; maxCH &#58;= vstChan; END;
            FOR ch &#58;= minCH to maxCH DO 
            BEGIN
                for i &#58;= 0 to 127 DO  BEGIN
                  // send note off s  
                    if noteONs&#91;i&#93; &#58;= TRUE THEN BEGIN
                       midi.channel &#58;= ch; midi.msg &#58;= 128;  midi.data1 &#58;= i; midi.data2 &#58;= 0;
                       setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;
                       outCount &#58;= outCount + 1;
                       noteONs&#91;i&#93; &#58;= FALSE;  
                    END;
                END;
                // send sus pedal off!
                midi.channel &#58;= ch; midi.msg &#58;= 176; midi.data1 &#58;= 64; midi.data2 &#58;= 0;
            end                
            setMidiArrayValue&#40;midiOUT, outCount, midi&#41;;            
            outCount &#58;= outCount + 1;  
            setLength&#40;midiOUT, outCount&#41;;  
            clearNotes &#58;= FALSE;
            //if we are clearing, we ignore other midi input for this cycle....            
        END  
        ELSE 
        BEGIN
            if newTranspose then 
            begin
                //strace&#40;'in NEW TRANSPOSE'&#41;;
                IF &#40;transCtl = 0&#41; then transpose &#58;= round&#40;getValue&#40;transposeIN&#41;&#41;
                ELSE BEGIN
                    transpose &#58;= 0;
                    // create midi cc out for drum tuning &#40;cc value is transCtl&#41;
                    ccTrans &#58;= &#40;round&#40;&#40;transpose * 1.76&#41; + 64&#41;&#41;;  
                    //strace&#40;'____________CC TRANS = ' + intToStr&#40;ccTrans&#41;&#41;;  
                    newMidi.msg &#58;= 176; newMidi.channel &#58;= 1; newMidi.data1 &#58;= transCtl; newMidi.data2 &#58;= round&#40;ccTrans&#41;;
                    SetMidiArrayValue&#40;midiOUT, outCount, newMidi&#41;; 
                    outCount &#58;= outCount + 1; 
                END;
                newTranspose &#58;= FALSE;                                                        
            end;
            // filter everything but notes for this script! 
            //Hold keeps new notes from being triggered 
            IF hasMidi and &#40;hold = false&#41; and enabled THEN 
            BEGIN             
                countOffset &#58;= outCount;
                FOR i &#58;= 0 TO &#40;midiCount - 1&#41; DO 
                BEGIN
                    GetMidiArrayValue&#40;midiIN, i, midi&#41;;  
                    note &#58;= midi.data1; 
                    vel &#58;= midi.data2;
                    chan &#58;= midi.channel;       
                    IF &#40;inputCh > 0&#41; then midi.channel &#58;= vstChan;  //if midiCH is 0 leave unchanged 
                    IF  &#40;midi.msg = 224&#41; OR &#40;&#40;midi.msg = 172&#41; AND &#40;noSus = false&#41;&#41; THEN   
                    BEGIN 
                        //strace&#40;'message = ' + inttoStr&#40;midi.msg&#41;&#41;;
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;     
                    END 
                        //TODO&#58; how does this work with PB and SUS on multi ch sources?
                    ELSE IF &#40;inputCH > 0&#41; AND &#40;chan <> inputCH&#41; THEN  //ignore notes from other channels. 0 is omni.                    
                    ELSE IF &#40;note < lowNote&#41; or &#40;note > hiNote&#41; THEN //ignore notes outside range.  True for any status. Includes NS limiting
                    ELSE IF &#40;status = 3&#41; and &#40;nSoloLow <= note&#41; and &#40;note <= nSoloHI&#41; THEN //ignore note solo range on NS channel
                    //strace&#40;'tracknum = ' + inttostr&#40;trackNum&#41; +', nsolo lo = ' + inttostr&#40;nSoloLow&#41; + ', nSoloHI = ' + inttostr&#40;nSoloHi&#41; + ',note = ' + intToStr&#40;note&#41;&#41;;                    
                                                                                                     
                    ELSE 
                    BEGIN     
                        IF &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 > 0&#41;&#41; THEN 
                        BEGIN // NoteOn
                            if hands then makeHands;
                            if resetClk and &#40;vel > resetVel&#41; then
                            begin        
                            //strace&#40;'resetting------------------------------------- '&#41;;
                                setLength&#40;resetClkOUT,1&#41;;
                                setValue&#40;resetClkOUT,1&#41;;
                                resetting &#58;= true;
                            end;
                            transpositions&#91;midi.data1&#93; &#58;= transpose; // Store transpose value used for NoteOn 
                            noteOns&#91;midi.data1&#93; &#58;= TRUE;  
                            midi.data1 &#58;= midi.data1 + transpose;                
                        END
                        ELSE IF &#40;   &#40;midi.msg = 128&#41;
                                  OR &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 = 0&#41;&#41;&#41; THEN 
                        BEGIN // NoteOff
                            if hands then makeHands;
                            if &#40;transCtl = 0&#41; then 
                            begin
                                // Retrieve stored transpose and add to NoteOff
                                midi.data1 &#58;= midi.data1 + transpositions&#91;midi.data1&#93;; 
                                noteOns&#91;midi.data1&#93; &#58;= FALSE; 
                            end;            
                        END; 
                        //ELSE IF &#40;midi.msg = 172&#41; and &#40;midi.data1 = 64&#41; 
                        SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;;
                        outCount &#58;= outCount + 1;  
                                                    
                    END; 
                END;
                setLength&#40;midiOUT, outCount&#41;;
            END
            ELSE
            BEGIN
              SetLength&#40;midiOUT, 0&#41;;
            END;                                                                  
        END;
    END;
END;
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

sephult
Member
Posts: 1144
Contact:

Unread post by sephult » 01 Nov 2017, 16:14

I took quick glance here on break at work try to give second pair of eyes....though...

Where is if MIDI array 0 then set Midi out length zaero and don't process?
"Every act of creation is first an act of destruction." -Picasso

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 01 Nov 2017, 22:55

okay, I solved the problem.... 2 take-aways:

1. Thanks to Olivier for the new error messaging. I don't think I would ever have figured out where the bug was without it.

2. I use Notepad++ for editing, and I found the bug by collapsing my code tree. I had a bunch of nested IF...THEN...ELSE sections, and there was an extra BEGIN in one of them. It's actually kind of amazing the code ever worked at all!

cheers all, and happy hollyhocking!

-eric
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

sephult
Member
Posts: 1144
Contact:

Unread post by sephult » 02 Nov 2017, 01:59

Wow awesome to hear you got it figured! Those are always the crazy ones...
"Every act of creation is first an act of destruction." -Picasso

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 03 Nov 2017, 02:42

well I guess I spoke too soon.... I guess I just broke midi out altogether, so that's why I wasn't getting the error.

It is back, but interestingly, I put a MIDI TRACE module on the output, and I am also getting a bunch of midi data out when the script starts, even though the procedure for writing to the midiArray has not been called....

Here are the messages I'm getting:

Code: Select all

 NOTE OFF  90   0 c&#58;16
 NOTE OFF  91   0 c&#58;16
 NOTE OFF  92   0 c&#58;16
 NOTE OFF  93   0 c&#58;16
 NOTE OFF  94   0 c&#58;16
 NOTE OFF  95   0 c&#58;16
 NOTE OFF  96   0 c&#58;16
 NOTE OFF  97   0 c&#58;16
 NOTE OFF  98   0 c&#58;16
 NOTE OFF  99   0 c&#58;16
 NOTE OFF 100   0 c&#58;16
 NOTE OFF 101   0 c&#58;16
 NOTE OFF 102   0 c&#58;16
 NOTE OFF 103   0 c&#58;16
 NOTE OFF 104   0 c&#58;16
 NOTE OFF 105   0 c&#58;16
 NOTE OFF 106   0 c&#58;16
 NOTE OFF 107   0 c&#58;16
 NOTE OFF 108   0 c&#58;16
 NOTE OFF 109   0 c&#58;16
 NOTE OFF 110   0 c&#58;16
 NOTE OFF 111   0 c&#58;16
 NOTE OFF 112   0 c&#58;16
 NOTE OFF 113   0 c&#58;16
 NOTE OFF 114   0 c&#58;16
 NOTE OFF 115   0 c&#58;16
 NOTE OFF 116   0 c&#58;16
 NOTE OFF 117   0 c&#58;16
 NOTE OFF 118   0 c&#58;16
 NOTE OFF 119   0 c&#58;16
 NOTE OFF 120   0 c&#58;16
 NOTE OFF 121   0 c&#58;16
 NOTE OFF 122   0 c&#58;16
 NOTE OFF 123   0 c&#58;16
 NOTE OFF 124   0 c&#58;16
 NOTE OFF 125   0 c&#58;16
 NOTE OFF 126   0 c&#58;16
 NOTE OFF 127   0 c&#58;16
 CTRL CHANGE  64   0 c&#58;16
Error &#58; E901 patch process &#58; Process of MIDI In &#40;rack&#58; 3&#41;  patch&#58; gui.pat
and here is the script as it stands. I broke the main method out into subroutines to make sure my syntax was what I intended.... I'm really stumped, and I have spent so many hours on this :(

Code: Select all

/////////////////////////////////////////////////////////////////////////////
//   MIDI_OMNI value is causing error--
//          Error &#58; E901 patch process &#58; Process of MIDI In &#40;following rack patch&#41;
//  
/////////////////////////////////////////////////////////////////////////////
const MIDI_OMNI = 0;
const MIDI_OFF = 17;
const CH_ENABLED = 1;
const CH_DISABLED = 0;
const CH_NOTESOLOED = 2; //a note solo instrument will mute other instruments on its channel over its key range
const CH_COMPROMISED = 3;//when all or part of the noterange is muted by a notesolo inst on another track

VAR midiIN, midiOUT &#58; Tparameter;
// from NS 
var transposeIN&#58; Tparameter;
var lowNoteIN  &#58; Tparameter; 
var hiNoteIN   &#58; Tparameter;
var chanIN     &#58; Tparameter;
var statusOUT  &#58; Tparameter;
var vstChIN    &#58; Tparameter;
// from mixer
var handsIN    &#58; Tparameter;  
var holdIN     &#58; Tparameter;
var trackIN     &#58; Tparameter; 
var enabledIN     &#58; Tparameter; 
// from inst    
var transToCtlIN &#58; Tparameter;
var resetClkIN    &#58; Tparameter;
var resetVelIN    &#58; Tparameter;
//arrays
var nSolosIN     &#58; Tparameter;  
var noSusIN      &#58; Tparameter;
var nsLowNotesIN  &#58; Tparameter;
var nsHiNotesIN   &#58; Tparameter; 

var resetClkOUT   &#58; Tparameter;                    

var clearIN      &#58; Tparameter;                            

VAR transpositions &#58; ARRAY OF integer;
VAR noteONs &#58; ARRAY OF boolean;        

VAR midi &#58; tMidi;                                               
VAR outCount, transpose,transCtl, trackCount, trackNum,status &#58; integer;
VAR newTranspose,hands,hold,resetClk,resetting&#58; boolean;         
var lowNote,hiNote,nSoloLow,nSoloHi, inputCh, vstChan, resetVel&#58; integer; 
var nSolo, clearNotes, enabled,noSus,statusChanged&#58; boolean;

PROCEDURE Init;
var i &#58; integer; 
BEGIN 
//from NS
    midiIN &#58;= CreateParam&#40;'midi in', ptMidi&#41;; SetIsOutput&#40;midiIN, FALSE&#41;; 
    //18 = OMNI, 17 = Disable Midi note Processing &#40;for normal fx&#41;
    chanIN &#58;= CreateParam&#40;'midi chan', ptDatafield&#41;; SetIsOutput&#40;chanIN, FALSE&#41;;
    lowNoteIN &#58;= CreateParam&#40;'low note', ptDataField&#41;; SetIsOutput&#40;lowNoteIN, FALSE&#41;;    
    hiNoteIN &#58;= CreateParam&#40;'hi note', ptDataField&#41;; SetIsOutput&#40;hiNoteIN, FALSE&#41;;
//from mixer    
    transposeIN &#58;= CreateParam&#40;'transpose', ptDataField&#41;;SetIsOutput&#40;transposeIN, FALSE&#41;;
    handsIN &#58;= CreateParam&#40;'hands on',ptSwitch&#41;;  SetIsOutput&#40;handsIN, false&#41;;     
    holdIN &#58;= CreateParam&#40;'hold on',ptSwitch&#41;;  SetIsOutput&#40;holdIN, false&#41;; 
//from inst
    transToCtlIN &#58;= CreateParam&#40;'transToCtl',ptDatafield&#41;; SetIsOutput&#40;transToCtlIN, false&#41;; 
    //ns array is an array &#91;1..trackcount&#93; of midi channels.  0 means either the chan is disabled, or it is not a ns channel
    nSolosIN &#58;= CreateParam&#40;'nsSolo arr',ptArray&#41;; SetIsOutput&#40;nSolosIN, false&#41;;      
    nsLowNotesIN &#58;= CreateParam&#40;'ns low arr',ptArray&#41;; SetIsOutput&#40;nsLowNotesIN, false&#41;;  
    nsHiNotesIN &#58;= CreateParam&#40;'ns high arr',ptArray&#41;; SetIsOutput&#40;nsHiNotesIN, false&#41;;
    // what ch the vst inst wants to see. If INPUT CH is OMNI or OFF, this doesn't matter   
    vstChIN &#58;= CreateParam&#40;'vst chan', ptDatafield&#41;; SetIsOutput&#40;vstChIN, FALSE&#41;;
    
    clearIN &#58;= CreateParam&#40;'clear notes',ptSwitch&#41;; SetIsOutput&#40;clearIN, false&#41;; 
        
    resetClkIN &#58;= CreateParam&#40;'vel clock reset', ptDatafield&#41;; SetIsOutput&#40;resetClkIN, FALSE&#41;; 
    resetVelIN &#58;= CreateParam&#40;'reset vel thresh', ptDatafield&#41;; SetIsOutput&#40;resetVelIN, FALSE&#41;;     
    trackIN &#58;= CreateParam&#40;'track num', ptDatafield&#41;; SetIsOutput&#40;trackIN, FALSE&#41;;     
    enabledIN &#58;= CreateParam&#40;'enable', ptDatafield&#41;; SetIsOutput&#40;enabledIN, FALSE&#41;;    
    noSusIN &#58;= CreateParam&#40;'no sus', ptDatafield&#41;; SetIsOutput&#40;noSusIN, FALSE&#41;; 
    
    resetClkOUT &#58;= CreateParam&#40;'reset clock', ptDatafield&#41;; SetIsInput&#40;resetClkOUT, FALSE&#41;; 
    
    midiOUT &#58;= CreateParam&#40;'midi out', ptMidi&#41;; SetIsInput&#40;midiOUT, FALSE&#41;;
    statusOUT &#58;= CreateParam&#40;'status', ptDatafield&#41;; SetIsInput&#40;statusOUT, FALSE&#41;;     
 
    SetArrayLength&#40;transpositions, 128&#41;;         
    SetArrayLength&#40;noteONs, 128&#41;;                 
    for i &#58;= 0 to 127 DO 
    BEGIN
        transpositions&#91;i&#93; &#58;= 0;
        noteOns&#91;i&#93; &#58;= FALSE;                    
    END;   
    clearNotes &#58;= FALSE;
    newTranspose &#58;= FALSE;
    statusChanged &#58;= FALSE;    
    setLength&#40;resetClkOUT,0&#41;;
    strace&#40;'INIT FINISHED--MIDIINPUTPROC'&#41;;
END; // Init

procedure makeHands;
var note &#58; integer;        
begin 
    hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;;   
    if hands then begin
           note &#58;= midi.data1;  
           if note > 60 then midi.data1 &#58;= note - 12
                        else midi.data1 &#58;= note + 12;  
    end;  

end;


procedure callback&#40;n&#58; integer&#41;;
BEGIN   
    //strace&#40;'MIDIINPUTPROC CALLBACK&#58;  n = ' + inttostr&#40;n&#41;&#41;;
    IF &#40;n = 0&#41;               THEN //ignore
    ELSE IF &#40;n = transposeIN&#41;     THEN newTranspose &#58;= TRUE                  
    ELSE IF &#40;n = trackIN&#41;         THEN trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;            
    ELSE IF &#40;n = transToCtlIN&#41;    THEN transCtl &#58;= trunc&#40;getValue&#40;transToCtlIN&#41;&#41;            
    ELSE IF &#40;n = resetClkIN&#41;      THEN resetClk &#58;= trunc&#40;getValue&#40;resetClkIN&#41;&#41; = 1
    ELSE IF &#40;n = resetVelIN&#41;      THEN resetVel &#58;= trunc&#40;getValue&#40;resetVelIN&#41;&#41;  
    ELSE IF &#40;n = noSusIN&#41;         THEN noSus &#58;= &#40;trunc&#40;getValue&#40;noSusIN&#41;&#41; > 0&#41;
    ELSE IF &#40;n = holdIN&#41;          THEN
    BEGIN
        hold &#58;= &#40;trunc&#40;getValue&#40;holdIN&#41;&#41; = 1&#41;;
        //strace&#40;'hold setting clear notes if it is off'&#41;; 
        //if we just turned off hold, clear notes
        IF NOT hold then clearNotes &#58;= TRUE;  
    END    
    ELSE IF &#40;n = enabledIN&#41; THEN 
        BEGIN
            hold &#58;= &#40;trunc&#40;getValue&#40;holdIN&#41;&#41; = 1&#41;;
            enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41; = 1;  
            //strace&#40;'enabled setting clear notes if not enabled and not hold'&#41;;            
            if  NOT enabled and NOT hold then clearNotes &#58;= TRUE;
            statusChanged &#58;= true;
        END                                              
    //some other inst has changed, so we need to check status
    ELSE IF &#40;n = nsHiNotesIN&#41; OR &#40;n= nsLowNotesIN&#41; OR &#40;n = nSolosIN&#41; THEN 
        statusChanged &#58;= true 
    ELSE IF &#40;n = resetClkOUT&#41; OR &#40;n = midiOUT&#41; OR &#40;n = statusOUT&#41; THEN 
        //why,it's an output??????
    ELSE BEGIN
        IF &#40;n = handsIN&#41;              THEN hands &#58;= trunc&#40;getValue&#40;handsIN&#41;&#41;
        ELSE IF &#40;n = vstChIN&#41;         THEN vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;
        ELSE IF &#40;n = lowNoteIN&#41;       THEN lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;
        ELSE IF &#40;n = hiNoteIN&#41;        THEN hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;
        ELSE IF &#40;n = chanIN&#41;          THEN inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        statusChanged &#58;= true;
        clearNotes &#58;= TRUE;
        //strace&#40;'setting clearNotes to true via hands, outch, lownote hinote,  or chan'&#41;;                                              
    END;  
END;   

procedure processIdle;
var compromised &#58; boolean;
var i &#58; integer;
BEGIN
    if &#40;statusChanged&#41; then
     
    BEGIN  
        //maybe we can stop short notes when ch is re-enabled....
        clearNotes &#58;= TRUE;    
        compromised &#58;= false;
        status &#58;= CH_ENABLED;  
        //maybe these aren't always initialized????    
        vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;;
        inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
        enabled &#58;= trunc&#40;getValue&#40;enabledIN&#41;&#41;; 
        hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
        lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;; 
        trackNum &#58;= trunc&#40;getValue&#40;trackIN&#41;&#41;;    
        
        if not enabled THEN status &#58;= CH_DISABLED 
        ELSE
        BEGIN
            //check our own status
            //strace&#40;'CHECKING STATUS-----------------------------------------'&#41;;
            trackCount &#58;= getLength&#40;nSolosIN&#41;;
            //figure key range based on NS    
            nSolo &#58;= &#40;getDataArrayValue&#40;nSolosIN,trackNum - 1&#41; = inputCh&#41;;
            IF nSolo THEN
            BEGIN
                nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN, trackNum - 1&#41;&#41;;
                nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN, trackNum - 1&#41;&#41;;
                IF nSoloHI < hiNote THEN hiNote &#58;= nSoloHI;
                IF nSoloLow > lowNote THEN lowNote &#58;= nSoloLow; 
            END ELSE
            BEGIN  // reset the keyboard range...
            //strace&#40;'resetting keyboard range for channel ' + inttostr&#40;trackNum&#41;&#41;;
                hiNote &#58;= trunc&#40;getValue&#40;hiNoteIN&#41;&#41;;
                lowNote &#58;= trunc&#40;getValue&#40;lowNoteIN&#41;&#41;;
            END;
            //No notesoloing for FX &#40;ch 17&#41;
            IF &#40;inputCH = MIDI_OFF&#41; THEN
            BEGIN
              IF enabled THEN status &#58;= CH_ENABLED ELSE status &#58;= CH_DISABLED;
            END
            //cannot be note solo in omni mode!
            ELSE IF &#40;inputCH <> MIDI_OMNI&#41; and nSolo THEN
            BEGIN
                 //we are a note solo inst 
                 //strace&#40;'note solo ON for track number ' + intToStr&#40;trackNum&#41;&#41;; 
                 status &#58;= CH_NOTESOLOED; 
            END
            ELSE BEGIN
                // compute status and nsInfo from arrays 
                nSoloHI &#58;= 0;
                nSoloLow &#58;= 127
                for i &#58;= 0 to trackCount - 1 do
                BEGIN
                    if &#40;inputCH <> MIDI_OMNI&#41; and &#40;getDataArrayValue&#40;nSolosIN,i&#41; = inputCH&#41; then
                    BEGIN  //we are note solo compromised.
                        //strace&#40;'note solo affecting track number ' + intToStr&#40;trackNum&#41;&#41;;
                        compromised &#58;= true;     
                        if &#40;getDataArrayValue&#40;nsHiNotesIN,i&#41; > nSoloHI&#41; then 
                            nSoloHI &#58;= trunc&#40;getDataArrayValue&#40;nsHiNotesIN,i&#41;&#41;;
                        if &#40;getDataArrayValue&#40;nsLowNotesIN,i&#41; < nSoloLow&#41; then 
                            nSoloLow &#58;= trunc&#40;getDataArrayValue&#40;nsLowNotesIN,i&#41;&#41;;
                    END;
                END; 
                //strace&#40;'notesoloLow = ' + intToStr&#40;nSoloLow&#41;&#41;; 
                //strace&#40;'notesoloHi = ' + intToStr&#40;nSoloHi&#41;&#41;; 
                if compromised then status &#58;= CH_COMPROMISED ELSE status &#58;= CH_ENABLED;
            END;
        END;  
        
        //strace&#40;'Status Set------------------------'&#41;; 
        setValue&#40;statusOUT,status&#41;;
    END;
    statusChanged &#58;= false;
END;  

procedure writeToMidiArray;
begin
    SetMidiArrayValue&#40;midiOUT, outcount, midi&#41;; 
    strace&#40;'added midi message num ' + inttostr&#40;outCount&#41;&#41;;
    outCount &#58;= outCount + 1; 
end;

procedure sendNoteOffs&#40;&#41;;   
var minCH,maxCH,ch,i &#58; integer;
BEGIN       
    //strace&#40;'clearing notes'&#41;;   
    //for omni sources, send noteoffs on every channel... 
    //otherwise just send to the chan VST is receiving on 
    //strace&#40;'vst channel = ' + inttostr&#40;vstChan&#41;&#41;;            
    IF &#40;inputCh = MIDI_OMNI&#41; then BEGIN 
        minCH &#58;= 1; 
        maxCH &#58;= 16; 
        //strace&#40;'minCH' = ' + inttostr&#40;minCH&#41;&#41;;
    END
    ELSE BEGIN 
        minCH = vstChan; 
        maxCH &#58;= vstChan; 
    END;
    //strace&#40;'minCH = ' + inttostr&#40;minCH&#41;&#41;;
    if &#40;minCH = 0&#41; then minCH &#58;= 1;  //avoid 0 value if ch num hasn't been sent yet 
    FOR ch &#58;= minCH to maxCH DO 
    BEGIN                 
        //strace&#40;'in note off subroutine, ch = ' + inttostr&#40;ch&#41;&#41;;
        for i &#58;= 0 to 127 DO  BEGIN
          // send note off s   
          
            if noteONs&#91;i&#93; &#58;= TRUE THEN BEGIN  
               midi.channel &#58;= ch; midi.msg &#58;= 128;  midi.data1 &#58;= i; midi.data2 &#58;= 0;
               strace&#40;'note off for ' + inttostr&#40;i&#41;&#41;;
               writeToMidiArray;
               noteONs&#91;i&#93; &#58;= FALSE;  
            END;
        END;
        // send sus pedal off!
        midi.channel &#58;= ch; midi.msg &#58;= 176; midi.data1 &#58;= 64; midi.data2 &#58;= 0;
        writeToMidiArray;
    end;              
    clearNotes &#58;= FALSE;
    //&#40;strace&#40;'finished with note offs'&#41;&#41;;
end;      

procedure processMIDI;
var vel,note,chan,midiCount,i&#58; integer;
BEGIN  
    midiCount &#58;= GetLength&#40;midiIN&#41;;
    FOR i &#58;= 0 TO &#40;midiCount - 1&#41; DO 
    BEGIN
        GetMidiArrayValue&#40;midiIN, i, midi&#41;;  
        note &#58;= midi.data1; 
        vel &#58;= midi.data2;
        chan &#58;= midi.channel;       
        IF &#40;inputCh <> MIDI_OMNI&#41; then midi.channel &#58;= vstChan;  //if midiCH is 0 leave unchanged 
        //pass PB and sus  ped messages &#40;if enabled&#41; through...
        IF  &#40;midi.msg = 224&#41; OR &#40;&#40;midi.msg = 172&#41; AND &#40;noSus = false&#41;&#41; THEN   
        BEGIN            
            //strace&#40;'message = ' + inttoStr&#40;midi.msg&#41;&#41;;
            writeToMidiArray;    
        END 
        //TODO&#58; how does this work with PB and SUS on multi ch sources?
        //ignore midi data from other channels.                   
        ELSE IF &#40;inputCH <> MIDI_OMNI&#41; AND &#40;chan <> inputCH&#41; THEN  
        ELSE IF &#40;note < lowNote&#41; or &#40;note > hiNote&#41; THEN 
              //ignore notes outside range.  True for any status. Includes NS limiting
        //ignore note solo range on NS channel
        ELSE IF &#40;status = CH_COMPROMISED&#41; and &#40;nSoloLow <= note&#41; and &#40;note <= nSoloHI&#41; THEN 
        //strace&#40;'tracknum = ' + inttostr&#40;trackNum&#41; +', nsolo lo = ' + inttostr&#40;nSoloLow&#41; + ', nSoloHI = ' + inttostr&#40;nSoloHi&#41; + ',note = ' + intToStr&#40;note&#41;&#41;;                                                                                                             
        ELSE  //process these notes
        BEGIN     
            IF &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 > 0&#41;&#41; THEN 
            BEGIN // NoteOn
                if hands then makeHands;
                if resetClk and &#40;vel > resetVel&#41; then
                begin        
                //strace&#40;'resetting------------------------------------- '&#41;;
                    setLength&#40;resetClkOUT,1&#41;;
                    setValue&#40;resetClkOUT,1&#41;;
                    resetting &#58;= true;
                end;
                if &#40;transCtl = 0&#41; then
                begin
                    transpositions&#91;midi.data1&#93; &#58;= transpose; // Store transpose value used for NoteOn 
                    noteOns&#91;midi.data1&#93; &#58;= TRUE;  
                    midi.data1 &#58;= midi.data1 + transpose;
                end;
            END
            ELSE IF &#40;   &#40;midi.msg = 128&#41;
                      OR &#40;&#40;midi.msg = 144&#41; AND &#40;midi.data2 = 0&#41;&#41;&#41; THEN 
            BEGIN // NoteOff
                if hands then makeHands;
                if &#40;transCtl = 0&#41; then    //??? what is this?? why not on NoteOns???
                begin
                    // Retrieve stored transpose and add to NoteOff
                    midi.data1 &#58;= midi.data1 + transpositions&#91;midi.data1&#93;; 
                    noteOns&#91;midi.data1&#93; &#58;= FALSE; 
                end;            
            END;         
            //ELSE IF &#40;midi.msg = 172&#41; and &#40;midi.data1 = 64&#41; 
            writeToMidiArray;
                                        
        END; 
    END;
END             

// process
procedure process;                        
var ccTrans&#58; integer;
var hasMidi&#58; boolean;
var minCH,maxCH,ch,i &#58; integer;           
BEGIN 
    outCount &#58;= 0;
    inputCh &#58;= trunc&#40;getValue&#40;chanIN&#41;&#41;;
    if resetting = true then begin
        resetting &#58;= false; //turn reset back off
        setValue&#40;resetClkOUT, 0&#41;; //null event for off
    end     
    hasMidi &#58;= &#40;GetLength&#40;midiIN&#41; > 0&#41;; 
    vstChan &#58;= trunc&#40;getValue&#40;vstChIN&#41;&#41;;                            
    // filter everything but notes, PB and sus for this script! 
    //Hold keeps new notes from being triggered 
    IF hasMidi and &#40;hold = false&#41; and enabled THEN processMIDI;   
    IF clearNotes then sendNoteOffs;              
    IF newTranspose then 
    begin
        //strace&#40;'in NEW TRANSPOSE'&#41;;
        IF &#40;transCtl = 0&#41; then transpose &#58;= round&#40;getValue&#40;transposeIN&#41;&#41;
        ELSE BEGIN
            transpose &#58;= 0;
            // create midi cc out for drum tuning &#40;cc value is transCtl&#41;
            ccTrans &#58;= &#40;round&#40;&#40;transpose * 1.76&#41; + 64&#41;&#41;;  
            //strace&#40;'____________CC TRANS = ' + intToStr&#40;ccTrans&#41;&#41;;  
            midi.msg &#58;= 176; midi.channel &#58;= 1; midi.data1 &#58;= transCtl; midi.data2 &#58;= round&#40;ccTrans&#41;;
            writeToMidiArray; 
        END;
        newTranspose &#58;= FALSE;                                                        
    END;
    SetLength&#40;midiOUT,outCount&#41;;
    //ELSE SetLength&#40;midiOUT, 0&#41; // outCount should just be 0 when appropriate       
END;
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 03 Nov 2017, 06:38

Okay, to continue my dialog with myself ;)

I found not one but TWO cases where I had ':=' instead of '=' in my code. The compiler won't help you there! (I'm not sure it couldn't--I don't know that there is a legit use for the code: "if x := 3 then".... should know better, but the only coding I'm doing these days is HH scripts.

It was a lot easier to find when I broke the main method into parts. Then it was easy to comment out sections of the process, and figure out where the problem was originating.

Now it is not giving errors, and I've verified it sends MIDI out, so I can sleep tonight.

cheers,
-e
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify

23fx23
Member
Posts: 2545
Contact:

Unread post by 23fx23 » 03 Nov 2017, 06:57

hehe a classic one^^ often happens to me too in cpp if x=3 vs if x==3, one set the value and debugger can't assume that itself

Post Reply

Who is online

Users browsing this forum: No registered users and 24 guests