Welcome to %s forums

BrainModular Users Forum

Login Register

Selecting from multiple VSTi? (choosing MIDI signal destination)

I need help on a Patch
Post Reply
Ben J
New member
Posts: 9
Contact:

Unread post by Ben J » 17 Apr 2010, 09:36

I've been playing with Usine for a few weeks now, and I'm a little more comfortable with the program, but I still can't build the setup I envision.

I play keyboards in a band (so I have no need for real-time recording or sampling stuff), I just need to be able to switch between VST instruments and occasionally select various presets within those VSTi. Basically, I want the functionality of pressing a single interface button to call up the [pre-loaded] VST.

Originally I built a workspace to where each VST was on a separate MIDI channel, and I simply changed patches by changing MIDI channels. However, this limited me to only 16 patches.

Most recently, I tried using emoon's MondoCombo, which works great for selecting presets within a single VST, but I can't figure out how to integrate it with several different VSTi.

I suppose another approach would be to solo/mute all other VST, although my understanding is that might have higher CPU usage...

Can any of you programming geniuses help me? Thanks for all your help thus far! :)

User avatar
nay-seven
Site Admin
Posts: 5684
Location: rennes France
Contact:

Unread post by nay-seven » 17 Apr 2010, 10:58

here an idea :
the low part let you dispatch the midi flow to different midi bus
the hight part, in the same time, active or not your different patches ( each vsti can be in different tracks or on the same ( mode all )
the right part show you the patch for each vsti
Image

gurulogic
Member
Posts: 1019
Contact:

Unread post by gurulogic » 17 Apr 2010, 11:10

Another idea...
There are many ways to accomplish what you are looking to do but I would have to say this is the absolute simplest example.
The preset manager will store and recall the states of the VST's, so you do not necessarily even need a way to change VST patches, and the preset manager will also store and recall rge bypass buttons for each VST.
All you have to do here is select which VST you want active, edit or load the VST patch as desired and then store a preset.
When you recall the preset manager preset via the combobox, you are ready to play!

Image

Ben J
New member
Posts: 9
Contact:

Unread post by Ben J » 18 Apr 2010, 07:06

Thanks guys!

I'm well on my way to creating my perfect live template.

woodslanding
Member
Posts: 1327
Contact:

Unread post by woodslanding » 19 Apr 2010, 00:16

Here is the latest version of my midi processing script, which you might find useful.... It gives control over transposition, noterange, etc, so it functions like a master keyboard:

Code: Select all

(*/////////////////////////////////////////////////////
// CHANNEL  
// Version 2010-03-28; author: eric moon
//
// based on work by Bsork and amiga909
//////////////////////////////////////////////////////
*)

//  MIDI Channel Strip:
//  it is designed to function as part of a mixer channel strip, running between several keyboards and a vsti.

//   takes a number of midi inputs (on separate cables, for visual clarity)
//  and performs the following operations on each.
//  enable, disable--per input
//  strip CCs and send them out a separate output
//  limit to minimum and maximum notes--one range affects all inputs
//  transpose--again, one range for all inputs.
//  output rechannelizing--all outs are a single channel.  Use multiple strips to control multi-timbral modules.
//  bypass output for turning off unused instruments.  waits for all notes to be released....
//  Drone switch that keeps current notes sounding, but discards all note input as long as it is held

//  Midi learn for note range:
//  When learn is turned on, midi note output is suspended
//   the first noteNumber sets the low end of the range, the second noteNumber sets the upper limit.
//   once both notes are sent, notes go to main output  as usual.
//   support for inverse range, if low note is above high note

CONST INPUT_COUNT = 2;  // could handle any number, I think!

CONST NOTEON        = Byte(144);	
CONST NOTEOFF       = Byte(128);
CONST CONTROL       = Byte(176);	
CONST PITCHBEND     = Byte(224);
CONST AFTERTOUCH    = Byte(208);

VAR   heldNotes                    : ARRAY OF boolean;
VAR   transList                    : ARRAY OF integer; 
VAR   isEnabled                    : Array of boolean;
VAR   pMidiINS,pEnableINS          : ARRAY OF TParameter;
VAR   midiInCounts                 : ARRAY OF integer;

VAR   pTransposeIN, pDroneIN,pOutChanIN, pLearnIN, pLowNoteIn, pHiNoteIn        : TParameter;       
VAR   pPassOut,pRejectOut,pBypassOut, pLowNoteOut, pHiNoteOut                   : Tparameter;       
VAR   transpose, hiVal, lowVal                                                  : integer; 
VAR   passCount, rejectCount, learnCount, minKey, maxKey, outChan               : integer;
VAR   isLearning, isDroning, doRelease, bypassReady               : boolean;

///////////////////////////      INITIALIZE        /////////////////////////////////////
PROCEDURE init; 
VAR i : integer;   
BEGIN  

    transpose := 0; hiVal:= 120; lowVal := 12;
    passCount := 0; rejectCount := 0; learnCount := 0; minKey := 128; maxKey := 0; outChan := 1;
    isLearning := FALSE; isDroning := FALSE; doRelease := FALSE; bypassReady := FALSE;    

    setArrayLength(pMidiINS, INPUT_COUNT);
    setArrayLength(pEnableINS, INPUT_COUNT);
    setArrayLength(isEnabled, INPUT_COUNT);
    setArrayLength(midiInCounts, INPUT_COUNT);   FOR i:=0 TO INPUT_COUNT   DO midiInCounts[i]:=0;
    setArrayLength(heldNotes, 128);               FOR i:=0 TO 127           DO heldNotes[i]:=FALSE;
    SetArrayLength(transList, 128);              FOR i:=0 TO 127           DO transList[i]:=0;    

    FOR i := 0 TO INPUT_COUNT - 1 DO  BEGIN
        pEnableINS[i]  := CreateParam('enable ' + intToStr(i + 1),ptSwitch);        
        SetIsOutPut(pEnableINS[i],false);        
    END;
    
    pBypassOut       := CreateParam('inst bypass', ptSwitch);       SetIsInput(pBypassOut,false);    
    pTransposeIN     := CreateParam('Transpose',ptDataFader);       SetIsOutPut(pTransposeIN,false);
    pOutChanIN       := CreateParam('out ch',ptMidiNoteFader);      SetIsOutPut(pOutChanIN,false);
    pLearnIN         := CreateParam('learn',ptButton);              SetIsOutPut(pLearnIN,false);
    pHiNoteIN        := CreateParam('high note',ptMidiNoteFader);   SetIsOutPut(pHiNoteIN,false);
    pHiNoteOUT        := CreateParam('hi note', ptDataField);         SetIsInPut(pHiNoteOut,false); 
    pLowNoteIN       := CreateParam('low note',ptMidiNoteFader);    SetIsOutPut(pLowNoteIN,false);
    pLowNoteOUT       := CreateParam('low note',ptDataField);         SetIsInPut(pLowNoteOut,false);
    pDroneIN         := CreateParam('drone', ptSwitch);             SetIsOutput(pDroneIN,false);  
     
    SetFormat(pTransposeIN,'%.0f');    SetMin(pTransposeIN,-48);  SetMax(pTransposeIN,48);
    SetFormat(pOutChanIN,'%.0f');   SetMin(pOutChanIN,1);  SetMax(pOutChanIN,16);   
    
    FOR i := 0 TO INPUT_COUNT - 1 DO  BEGIN
        pMidiINS[i]  := CreateParam('MIDIin ' + intToStr(i + 1) ,ptMidi);       
        SetIsOutPut(pMidiINS[i],false);
    END;
    
    pPassOut          := CreateParam('passed MIDI',ptMidi);           SetIsInput(pPassOut,false);  
    pRejectOut        := CreateParam('rejected MIDI',ptMidi);         SetIsInput(pRejectOut,false);

END;   
///////////////////////////  MIDI OUTPUT METHODS   ////////////////////////////////////

PROCEDURE PassOut(midi : tMidi);
BEGIN
   midi.channel := BYTE(outChan);
   SetMidiArrayValue(pPassOut, passCount, midi);
   passCount := passCount + 1;
END;

PROCEDURE RejectOut(midi : tMidi);
BEGIN
   midi.channel := BYTE(outChan);
   SetMidiArrayValue(pRejectOut, rejectCount, midi);
   rejectCount := rejectCount + 1;
END;


/////////////////////////   MIDI MESSAGE TESTS  ///////////////////////////////////////

FUNCTION IsNote (midi : tMidi) : Boolean;
BEGIN
   IsNote := ((midi.msg = NOTEON) OR (midi.msg = NOTEOFF));
END;

FUNCTION IsNoteOn (midi : tMidi) : Boolean;
BEGIN
   IsNoteOn := ((midi.msg = NOTEON) AND (midi.data2 > 0));
END;

FUNCTION IsNoteOff (midi : tMidi) : Boolean;
BEGIN
   IsNoteOff := (midi.msg = NOTEOFF) OR ((midi.msg = NOTEON) AND (midi.data2 = 0));
END;


//////////////////////////      OTHER TESTS     ////////////////////////////////////////

FUNCTION UpdateBypass()  :  INTEGER;
VAR i  : integer;
BEGIN 
    bypassReady := TRUE;  
    FOR i := 0 to (INPUT_COUNT - 1) DO BEGIN
        if isEnabled[i] THEN BEGIN
            bypassReady := FALSE;
            setValue(pBypassOut, 0);
        END;
    END;
    IF bypassReady AND isClear() THEN setValue(pBypassOUT, 1);       
END; 

FUNCTION isInRange(noteNumber : integer ) : Boolean;
VAR inRange : Boolean;
VAR reversed : Boolean;
BEGIN
    reversed := (lowVal >= hiVal);
    IF reversed THEN isInRange &#58;= &#40;noteNumber < hiVal&#41;  OR  &#40;noteNumber > lowVal&#41;
                ELSE isInRange &#58;= &#40;noteNumber <= hiVal&#41; AND &#40;noteNumber >= lowVal&#41;; 
END;


////////////////////////       SETTERS       ////////////////////////////////////////////



PROCEDURE SetLowVal&#40;n &#58; integer&#41;;
BEGIN
    setValue&#40;pLowNoteOut, n&#41;;
    lowVal &#58;= n;
END;

PROCEDURE SetHiVal&#40;n &#58; integer&#41;;
BEGIN
    setValue&#40;pHiNoteOut, n&#41;;
    hiVal &#58;= n;
END;

////////////////////////     PROCESS MIDI    ////////////////////////////////////////////
FUNCTION bstr&#40;b &#58; boolean&#41; &#58; string;
BEGIN if b THEN bstr &#58;= 'TRUE' else bstr &#58;= 'FALSE'; END;

PROCEDURE ProcessMidi&#40;midi &#58; tMidi; enabled &#58; boolean&#41;;
BEGIN
    IF isLearning THEN processLearn&#40;midi&#41; 
    ELSE IF not&#40;isDroning&#41; THEN BEGIN
          
        // pass PB and AT with notes
        IF &#40;midi.msg = PITCHBEND&#41; OR &#40;midi.msg = AFTERTOUCH&#41; THEN passOut&#40;midi&#41;
        ELSE IF NOT&#40;IsNote&#40;midi&#41;&#41; THEN rejectOut&#40;midi&#41;
        // everything else deals with note data....
        ELSE IF IsInRange&#40;midi.data1&#41;and enabled THEN BEGIN
            IF isNoteOn&#40;midi&#41; THEN BEGIN
                ProcessNoteOn&#40;midi, enabled&#41;;
            END ELSE BEGIN       
                ProcessNoteOff&#40;midi&#41;
            END;
        END ELSE rejectOut&#40;midi&#41;; //notes that are out of range
        IF doRelease THEN sendNoteOffs&#40;false&#41;;
    END;  
END;

PROCEDURE ProcessLearn&#40;midi &#58; tMidi&#41;;
BEGIN
    IF &#40;isNoteOn&#40;midi&#41;&#41; and &#40;learnCount = 0&#41; THEN BEGIN
        lowVal &#58;= midi.data1;
        setValue&#40;pLowNoteOUT, lowVal&#41;;
        learnCount &#58;= 1;                   
    END 
    ELSE IF &#40;isNoteOn&#40;midi&#41;&#41; and &#40;learnCount = 1&#41;  THEN BEGIN
        hiVal &#58;= midi.data1;
        setValue&#40;pHiNoteOUT, hiVal&#41;;
        learnCount &#58;= 0;
        isLearning &#58;= FALSE;  // we've set our outs....
    END;
END;

PROCEDURE ProcessNoteOn&#40;midi &#58; tMidi; enabled &#58; boolean&#41;;
BEGIN
    IF enabled THEN BEGIN
        transList&#91;midi.data1&#93; &#58;= transpose; 
        midi.data1 &#58;= midi.data1 + transpose;
        PassOut&#40;midi&#41;;
        heldNotes&#91;midi.data1&#93; &#58;= TRUE;
        IF &#40;midi.data1 > maxKey&#41; THEN maxKey &#58;= midi.data1;
        IF &#40;midi.data1 < minKey&#41; THEN minKey &#58;= midi.data1;
    END;
END;

PROCEDURE ProcessNoteOff&#40;midi &#58; Tmidi&#41;;
BEGIN
    midi.data1 &#58;= midi.data1 + transList&#91;midi.data1&#93;;
    heldNotes&#91;midi.data1&#93; &#58;= FALSE;
    PassOut&#40;midi&#41;;
    IF bypassReady AND isClear&#40;&#41; THEN  BEGIN
        setValue&#40;pBypassOut, 1&#41;;
        isDroning &#58;= FALSE;
        bypassReady &#58;= FALSE;
    END;
END;


PROCEDURE ProcessDrone&#40;n &#58; integer&#41;;
BEGIN
    IF n = 0 THEN SendNoteOffs&#40;TRUE&#41;;
    isDroning &#58;= n > 0;   
END;

FUNCTION isClear&#40;&#41; &#58; boolean;
VAR key &#58; integer; 
VAR clear &#58; boolean;
BEGIN
    clear &#58;= TRUE;
    FOR key&#58;= minKey TO maxKey DO IF heldNotes&#91;key&#93; = TRUE THEN clear &#58;= FALSE;
    isClear &#58;= clear;
END;

PROCEDURE SendNoteOffs&#40;closeAll &#58; boolean&#41;;
VAR key &#58; integer;
VAR midi &#58; tMidi;
BEGIN
    FOR key&#58;= minKey TO maxKey DO BEGIN    
        IF &#40;heldNotes&#91;key&#93; = FALSE&#41; OR closeAll THEN BEGIN 
            midi.msg &#58;= NOTEOFF;
            midi.channel &#58;= Byte&#40;outChan&#41;;
            midi.data1 &#58;= key;
            midi.data2 &#58;= 0;
            passOut&#40;midi&#41;;
            heldNotes&#91;key&#93; &#58;= FALSE;
        END;                                                          
    END; 
    doRelease &#58;= FALSE;
END;

////////////////////////       CALLBACK      /////////////////////////////////////////////

PROCEDURE Callback&#40;n&#58; integer&#41;;
VAR i &#58; integer;

BEGIN


    FOR i &#58;= 0 to INPUT_COUNT - 1 DO BEGIN
        CASE n OF 
            pEnableINS&#91;i&#93; &#58;  BEGIN
                                 isEnabled&#91;i&#93; &#58;= getValue&#40;n&#41; > 0;
                                 UpdateBypass&#40;&#41;;
                             END;   
            pMidiINS&#91;i&#93;   &#58;  midiInCounts&#91;i&#93; &#58;= GetLength&#40;n&#41;;
        END;
    END;
    
    CASE n OF
        pLearnIN      &#58;     isLearning     &#58;= TRUE;        
        pOutChanIN    &#58;     outChan        &#58;= Byte&#40;trunc&#40;getValue&#40;n&#41;&#41;&#41;;
        pTransposeIN  &#58;     transpose      &#58;= &#40;trunc&#40;getValue&#40;n&#41;&#41;&#41;; 
        pHiNoteIN     &#58;     setHiVal&#40;trunc&#40;getValue&#40;n&#41;&#41;&#41;;
        pLowNoteIN    &#58;     setLowVal&#40;trunc&#40;getValue&#40;n&#41;&#41;&#41;;        
        pDroneIN      &#58;     ProcessDrone&#40;trunc&#40;getValue&#40;n&#41;&#41;&#41;;    
        
    END;
END;

/////////////////////////      PROCESS        //////////////////////////////////////////

PROCEDURE Process;
VAR i, inputNum &#58; Integer;
VAR currMsg     &#58; tMidi;
BEGIN
    FOR inputNum &#58;= 0 TO &#40;INPUT_COUNT - 1&#41; DO BEGIN
            FOR i &#58;= 0 TO &#40;midiInCounts&#91;inputNum&#93; - 1&#41; DO BEGIN
                GetMidiArrayValue&#40;pMidiINS&#91;inputNum&#93;, i, currMsg&#41;;
                ProcessMidi&#40;currMsg, isEnabled&#91;inputNum&#93;&#41;;
            END;
    END;
    SetLength&#40;pPassOut, passCount&#41;;
    SetLength&#40;pRejectOut, rejectCount&#41;;
    passCount   &#58;= 0;
    rejectCount &#58;= 0;
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 » 19 Apr 2010, 01:50

I uploaded this script to the addons. I also updated another patch-change widget which I am using now instead of mondo combo.

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

Ander
New member
Posts: 9
Contact:

Unread post by Ander » 25 Sep 2018, 02:11

Hi, I just tryed this script on Usine Hollodeck 3 and can't compile it.

I rearranged procedures order to avoid compiler errors but finally an assignation error crashes the compiler.

I looked on addons but the Midi Channel Strip is not included.

I studied Pascal language about 15 years ago, but I don't remember enough to modify or rewrite the script now.

Anyone have a fast way to filter midi IN and route only a range of notes to a VSTi?

User avatar
x.iso
Member
Posts: 565
Location: RU, Saint-Petersburg
Contact:

Unread post by x.iso » 25 Sep 2018, 11:29

There is a patch in add-ons for filtering certain octaves and/or transposing them, but generally you can just use MIDI filter module and set > module that triggers flow pass if note message is above or below desired, use two of these to set a range from lower and upper values. at least I think that should do the job.
join Hollyhock Usine Discord server: https://discord.gg/EdJarnE

User avatar
nay-seven
Site Admin
Posts: 5684
Location: rennes France
Contact:

Unread post by nay-seven » 27 Sep 2018, 08:41

there 's also the MIDI split module in multi mode ?

Ander
New member
Posts: 9
Contact:

Unread post by Ander » 27 Sep 2018, 13:02

The MIDI Split module works, but it also filters all the other MIDI messages.

With some filtering and merging I solve the key range split.

I created a new thread were I will share my advances.

Post Reply

Who is online

Users browsing this forum: No registered users and 20 guests