Welcome to %s forums

BrainModular Users Forum

Login Register

compile problem with midi script

I need help on a Patch
Post Reply
amiga909
Member
Posts: 324
Contact:

Unread post by amiga909 » 04 Nov 2008, 08:47

hi

got a problem with this (unfinished) script here.

when I compile it the midi in input pin is not generated. (using v.4.01)

further I get some cpu lags and freezes but this could be caused by my shitty office computer.
and yes, I hope this script will have some practical use :)

thaumat.org/tmp/_transfer/MEP.0.037.script

Code: Select all

(* MEP 0.037
// 2008-11-29: @amiga909
// credits to: bSork, senso (www.sensomusic.com/forums)

// <Description>
// MEP&#58; midi tool roughly inspired by Yamaha MEP-4 Midi Event Processor. 
     download the original MEP-4 manual here&#58; 
     http&#58;//www2.yamaha.co.jp/manual/pdf/emi/english/synth/MEP4E.PDF 
// Features&#58; prevent hanging notes, swap data bytes, convert to notes or system messages, ..
// Processing chain&#58; 
    <input>    ->
    select     ->                        // filter input &#40;if midi thru on&#58; pass filtered data&#41;  
    inverse    -> swapBytes ->           // modify input bytes
    expand     -> transpose ->           // calculate input bytes
    wrap       -> step&#40;x%y&#41; -> limit ->  // limit/rescale input bytes 
    affectByte ->                        // modify output bytes
    convert    ->                        // change output type
    <output>   <-
// <Parameters> 
// select event &#58; select an event type for processing 
// midi thru    &#58; output all other event types.  
                  !&#123;sysex, clock and activesensing are always filtered&#125;
// affect byte  &#58; process first or second data byte or both. if only one 
                  byte is selected, then the other byte is output unprocessed.
// inv. byte1/2 &#58; inverse incoming data byte. high value -> low, low -> high.
// swap bytes   &#58; swap first and second byte &#40;eg. convert velocity to noteOn&#41;.
// expand       &#58; choose a multiplication factor between 0.0625 to 16
// transpose    &#58; add or subtract value
// wrap around  &#58; if a value as a result of expanding or transposing is not between 1 and 128, 
                  and if wrap around is off&#58; result is 128 or 1, 
                  if wrap around is on&#58; &#40;1-1=128;128+1=1;&#41;.
// step         &#58; only messages with a data byte that is a multiple of the Step 
                  will be allowed through.
// limit low/hi &#58; specify the output data range.
                  use a range fader &#40;interface design&#41; for control.  
// limit mode   &#58; limit hard limits the output and filters values out of range 
                  scale rescales to desired range&#58; value/128 => value/newRange 
// convert      &#58; transform input event to CC, PC, PitchBend or Aftertouch

// <Notes>
   Aftertouch, PC and other messages are not tested. 
*&#41;

VAR pIn, pOut, pMult,  pEvent, pDest, pWrap,pThru, pSwap, 
 pInv1, pInv2, pTransp,  pNotesCount,   
 pStep,  pLimitHi, pLimitLo, pLimit, pConv &#58; TParameter;
TYPE TMult = ARRAY OF integer;
VAR mult &#58; ARRAY OF TMult;
VAR pMultAr&#58; ARRAY OF double; 
TYPE TBool = ARRAY OF boolean; // convert -> notes
VAR notesList&#58; ARRAY OF TBool;
VAR tmp&#58; TMidi;   
VAR multiply&#58; double;   
VAR len, i, tmpX ,tmpY, tmpXX, tmpDest,tmpMsg, transpose, limit, convert,
 tmpEvent,limitLo, limitHi, tmpLimitLo, step, notesCount,filterByte,lenCount&#58; integer; 
VAR isNoteOff, isNoteOn, isSwap, isThru,isWrap, isStepActive,
 isInv1,isInv2,isConvert,isLimit,isFirstByte,isSecondByte&#58; boolean;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//           
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE Init;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
VAR f_c1,f_c2,f_c3&#58; integer;
BEGIN
pIn &#58;= createParam&#40;'midi in', ptMidi&#41;;  
pOut &#58;= createParam&#40;'midi out', ptMidi&#41;; 
pEvent &#58;= createParam&#40;'select', ptListBox&#41;; 
  setListBoxString&#40;pEvent,
  '"ALL","Note On+Off", "Control Change", "Program Change", "Pitch Bend", "Aftertouch"'&#41;;         
pInv1 &#58;= createParam&#40;'inverse byte1', ptSwitch&#41;;      
pInv2 &#58;= createParam&#40;'inverse byte2', ptSwitch&#41;;     
pSwap &#58;= createParam&#40;'swap bytes', ptSwitch&#41;; 
pMult &#58;= createParam&#40;'expand', ptListBox&#41;; 
  setListBoxString&#40;pMult,
  '        "-bypass-", "1/16",  "1/8", "1/4", "1/2","1","2","4","8","16"'&#41;;
  pMultAr&#58;=&#91;1,          0.0625, 0.125,  0.25,  0.5,  1,  2,  4,  8,  16&#93;;       
pTransp &#58;= createParam&#40;'transpose',ptDataFader&#41;;setMin&#40;pTransp,-128&#41;;setMax&#40;pTransp,127&#41;; 
 setSymbol&#40;pTransp, ''&#41;;setFormat&#40;pTransp,'-bypass-'&#41;; 
pStep &#58;= createParam&#40;'step', ptDataFader&#41;;setMin&#40;pStep,1&#41;;setMax&#40;pStep, 16&#41;; 
  setSymbol&#40;pStep,''&#41;;setFormat&#40;pStep,'-bypass-'&#41;;  
pWrap &#58;= createParam&#40;'wrap around', ptSwitch&#41;;  
pLimitLo &#58;= createParam&#40;'lo limit', ptMidiNoteFader&#41;; setMax&#40;pLimitLo, 126&#41;; setMin&#40;pLimitLo, 0&#41;;    
pLimitHi &#58;= createParam&#40;'hi limit', ptMidiNoteFader&#41;; setMin&#40;pLimitHi, 1&#41;;setMax&#40;pLimitHi, 127&#41;;   
pLimit &#58;= createParam&#40;'limit mode', ptListBox&#41;; 
  setListBoxString&#40;pLimit,'"-bypass-","filter","rescale","compress"'&#41;;// if compress&#58; faders = ratio, threshold
  setValue&#40;pLimit,1&#41;; setDefaultValue&#40;pLimit,0&#41;;
pDest &#58;= createParam&#40;'affect byte', ptListBox&#41;; 
  setListBoxString&#40;pDest,'"1&#40;note,cc.num,..&#41;", "2&#40;velo,cc.val,..&#41;", "1 + 2"'&#41;;    
pConv &#58;= createParam&#40;'convert', ptListBox&#41;; // take all from 'Create Midi?'
  setListBoxString&#40;pConv,
  '"-bypass-","Note Legato","Note Poly &#40;mode1&#41;","Note Poly &#40;mode2&#41;","Control Change","Program Change", "Pitch Bend","Aftertouch Channel","Aftertouch Poly", "Timing Clock","Start","Stop","Continue","Active Sensing", "NoteOn !","NoteOff !"'&#41;;
pThru &#58;= createParam&#40;'midi thru', ptSwitch&#41;; 
pNotesCount &#58;= createParam&#40;'open notes', ptDataField&#41;; setReadOnly&#40;pNotesCount,true&#41;; 
 setMin&#40;pNotesCount,0&#41;;setMax&#40;pNotesCount,999&#41;;

f_c1&#58;= 90099;f_c2&#58;= 60099;f_c3&#58;= 6666666;
 setColor&#40;pLimitHi,f_c1&#41;; setColor&#40;pLimitLo,f_c1&#41;;setColor&#40;pTransp,f_c1&#41;;setColor&#40;pStep,f_c1&#41;;
 setColor&#40;pWrap,f_c2&#41;;setColor&#40;pThru,f_c2&#41;;setColor&#40;pInv1,f_c2&#41;;setColor&#40;pInv2,f_c2&#41;;setColor&#40;pSwap,f_c2&#41;;
 //setColor&#40;pNotesCount,f_c3&#41;;

setIsInput&#40;pOut,false&#41;;
setIsInput&#40;NotesCount,false&#41;;
setIsOutput&#40;pIn,false&#41;;
setIsOutput&#40;pEvent,false&#41;;
setIsOutput&#40;pThru,false&#41;;
setIsOutput&#40;pDest,false&#41;;
setIsOutput&#40;pInv1,false&#41;;
setIsOutput&#40;pInv2,false&#41;;
setIsOutput&#40;pSwap,false&#41;;
setIsOutput&#40;pMult,false&#41;;//setIsOutput&#40;pMultSw,false&#41;;
setIsOutput&#40;pTransp,false&#41;;//setIsOutput&#40;pTranspSw,false&#41;;
setIsOutput&#40;pStep,false&#41;;//setIsOutput&#40;pStepSw,false&#41;;
setIsOutput&#40;pWrap,false&#41;;
setIsOutput&#40;pLimit,false&#41;;
setIsOutput&#40;pLimitLo,false&#41;;
setIsOutput&#40;pLimitHi,false&#41;;
setIsOutput&#40;pConv,false&#41;; 

setValue&#40;pEvent,1&#41;;  
setValue&#40;pDest,0&#41;; 
setValue&#40;pInv1,0&#41;;setValue&#40;pInv2,0&#41;;
setValue&#40;pMult,GetLength&#40;pMult&#41;-1&#41;;setDefaultValue&#40;pMult,0&#41;;
setValue&#40;pTransp,-128&#41;;
setValue&#40;pStep,1&#41;;   
setValue&#40;pWrap,0&#41;;
setValue&#40;pLimitLo,0&#41;;setValue&#40;pLimitHi,127&#41;; setValue&#40;pLimit,0&#41;;
setValue&#40;pConv,0&#41;;

setArrayLength&#40;mult, 16&#41;;     
setArrayLength&#40;notesList, 16&#41;;  
  FOR i &#58;= 0 TO 15 DO BEGIN   
      setArrayLength&#40;mult&#91;i&#93;, 128&#41;; // init &#91;16 channels&#93;&#91;128 multiply values&#93;
      SetArrayLength&#40;notesList&#91;i&#93;, 128&#41;;  
  END;
notesCount&#58;=0;

END; 

// <F> isMidiMsg&#58; 'event' is a list of pEvent &#40;0=ALL&#41;. filters sysex, clock and system messages
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isMidiMsg&#40;msg&#58; integer; e&#58; integer&#41;&#58; boolean;
BEGIN    
 IF      &#40;&#40;e=1&#41;OR&#40;e=0&#41;&#41; AND &#40;&#40;msg=144&#41;OR&#40;msg=128&#41;&#41; THEN BEGIN 
     result &#58;= true; END  // Notes
 ELSE IF &#40;&#40;e=2&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=176&#41; THEN BEGIN 
     result &#58;= true; END  //CtrlChg
 ELSE IF &#40;&#40;e=3&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=192&#41; THEN BEGIN 
     result &#58;= true; END  //PrgrChg
 ELSE IF &#40;&#40;e=4&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=224&#41; THEN BEGIN 
     result &#58;= true; END  //PitchBend
 ELSE IF &#40;&#40;e=5&#41;OR&#40;e=0&#41;&#41; AND &#40;&#40;msg=208&#41; OR &#40;msg=160&#41;&#41; THEN BEGIN 
     result &#58;= true; END  //Aftertouch &#40;Channel, Poly&#41;
 ELSE BEGIN
     result&#58;=false;
 END;
END;

// <F> setWrap&#58; wrap or limit byte range  
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION setWrap &#40;t&#58; integer; wrap&#58; boolean&#41;&#58; integer;   // 777777 rename 'setWrap' 
BEGIN 
 IF t < 0 THEN BEGIN t&#58;=t*&#40;-1&#41;; END;
 IF t > 127 THEN BEGIN   
     IF isWrap THEN BEGIN 
         result &#58;= round&#40;&#40;t+1&#41; MOD 128&#41;; // TEST 
     END 
     ELSE BEGIN 
         result&#58;= 127; 
     END;  
 END
 ELSE IF t < 0 THEN BEGIN  /// ADD for transpose!
 END 
 ELSE BEGIN 
     result&#58;=t; 
 END;  
END;

// &#58; setTransp&#58; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION setTransp&#40;val&#58; integer; trsp&#58; integer; wrap&#58; boolean&#41;&#58;integer;
BEGIN
    val&#58;=val+trsp;
    IF &#40;&#40;val>127&#41;OR&#40;val<0&#41;&#41; THEN BEGIN 
        IF isWrap THEN BEGIN
            IF val>127 THEN BEGIN 
                result&#58;=val-127; 
            END
            ELSE BEGIN 
                result&#58;=val+127;
            END;
        END
        ELSE BEGIN 
            IF val>127 THEN BEGIN 
               result&#58;=127; 
            END
            ELSE BEGIN // val<0
                result&#58;=0;
            END;
        END;
    END
    ELSE BEGIN 
        result&#58;=0; 
    END;
END;

// <F> calcLimited&#58; returns multiplication value for limiting, or return 1 &#40;x*1=x; x>0&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION calcLimited &#40;val&#58;integer; lo&#58;integer; hi&#58;integer; mode&#58;integer&#41;&#58;double; 
BEGIN
    IF mode=0 THEN BEGIN result&#58;=1 END
        //IF &#40;val<=hi&#41;AND&#40;val>=lo&#41; 
    ELSE IF mode=1 THEN BEGIN 
        result&#58;= &#40;hi-lo&#41;/128;  
        //result&#58;= &#40;lo + round&#40;val*r&#41; - 1&#41;; 	      
    END
    ELSE IF mode = 2 THEN BEGIN  
        // compress
    END
    ELSE BEGIN 
        result&#58;=1 
    END;
END; 

// <F> isStep&#58; step limit data&#58; filter out &#40;? or compress->max, or compress->min&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isStep&#40;val&#58; integer; stp&#58; integer&#41;&#58;boolean;
BEGIN
    IF &#40;&#40;val+1&#41; MOD stp=0&#41; THEN BEGIN
        result&#58;=true;
    END
    ELSE BEGIN
        result&#58;=false;
    END;
END;
// <F> convert
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
// setConvert&#58; &#40;why not convert to&#58; clock , start, stop, cont?&#41;
FUNCTION setConvert&#40;srcMsg&#58;byte;typeId&#58;integer&#41;&#58;byte;
BEGIN
&#40;*
IF = notes&#58; 
Note Legato","Note Poly &#40;mode1&#41;","Note Poly &#40;mode2&#41; 1-3; CC = 4
generate events! if replace with current, loose data...
Legato&#58; 
        if new event arrives, last event is closed&#58; 
        if not first event generate noteOff for the previous event
        structures&#58; noteConvertTmpMidi&#58;= tmp // just before FOR loop ends.
Mode1&#58;  if new event arrives, add_output noteOFF for oldest even noteOn, 
        or if it is the only note present. remove closed note from array
        structures&#58; event array&#58; boolean&#91;chn&#93;&#91;note&#93; for currently open notes  //
        ..already got this?

Mode2&#58;  if new event arrives, add_output noteOFF for oldest odd noteOn, 
        or if it there are only even notes. remove closed note from array
        -> even notes will endure until all odd notes are finished
*&#41;
    IF typeId=4 THEN BEGIN
        result&#58;=176; // CC
    END
    ELSE IF typeId=14 THEN BEGIN
        result&#58;=144; // leg play&#58; send noteOff Value if next noteOn value arrives tmp.Msg var holding last value
    END     
    ELSE IF typeId=5 THEN BEGIN
        result&#58;=192; // PC &#40;no 2nd byte&#41;
    END
    ELSE IF typeId=6 THEN BEGIN 
        result&#58;=224; // PitchBend &#40;Modwheel&#41;
    END
    ELSE IF typeId=7 THEN BEGIN
        result&#58;=208; // Aftert Channel
    END
    ELSE IF typeId=8 THEN BEGIN
        result&#58;=160; // Aftert Poly
    END
    ELSE BEGIN
        result&#58;=srcMsg;
    END; 
END;
&#40;*
// <F>getOpenNotes
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
FUNCTION getOpenNotes&#40;&#41;&#58;integer;
// global variables!!
BEGIN
      
     //boolNotesArray&#91;&#93;&#91;&#93;    
END; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
// <P> writeNoteOff&#58; for convert to Notes
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
PROCEDURE writeNoteOff;
// global variables!!
VAR extra&#58; TMidi;
BEGIN 
     extra.msg&#58;=byte&#40;128&#41;;
     extra.data1&#58;=tmp.data1;
     extra.data2&#58;=0;
     extra.channel&#58;=tmp.channel;
     // write out
     //setLength&#40;pOut&#41;&#58;= getLength&#40;pOut&#41;+1;
     // ?? TEST!! ?? setMidiArrayData&#40;pOut,trunc&#40;getLength&#40;pOut&#41;&#41;-1&#41;,extraMidi&#41;
     // remove from array
     //NotesArray&#91;aVal&#93;&#58;= false;
     //countNotes&#40;false&#41;; 
END; 
*&#41;
// <P> countNotes&#58;  
PROCEDURE countNotes&#40;isANoteAndON&#58;boolean&#41;;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
BEGIN   
    IF isANoteAndON THEN BEGIN 
        notesCount&#58;=notesCount+1         
    END
    ELSE BEGIN
        notesCount&#58;=notesCount-1;   
    END;   
    
END;

// <P> initLimitRange&#58; expect&#58; limitHi and limitLo are getValue&#40;p&#41; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE initLimitRange;
BEGIN 
      IF limitHi-limitLo< 0 THEN BEGIN  
          tmpLimitLo&#58;=limitLo;
          limitLo&#58;=limitHi;
          limitHi&#58;=tmpLimitLo 
      END
      ELSE IF limitHi-limitLo=0 THEN BEGIN
          IF limitHi=128 THEN BEGIN 
              limitLo&#58;=127; 
          END
          ELSE BEGIN
              limitHi&#58;=limitHi+1;
          END;
      END; 
END; 

// <P> setDataSymbols&#58; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE setDataSymbols;
VAR tr&#58; integer;
BEGIN                
    IF &#40;trunc&#40;getValue&#40;pStep&#41;&#41;<= 1&#41; THEN BEGIN 
        setSymbol&#40;pStep,''&#41;;setFormat&#40;pStep,'-bypass-'&#41;; 
    END 
    ELSE BEGIN  
        setSymbol&#40;pStep,'%'&#41;; setFormat&#40;pStep,'%.0f'&#41;
    END;
     

    tr&#58;=trunc&#40;getValue&#40;pTransp&#41;&#41;;
    IF tr>0 THEN BEGIN 
        setSymbol&#40;pTransp,'+'&#41;; setFormat&#40;pTransp,'%.0f'&#41;;  
    END
    ELSE IF  &#40;tr=&#40;-128&#41;&#41;OR&#40;tr=0&#41; THEN BEGIN 
        setSymbol&#40;pTransp,''&#41;; setFormat&#40;pTransp,'-bypass-'&#41;; 
    END
    ELSE BEGIN  
        setSymbol&#40;pTransp,''&#41;;setFormat&#40;pTransp,'%.0f'&#41;;  
    END;
 &#40;*   
    IF trunc&#40;getValue&#40;pLimitHi&#41;&#41; = 127 THEN BEGIN 
        setColor&#40;pLimitHi,81099&#41;;
    END 
    ELSE BEGIN 
        setColor&#40;pLimitHi,90099&#41;;
    END; 
    IF trunc&#40;getValue&#40;pLimitLo&#41;&#41; = 0 THEN BEGIN      
        setOffColor&#40;pLimitLo,90099&#41;;
    END 
    ELSE BEGIN 
       // setColor&#40;pLimitLo,90099&#41;;
    END; 
   *&#41;
    
END;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
   // main  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| 
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|
BEGIN   
   
   len &#58;= getLength&#40;pIn&#41;;
   lenCount&#58;= len;    
   IF len > 0 THEN BEGIN        
      multiply&#58;=pMultAr&#91;trunc&#40;getValue&#40;pMult&#41;&#41;&#93;;
      transpose&#58;= trunc&#40;getValue&#40;pTransp&#41;&#41;; 
      IF &#40;transpose=&#40;-128&#41;&#41; THEN BEGIN // control&#58; bypass at the left end for convenience
          transpose&#58;=0; 
      END;
      tmpEvent&#58;=trunc&#40;getValue&#40;pEvent&#41;&#41;;
      tmpDest&#58;=trunc&#40;getValue&#40;pDest&#41;&#41;;
      isFirstByte&#58;=&#40;tmpDest=2&#41;OR&#40;tmpDest=0&#41;;
      isSecondByte&#58;=&#40;tmpDest=2&#41;OR&#40;tmpDest=1&#41;;
      limitLo&#58;=trunc&#40;getValue&#40;pLimitLo&#41;&#41;;
      limitHi&#58;=trunc&#40;getValue&#40;pLimitHi&#41;&#41;;
      limit&#58;=trunc&#40;getValue&#40;pLimit&#41;&#41;;
      isLimit&#58;=&#40;limit>0&#41; AND &#40;&#40;limitLo>=1&#41;AND&#40;limitHi<=126&#41;&#41;;
      initLimitRange&#40;&#41;;
      convert&#58;=trunc&#40;getValue&#40;pConv&#41;&#41;;
      step&#58;=trunc&#40;getValue&#40;pStep&#41;&#41;;
      isStepActive&#58;=step>1;  
      isInv1&#58;=getValue&#40;pInv1&#41;>0; 
      isInv2&#58;=getValue&#40;pInv2&#41;>0;   
      isSwap&#58;=getValue&#40;pSwap&#41;>0;   
      isWrap&#58;=trunc&#40;getValue&#40;pWrap&#41;&#41;>0;
      isThru&#58;=trunc&#40;getValue&#40;pThru&#41;&#41;>0;
      FOR i &#58;= 0 TO &#40;len - 1&#41; DO BEGIN 
         getMidiArrayValue&#40;pIn, i, tmp&#41;;  
         IF isMidiMsg&#40;tmp.msg, tmpEvent&#41; THEN BEGIN  // process on IF. if pThru is 1, process on ELSE
             tmpMsg &#58;=tmp.msg;
             tmpX &#58;= tmp.data1;
             tmpY &#58;= tmp.data2;  
             tmpXX &#58;= tmpX; // store global for note off array
   
             IF isInv1 THEN BEGIN tmpX&#58;= 127 - tmpX;END;
             IF isInv2 THEN BEGIN tmpY&#58;= 127 - tmpY;END;             		 
             IF isSwap THEN BEGIN   
                 tmpX &#58;= tmpY;    
                 tmpY &#58;= tmpXX; 
             END;  
             
             // affect byte 1 
             IF isFirstByte THEN BEGIN   // 1st byte&#58; process 1st+2nd byte if tmpDest=2         
                 tmpX &#58;= trunc&#40;multiply*tmpX&#41; + &#40;transpose&#41;;
                 tmpX &#58;= setWrap&#40;tmpX, isWrap&#41;;
                 IF isLimit THEN BEGIN
                     tmpX &#58;= trunc&#40;tmpX * calcLimited&#40;tmpX,limitLo,limitHi,limit&#41;&#41;;
                 END;
                 tmp.data1 &#58;= byte&#40;tmpX&#41;;
                
             END; 
             // affect byte 2 
             IF isSecondByte THEN BEGIN    // 2nd byte&#58; process 1st+2nd byte if tmpDest=2  
                 tmpY &#58;= trunc&#40;multiply*tmpY&#41; + &#40;transpose&#41;;
                 tmpY &#58;= setWrap&#40;tmpY, isWrap&#41;;
                 IF isLimit THEN BEGIN 
                     tmpY &#58;= trunc&#40;tmpY * calcLimited&#40;tmpY,limitLo,limitHi,limit&#41;&#41;;
                 END;
                 tmp.data2 &#58;= byte&#40;tmpY&#41;;       		   
             END;    

             // affect msg&#58; convert event
             IF isConvert THEN BEGIN 
                  tmp.msg &#58;= setConvert&#40;tmp.msg,convert&#41;;
             END;
             isNoteOff&#58;= &#40;tmpMsg=128&#41; OR &#40;&#40;tmpMsg=144&#41;AND&#40;tmpY=0&#41;&#41;;
             isNoteOn &#58;= &#40;isNoteOff=false&#41;AND&#40;&#40;tmpMsg=144&#41;AND&#40;tmpY>0&#41;&#41;;   
                 // only when Notes are output
                 // prevent hanging notes &#40;tmpXX for swapped note values&#41;; ! if convert=>Notes&#58; 
             IF isNoteOn THEN BEGIN 
                 mult&#91;tmp.channel - 1&#93;&#91;tmpXX&#93; &#58;= tmp.data1;  // tmpXX&#40;old 1st byte&#41; needed for noteOff value  
                 IF notesList&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;=false THEN BEGIN
                     notesList&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;&#58;= true;
                     
                 END; 
                 //IF &#40;&#40;convert<=3&#41;AND&#40;convert>0&#41;&#41; THEN BEGIN 
                 //addToBoolNotes&#40;tmp.data1, tmp.channel, tmpXX&#41;; 
                // END
                 //ELSE BEGIN 
                     
                 //END;
                  
             END
             ELSE IF isNoteOff THEN BEGIN //  ! if convert=>Notes&#58;
                 tmp.data1 &#58;= mult&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;; // set NoteOff value from original NoteOn value
                 IF notesList&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;=true THEN BEGIN
                     notesList&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;&#58;=false;
                     
                 END; 
             END;
           
           IF  isFirstByte OR &#40;isFirstByte AND isSecondByte&#41; THEN BEGIN 
               filterByte&#58;= tmpX;
           END //&#40;tempDest=1&#41;
           ELSE BEGIN 
               filterByte&#58;= tmpY;
           END;
           IF &#40;&#40;limit=1&#41; AND &#40;&#40;limitLo>filterByte&#41; OR &#40;limitHi<filterByte&#41;&#41;&#41; OR
              &#40;isStepActive AND&#40;isStep&#40;filterByte,step&#41;=true&#41;&#41;
           THEN BEGIN  // filter message 
               lenCount&#58;=lenCount-1;
           END 
           ELSE BEGIN 
               IF isNoteOn THEN BEGIN 
                   countNotes&#40;true&#41;; 
               END
               ELSE IF isNoteOff THEN BEGIN 
                   countNotes&#40;false&#41;;
               END;       
               setLength&#40;pOut,lenCount&#41;; 
               setMidiArrayValue&#40;pOut, i, tmp&#41;;  // write modified message
           END;


           END   
           // ! isMidiMsg&#40;&#41;
           ELSE BEGIN 
                 IF isThru THEN BEGIN   
                    setMidiArrayValue&#40;pOut, i, tmp&#41;;  
                 END
                 ELSE BEGIN  
                    setLength&#40;pOut, 0&#41;; 
                 END;
            END;
         END;  // &#40;FOR i &#58;= 0 ..        
   END 
   ELSE BEGIN 
      setLength&#40;pOut, 0&#41;; 
   END; // len = 0 

setValue&#40;pNotesCount, notesCount&#41;;
setDataSymbols&#40;&#41;;
END.

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 04 Nov 2008, 10:44

Right now I can only confirm that the pIn is missing here as well. But what's with the (* and *)? Is it a form of multi-line comment I didn't know about? I've been using {$ and $} without any problems, but when I tried to use these instead in your script, it wouldn't compile. Strange...
Bjørn S

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 04 Nov 2008, 14:17

whaooo... incredible patch!

replace

Code: Select all

setIsInput&#40;NotesCount,false&#41;;
by
setIsInput&#40;pNotesCount,false&#41;;
it works
the parameter are in fact numbers which represent their ID
pIn = 0
pOut = 1
...
in the order of creation

for example

Code: Select all

setIsInput&#40;pIn,false&#41;;

is totally equivalent to 

setIsInput&#40;0,false&#41;;

amiga909
Member
Posts: 324
Contact:

Unread post by amiga909 » 04 Nov 2008, 15:55

thanks a lot senso. it worked.
great explanation too.


(* blabla *) multiline comment compiles here without any problems.

btw: tkx bsork, based on another post of you I have corrected the setLength(pOut, len) thing (output array will now get smaller when select input data is filtered)

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 04 Nov 2008, 20:10

wow, that's an amazing patch---thanks!

I used to have one of those yamaha boxes, it was awesome!

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

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 04 Nov 2008, 21:29

@amiga090
will you post it as add-on?

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 04 Nov 2008, 21:43

@senso+amiga909: Thanks guys, I learnt two new things from this thread!
Bjørn S

amiga909
Member
Posts: 324
Contact:

Unread post by amiga909 » 04 Nov 2008, 22:52

thanks for the kind words :)

its not a MEP-4 emulation, btw. its an experimental midi tool to learn the script language,
the only thing it has in common are most parameters and some of their ranges.
i try to avoid the hanging notes problem which the MEP-4 does not. on the other hand the MEP features channel filter/routing, mid delay, data presetting or stuff regarding its 4 ins and outs. personally I like to deal with channel filtering before or after a midi effect, midi delay already exists as a script and if you'd need 4in/outs you can use 4 instances of the script.
do you think if something essential from the MEP-4 is missing in the script?

guess i'll post a running beta with all features implemented here. to finish this script it will take some more time..

amiga909
Member
Posts: 324
Contact:

Unread post by amiga909 » 07 Nov 2008, 20:25

worked a bit on the script and still a lot to do.
the idea is to have a midi effect patch for live use. using midi effects live isnt exactly popular though.

trying it with vsti's bSorks noteoff solution works great, here from a first try.
http://thaumat.org/_permShare/mp3/mep.draft.t1.mp3
used: a piano roll with a drum pattern, ephonic drumatic , tpmusic t-pulse, and 2x mep script for each plugin.

amiga909
Member
Posts: 324
Contact:

Unread post by amiga909 » 12 Nov 2008, 15:35

here a release version of the script. will do some tests on it later and post it as addon.
changes:
- almost all algos replaced
- convert CC or PC to Notes
- removed functionality: compress note, convert midi message to notes (polyphonic)
- more demos: noteLegato.mp3 , noteLegato.stepMod.mp3 (LFO->+createMidi->MEP.script->T-Pulse VSTii)

Code: Select all

&#40;* 
no compress, no multinoteConvert

MEP 0.95 by amiga909
// 2008-10-29&#58; first version
// 2008-11-12&#58; release version
// credits to&#58; bSork, senso &#40;www.sensomusic.com/forums&#41;

// <Description> midi tool roughly inspired by Yamaha MEP-4 Midi Event Processor. 
    MEP was designed for experimental purposes but it can be also used as a midi utility. 
    download the original MEP-4 manual here&#58; 
    http&#58;//www2.yamaha.co.jp/manual/pdf/emi/english/synth/MEP4E.PDF 

// <Features> prevent hanging notes, swap data bytes, convert to notes, ..

// <Processing chain> 
    <input>    ->
    select     ->                        // filter input &#40;if midi thru on&#58; pass filtered data&#41;  
    swapBytes  -> inverse   ->           // modify input bytes
    expand     -> transpose ->           // calculate input bytes
    wrap       -> step&#40;x%y&#41; -> limit ->  // limit/rescale input bytes 
    affectByte ->                        // modify output bytes
    convert    ->                        // change output type
    <output>   <-

// <Parameters> 
// select event &#58; select an event type for processing &#40;if event type is NoteOn+Off and 
                  convert is not bypassed, NoteOff messages are filtered in some cases&#41;.  
// mute         &#58; filter selected event.  
// midi thru    &#58; output all other event types. 
// affect byte  &#58; process first or second data byte or both. if only one 
                  byte is selected, then the other byte is output unprocessed.
// inv. byte1/2 &#58; inverse incoming data byte. high value -> low, low -> high.
// swap bytes   &#58; swap first and second byte &#40;eg. convert velocity to noteOn&#41;.
// expand       &#58; choose a multiplication factor from 0.0625 to 16.
// transpose    &#58; add or subtract value.
// wrap around  &#58; if a value as a result of expanding or transposing is not between 1 and 128, 
                  and if wrap around is off&#58; result is 128 or 1, 
                  if wrap around is on&#58; &#40;1-1=128;128+1=1;&#41;.
// step         &#58; only messages with a data byte that is a multiple of the Step 
                  will be allowed through.
// limit low/hi &#58; specify the output data range.
                  use a range fader &#40;interface design&#41; for control.  
// limit mode   &#58; limit hard limits the output and filters values out of range, 
                  scale rescales to desired range.
// convert      &#58; transform input event to another midi message. 
                  &#40;mode 1&#58; convert to notes&#58; even events are noteOns, odd events are noteOffs
                  hanging notes; in contrary NoteOff! or NoteOn! create invalid midi notes&#41;.    
// <Notes>
   - Aftertouch, PC and other messages are not tested as much as Notes and CC
   - compress is very beta. maybe it will be removed... &#40;not original MEP anyway&#41;
   - the interface will maybe be reworked. there is the idea to have 8 toggle buttons that can each hold
     an operation parameter &#40;à la instajungle&#41;.

*&#41;

VAR  pIn, pOut, pMult, pEvent, pDest, pWrap, pInv1, pInv2, pTransp, pBypass, 
     pNotesCount, pThru, pConv, pStep, pLimitHi, pLimitLo, pLimit, pSwap    &#58; TParameter;

TYPE TMult    = ARRAY OF integer;
VAR  mult     &#58; ARRAY OF TMult;
VAR  pMultAr  &#58; ARRAY OF double; 
 
VAR  tmp      &#58; TMidi;   
VAR  multiply &#58; double;   

VAR  len,i,tmpX,tmpY,tmpXX,tmpYY,tmpMsg,dest,transpose,limit,convert,event,step,convCnt,
     limitLo,limitHi,tmpLimitLo, notesCount,filterByte,lenCount,lastConvNoteOn&#58; integer; 

VAR  isSwap, isWrap, isInv1, isInv2, isLimit, isConvNoteOff,
       isFirstByte, isSecondByte, isConvert, isConvertToNotes      &#58; boolean;

CONST NOTE_ON     = 144;
CONST NOTE_OFF    = 128;
CONST CONTROL_CHG = 176;
CONST PROGRAM_CHG = 192;
CONST PITCHBEND   = 224;
CONST AFTER_MONO  = 208;
CONST AFTER_POLY  = 160;
CONST MIDI_CLOCK  = 248;
CONST MIDI_START  = 250;
CONST MIDI_CONT   = 251;
CONST MIDI_STOP   = 252;
CONST ACTIVE_SENS = 254;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//           
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE Init;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
VAR f_c1,f_c2&#58; integer; 
BEGIN 
pIn &#58;= createParam&#40;'midi in', ptMidi&#41;;  
pOut &#58;= createParam&#40;'midi out', ptMidi&#41;; 
pEvent &#58;= createParam&#40;'select', ptListBox&#41;; 
  setListBoxString&#40;pEvent,
  '"ALL","Note On+Off", "Control Change", "Program Change", "Pitch Bend", "Aftertouch"'&#41;;         
pInv1 &#58;= createParam&#40;'inverse byte1', ptSwitch&#41;;      
pInv2 &#58;= createParam&#40;'inverse byte2', ptSwitch&#41;;     
pSwap &#58;= createParam&#40;'swap bytes', ptSwitch&#41;; 
pMult &#58;= createParam&#40;'expand', ptListBox&#41;; 
  setListBoxString&#40;pMult,
  '        "-bypass-", "1/16",  "1/8", "1/4", "1/2","1","2","4","8","16"'&#41;;
  pMultAr&#58;=&#91;1,          0.0625, 0.125,  0.25,  0.5,  1,  2,  4,  8,  16&#93;;       
pTransp &#58;= createParam&#40;'transpose',ptDataFader&#41;;setMin&#40;pTransp,-128&#41;;setMax&#40;pTransp,127&#41;; 
 setSymbol&#40;pTransp, ''&#41;;setFormat&#40;pTransp,'-bypass-'&#41;;  
pWrap &#58;= createParam&#40;'wrap around', ptSwitch&#41;;  
pStep &#58;= createParam&#40;'step modulo', ptDataFader&#41;;setMin&#40;pStep,1&#41;;setMax&#40;pStep, 16&#41;; 
  setSymbol&#40;pStep,''&#41;;setFormat&#40;pStep,'-bypass-'&#41;; 
pLimitLo &#58;= createParam&#40;'lo limit', ptMidiNoteFader&#41;; setMax&#40;pLimitLo, 126&#41;; setMin&#40;pLimitLo, 0&#41;;    
pLimitHi &#58;= createParam&#40;'hi limit', ptMidiNoteFader&#41;; setMin&#40;pLimitHi, 1&#41;;setMax&#40;pLimitHi, 127&#41;;   
pLimit &#58;= createParam&#40;'limit mode', ptListBox&#41;; 
  setListBoxString&#40;pLimit,'"-bypass-","filter","rescale","compress"'&#41;;// if compress&#58; faders = ratio, threshold
  setValue&#40;pLimit,1&#41;; setDefaultValue&#40;pLimit,0&#41;;
pDest &#58;= createParam&#40;'affect', ptListBox&#41;; 
  setListBoxString&#40;pDest,'"1st byte &#40;note,cc.num,..&#41;", "2nd byte &#40;velo,cc.val,..&#41;", "1st and 2nd byte"'&#41;;    
pConv &#58;= createParam&#40;'convert', ptListBox&#41;; // take all from 'Create Midi?'
  setListBoxString&#40;pConv,
  '"-bypass-","Note Legato","Note Poly &#40;mode1&#41;","Note Poly &#40;mode2&#41;","Note Poly &#40;random&#41;",'+
  '"Control Change","Program Change", "Pitch Bend","Aftertouch Channel","Aftertouch Poly",'+
  '"Timing Clock","Start","Stop","Continue","Active Sensing", "NoteOn !","NoteOff !"'&#41;;
pThru &#58;= createParam&#40;'midi thru', ptSwitch&#41;; 
pBypass &#58;= createParam&#40;'mute', ptSwitch&#41;; 
pNotesCount &#58;= createParam&#40;'open notes', ptDataField&#41;; setReadOnly&#40;pNotesCount,true&#41;; 
 setMin&#40;pNotesCount,0&#41;;setMax&#40;pNotesCount,999&#41;;

f_c1&#58;= 90099;f_c2&#58;= 60099; 
setColor&#40;pLimitHi,f_c1&#41;;setColor&#40;pLimitLo,f_c1&#41;;setColor&#40;pTransp,f_c1&#41;;setColor&#40;pThru,f_c2&#41;;
setColor&#40;pStep,f_c1&#41;;setColor&#40;pWrap,f_c2&#41;;setColor&#40;pInv1,f_c2&#41;;setColor&#40;pInv2,f_c2&#41;;setColor&#40;pSwap,f_c2&#41;;

setIsInput&#40;pOut,false&#41;;
setIsInput&#40;pNotesCount,false&#41;;
setIsOutput&#40;pIn,false&#41;;
setIsOutput&#40;pEvent,false&#41;;
setIsOutput&#40;pThru,false&#41;;
setIsOutput&#40;pDest,false&#41;;
setIsOutput&#40;pInv1,false&#41;;
setIsOutput&#40;pInv2,false&#41;;
setIsOutput&#40;pSwap,false&#41;;
setIsOutput&#40;pMult,false&#41;; 
setIsOutput&#40;pTransp,false&#41;; 
setIsOutput&#40;pStep,false&#41;; 
setIsOutput&#40;pWrap,false&#41;;
setIsOutput&#40;pLimit,false&#41;;
setIsOutput&#40;pLimitLo,false&#41;;
setIsOutput&#40;pLimitHi,false&#41;;
setIsOutput&#40;pConv,false&#41;; 
setIsOutput&#40;pBypass,false&#41;;
 

setValue&#40;pEvent,1&#41;;  
setValue&#40;pDest,0&#41;; 
setValue&#40;pInv1,0&#41;;setValue&#40;pInv2,0&#41;;
setValue&#40;pMult,GetLength&#40;pMult&#41;-1&#41;;setDefaultValue&#40;pMult,0&#41;;
setValue&#40;pTransp,-128&#41;;
setValue&#40;pStep,1&#41;;   
setValue&#40;pWrap,0&#41;;
setValue&#40;pLimitLo,0&#41;;setValue&#40;pLimitHi,127&#41;; setValue&#40;pLimit,0&#41;;
setValue&#40;pConv,0&#41;;

// array init
setArrayLength&#40;mult, 16&#41;;     
  FOR i &#58;= 0 TO 15 DO BEGIN   
      setArrayLength&#40;mult&#91;i&#93;, 128&#41;; // init &#91;16 channels&#93;&#91;128 multiply values&#93; 
  END;
notesCount&#58;=0;
convCnt&#58;=0;

END; 

//^^^^^^^^^^^^^^^^^^^^^^^<F>^^^^^^^^^^^^^^^^^^^^^//
// <F> isMidiMsg&#58; 'event' is a list of pEvent &#40;0=ALL&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isMidiMsg&#40;msg&#58; integer; e&#58; integer&#41;&#58; boolean;
BEGIN   
 IF      &#40;&#40;e=1&#41;OR&#40;e=0&#41;&#41; AND &#40;&#40;msg=NOTE_ON&#41;OR&#40;msg=NOTE_OFF&#41;&#41; THEN BEGIN 
     result &#58;= true; END  // Notes
 ELSE IF &#40;&#40;e=2&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=CONTROL_CHG&#41; THEN BEGIN 
     result &#58;= true; END  //CtrlChg
 ELSE IF &#40;&#40;e=3&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=PROGRAM_CHG&#41; THEN BEGIN
     result &#58;= true; END  //PrgrChg
 ELSE IF &#40;&#40;e=4&#41;OR&#40;e=0&#41;&#41; AND &#40;msg=PITCHBEND&#41; THEN BEGIN 
     result &#58;= true; END  //PitchBend
 ELSE IF &#40;&#40;e=5&#41;OR&#40;e=0&#41;&#41; AND &#40;&#40;msg=AFTER_MONO&#41; OR &#40;msg=AFTER_POLY&#41;&#41; THEN BEGIN 
     result &#58;= true; END  //Aftertouch &#40;Channel, Poly&#41;
 ELSE BEGIN
     result&#58;=false;
 END; 
END;

// <F> isStep&#58; step limit data&#58; filter out &#40;? or compress->max, or compress->min&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isStep&#40;val&#58; integer; stp&#58; integer&#41;&#58; boolean;
BEGIN
    IF NOT&#40;&#40;val+1&#41; MOD stp=0&#41; THEN BEGIN
        result&#58;=true;
    END
    ELSE BEGIN
        result&#58;=false;
    END;
END;

// <F> isNoteOn&#58;  
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isNoteOn&#40;message&#58; byte;velocity&#58; byte&#41;&#58; boolean;
BEGIN 
    IF &#40;message=NOTE_ON&#41;AND&#40;velocity>0&#41; THEN BEGIN 
        result&#58;=true;
    END
    ELSE BEGIN 
        result&#58;=false; 
    END;
END;

// <F> isNoteOff&#58;  
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION isNoteOff&#40;message&#58; byte;velocity&#58; byte&#41;&#58; boolean;
BEGIN  
    IF &#40;message=NOTE_OFF&#41;OR&#40;&#40;message=NOTE_ON&#41;AND&#40;velocity=0&#41;&#41; THEN BEGIN 
        result&#58;=true;
    END
    ELSE BEGIN 
        result&#58;=false;
    END;
END;

// <F> setWrap&#58; wrap or limit byte range  
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION setWrap &#40;t&#58; integer; wrap&#58; boolean&#41;&#58; integer;   // 777777 rename 'setWrap' 
BEGIN 
 IF isWrap THEN BEGIN 
    IF t<0 THEN BEGIN 
        result&#58;= 128 - &#40;&#40;t*-1&#41; MOD 128&#41;;         
    END 
    ELSE IF t>127 THEN BEGIN 
        result &#58;= t MOD 128;  
    END
    ELSE BEGIN 
        result&#58;=t;
    END;
 END
 ELSE BEGIN 
    IF t<0 THEN BEGIN 
        result&#58;=0;
    END 
    ELSE IF t>127 THEN BEGIN 
        result&#58;=127;
    END
    ELSE BEGIN 
        result&#58;=t;
    END;
 END;
END;
// &#58; setTransp&#58; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION setTransp&#40;val&#58; integer; trsp&#58; integer; wrap&#58; boolean&#41;&#58;integer;
BEGIN
    val&#58;=val+trsp;
    IF &#40;&#40;val>127&#41;OR&#40;val<0&#41;&#41; THEN BEGIN 
        IF isWrap THEN BEGIN
            IF val>127 THEN BEGIN 
                result&#58;=val-127; 
            END
            ELSE BEGIN 
                result&#58;=val+127;
            END;
        END
        ELSE BEGIN 
            IF val>127 THEN BEGIN 
               result&#58;=127; 
            END
            ELSE BEGIN // val<0
                result&#58;=0;
            END;
        END;
    END
    ELSE BEGIN 
        result&#58;=0; 
    END;
END;


// <F> convert&#58;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
// setConvert&#58; &#40;why not convert to&#58; clock , start, stop, cont?&#41;
FUNCTION setConvert&#40;srcMsg&#58; byte;typeId&#58; integer&#41;&#58; byte;
BEGIN
CASE typeId OF
      0&#58; result&#58;=srcMsg; // bypass
      1&#58; result&#58;=NOTE_ON; // NotesLegato
      2&#58; result&#58;=NOTE_ON; // NotesPoly1
      3&#58; result&#58;=NOTE_ON; // NotesPoly2
      4&#58; result&#58;=NOTE_ON; // NotesPoly rnd
      5&#58; result&#58;=CONTROL_CHG;  
      6&#58; result&#58;=PROGRAM_CHG; 
      7&#58; result&#58;=PITCHBEND; //&#40;Modwheel&#41;
      8&#58; result&#58;=AFTER_MONO; // Aftert Channel
      9&#58; result&#58;=AFTER_POLY; // Aftert Poly
     10&#58; result&#58;=MIDI_CLOCK;  
     11&#58; result&#58;=MIDI_START;  
     12&#58; result&#58;=MIDI_STOP; 
     13&#58; result&#58;=MIDI_CONT;  
     14&#58; result&#58;=ACTIVE_SENS; 
     15&#58; result&#58;=NOTE_ON; // NoteON ONLY!
     16&#58; result&#58;=NOTE_OFF; // NoteOFF ONLY!
   ELSE BEGIN
      result&#58;=srcMsg;
   END;
END;
END;

// <F> calcLimited&#58; returns multiplication value for limiting, or return 1 &#40;x*1=x; x>0&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
FUNCTION calcLimited &#40;val&#58; integer;lo&#58; integer;hi&#58; integer;mode&#58; integer&#41;&#58; integer; 
VAR r  &#58; double;  
BEGIN  //writeln&#40;'val&#58;'+inttostr&#40;val&#41;&#41;
    IF mode<=1 THEN BEGIN  // filter, bypass, not used here
        result&#58;=val; 
    END  
    ELSE IF mode=2 THEN BEGIN // scale
        r &#58;= 128/&#40;hi-lo&#41;;
        val&#58;= trunc&#40;&#40;val+1&#41;/r&#41;;
        result&#58;= val+lo;  	      
    END 
    ELSE BEGIN 
        result&#58;=val; 
    END;
END; 
   
//^^^^^^^^^^^^^^^^^^^^^^^<P>^^^^^^^^^^^^^^^^^^^^^//
// <P> countNotes&#58;  
PROCEDURE countNotes&#40;isANoteAndON&#58;boolean&#41;;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
BEGIN   
    IF isANoteAndON THEN BEGIN 
        notesCount&#58;=notesCount+1         
    END
    ELSE BEGIN
        notesCount&#58;=notesCount-1;   
    END;   
    
END;


// <P> convertToLegatoNotes&#58; isConvert AND isNoteOff=false &#40;dont process noteOff for eg. note->cc&#41;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE convertToLegatoNotes;
BEGIN   
  IF  convCnt MOD 2 = 1  THEN BEGIN  
        tmp.data1&#58;=byte&#40;lastConvNoteOn&#41;;
        tmp.msg&#58;=byte&#40;NOTE_OFF&#41;; 
    END
    ELSE BEGIN 
        lastConvNoteOn&#58;=tmp.data1;
        tmp.msg&#58;=byte&#40;NOTE_ON&#41;;  
    END;
    convCnt&#58;=convCnt+1; 
    IF convCnt=1028 THEN BEGIN convCnt&#58;=0; END;
END;

// <P> initLimitRange&#58; expect&#58; limitHi and limitLo are getValue&#40;p&#41; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE initLimitRange;
BEGIN 
 IF NOT&#40;limit=3&#41; THEN BEGIN  // if limit is compress&#58; thres/ratio fader functions
      IF limitHi-limitLo< 0 THEN BEGIN  
          tmpLimitLo&#58;=limitLo;
          limitLo&#58;=limitHi;
          limitHi&#58;=tmpLimitLo 
      END
      ELSE IF limitHi-limitLo=0 THEN BEGIN
          IF limitHi=128 THEN BEGIN 
              limitLo&#58;=127; 
          END
          ELSE BEGIN
              limitHi&#58;=limitHi+1;
          END;
      END;
 END; 
END; 
                           
// <P> setDataSymbols&#58; 
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 
PROCEDURE setDataSymbols;
VAR tr&#58; integer;
BEGIN              
    IF &#40;trunc&#40;getValue&#40;pStep&#41;&#41;<= 1&#41; THEN BEGIN 
        setSymbol&#40;pStep,''&#41;;setFormat&#40;pStep,'-bypass-'&#41;; 
    END 
    ELSE BEGIN  
        setSymbol&#40;pStep,'%'&#41;; setFormat&#40;pStep,'%.0f'&#41;
    END;
     
    tr&#58;=trunc&#40;getValue&#40;pTransp&#41;&#41;;
    IF tr>0 THEN BEGIN 
        setSymbol&#40;pTransp,'+'&#41;; setFormat&#40;pTransp,'%.0f'&#41;;  
    END
    ELSE IF &#40;tr=&#40;-128&#41;&#41;OR&#40;tr=0&#41; THEN BEGIN 
        setSymbol&#40;pTransp,''&#41;; setFormat&#40;pTransp,'-bypass-'&#41;; 
    END
    ELSE BEGIN  
        setSymbol&#40;pTransp,''&#41;;setFormat&#40;pTransp,'%.0f'&#41;;  
    END;    
END;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
   // main  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| 
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 
      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|
BEGIN   
   
   len &#58;= getLength&#40;pIn&#41;;
   lenCount&#58;= len;   
   
   IF len > 0 THEN BEGIN      
      multiply&#58;=pMultAr&#91;trunc&#40;getValue&#40;pMult&#41;&#41;&#93;;
      transpose&#58;= trunc&#40;getValue&#40;pTransp&#41;&#41;; 
      IF &#40;transpose=&#40;-128&#41;&#41; THEN BEGIN // control&#58; bypass at the left end for convenience
          transpose&#58;=0; 
      END;
      event&#58;=trunc&#40;getValue&#40;pEvent&#41;&#41;;
      dest&#58;=trunc&#40;getValue&#40;pDest&#41;&#41;;
      isFirstByte&#58;=&#40;dest=2&#41;OR&#40;dest=0&#41;; 
      isSecondByte&#58;=&#40;dest=2&#41;OR&#40;dest=1&#41;;
      limit&#58;=trunc&#40;getValue&#40;pLimit&#41;&#41;;
      limitLo&#58;=trunc&#40;getValue&#40;pLimitLo&#41;&#41;;
      limitHi&#58;=trunc&#40;getValue&#40;pLimitHi&#41;&#41;;      
      isLimit&#58;=&#40;limit>0&#41; AND &#40;&#40;limitLo>=1&#41;OR&#40;limitHi<=126&#41;&#41;; 
      initLimitRange&#40;&#41;;
      convert&#58;=trunc&#40;getValue&#40;pConv&#41;&#41;; 
      isConvert&#58;=convert>0;
      isConvertToNotes&#58;=convert=1;
      isConvNoteOff&#58;=false; 
      step&#58;=trunc&#40;getValue&#40;pStep&#41;&#41;; 
      isInv1&#58;=getValue&#40;pInv1&#41;>0; 
      isInv2&#58;=getValue&#40;pInv2&#41;>0;   
      isSwap&#58;=getValue&#40;pSwap&#41;>0;    
      isWrap&#58;=getValue&#40;pWrap&#41;>0;
      FOR i &#58;= 0 TO &#40;len - 1&#41; DO BEGIN 
         getMidiArrayValue&#40;pIn, i, tmp&#41;; 
         IF  &#40;getValue&#40;pBypass&#41;=0&#41; AND &#40;isMidiMsg&#40;tmp.msg,event&#41;&#41; THEN BEGIN   
             tmpMsg&#58;= tmp.msg;
             tmpX  &#58;= tmp.data1;
             tmpY  &#58;= tmp.data2;  
             tmpXX &#58;= tmpX; // store orig. val for noteList
             tmpYY &#58;= tmpY;
             IF isInv1 THEN BEGIN 
                tmpX&#58;= 127 - tmpX;
             END;
             IF isInv2 THEN BEGIN  
                 tmpY&#58;= 127 - tmpY;
             END;             		 
             IF isSwap THEN BEGIN   
                 tmpX &#58;= tmpY;    
                 tmpY &#58;= tmpXX;   
             END;         

             // affect byte 1 
             IF isFirstByte THEN BEGIN    // 1st byte&#58; process 1st+2nd byte if dest=2 
                 tmpX &#58;= trunc&#40;multiply*tmpX&#41;;
                 tmpX &#58;= tmpX + &#40;transpose&#41;;
                 tmpX &#58;= setWrap&#40;tmpX, isWrap&#41;; // wrap or hard limit 
                 IF isLimit THEN BEGIN
                     tmpX &#58;= calcLimited&#40;tmpX,limitLo,limitHi,limit&#41;;
                 END; 
                 tmp.data1 &#58;= byte&#40;tmpX&#41;;   
             END; 
             // affect byte 2 
             IF isSecondByte THEN BEGIN   
                 tmpY &#58;= trunc&#40;multiply*tmpY&#41;;
                 tmpY &#58;= tmpY + &#40;transpose&#41;;
                 tmpY &#58;= setWrap&#40;tmpY, isWrap&#41;; // wrap or hard limit 
                 IF isLimit THEN BEGIN
                     tmpY &#58;= calcLimited&#40;tmpY,limitLo,limitHi,limit&#41;;
                 END; 
                 tmp.data2 &#58;= byte&#40;tmpY&#41;;       		   
             END; 
 
             // prevent hanging notes &#40;tmpXX for swapped note values&#41;
             IF isNoteOn&#40;tmpMsg,tmpYY&#41; THEN BEGIN  
                   mult&#91;tmp.channel - 1&#93;&#91;tmpXX&#93; &#58;= tmp.data1;  // tmpXX&#40;old 1st byte&#41; needed for noteOff value              
             END
             ELSE IF &#40;&#40;isConvertToNotes=false&#41; AND &#40;isNoteOff&#40;tmpMsg,tmpYY&#41;=true&#41;&#41; THEN BEGIN //! if convert=>Notes&#58;
                   tmp.data1 &#58;= mult&#91;tmp.channel - 1&#93;&#91;tmpXX&#93;; // set NoteOff value from original NoteOn value
             END;

             // affect msg&#58; convert event
             IF isConvert THEN BEGIN  
                     IF isConvertToNotes THEN BEGIN 
                         convertToLegatoNotes&#40;&#41;; 
                     END  
                     ELSE BEGIN // isConvertToNotes=false 
                         IF isNoteOff&#40;tmpMsg,tmpYY&#41;=true THEN BEGIN 
                             isConvNoteOff&#58;=true;  // filter flag for output
                         END 
                         ELSE BEGIN 
                             tmp.msg&#58;=setConvert&#40;tmpMsg, convert&#41;;
                         END;
                     END;      
             END;

             IF  isFirstByte OR &#40;isFirstByte AND isSecondByte&#41; THEN BEGIN 
                 filterByte&#58;= tmpX;
             END  
             ELSE BEGIN 
                 filterByte&#58;= tmpY;
             END;
             IF  &#40;isConvNoteOff&#41; OR    // if convert to notes dont convert noteOff
                 &#40;&#40;limit=1&#41;AND&#40;limitLo>filterByte&#41;&#41; OR &#40;limitHi<filterByte&#41;  OR 
                 &#40;step>1&#41;AND&#40;isStep&#40;filterByte,step&#41;&#41;   THEN BEGIN  // filter message 
                 lenCount&#58;=lenCount-1;
             END 
             ELSE BEGIN  
               IF isNoteOn&#40;tmp.msg,tmp.data2&#41; THEN BEGIN 
                   countNotes&#40;true&#41;;
               END
               ELSE IF isNoteOff&#40;tmp.msg,tmp.data2&#41; THEN BEGIN 
                   countNotes&#40;false&#41;;
               END;       
               setLength&#40;pOut,lenCount&#41;;  
               setMidiArrayValue&#40;pOut, i, tmp&#41;;  // write modified message
             END;  

            END    
            // ! isMidiMsg&#40;&#41;
            ELSE BEGIN 
                 IF &#40;getValue&#40;pThru&#41;>0&#41; THEN BEGIN   
                    setMidiArrayValue&#40;pOut, i, tmp&#41;;  
                 END
                 ELSE BEGIN  
                    setLength&#40;pOut, 0&#41;; 
                 END;
            END;
        END;  // &#40;FOR i &#58;= 0 ..        
   END 
   ELSE BEGIN 
      setLength&#40;pOut, 0&#41;; 
   END; // len = 0 

setValue&#40;pNotesCount, notesCount&#41;;
setDataSymbols&#40;&#41;;

END.

Post Reply

Who is online

Users browsing this forum: No registered users and 87 guests