Implementing bidirectional MIDI with scripting

So I know we don’t yet have the ability to handle bidirectional MIDI (it’s on our list) but there is a way to do it with scripting. I have a MIDI Fighter Twister (look it up if you’re not familiar, it’s a nice controller) which has endless knobs. You can have widgets learn the knobs with no problem but right now, you can’t update the Twister knobs from widgets.

However, if you use the following script in your rackspace you can :slight_smile:
In this example, I’m assuming you have (a) created a MIDI Out Block that’s associated with your MIDI Twister (or whatever controller you have where you want this trick to work) and (b) you have created some widgets and given them script names K1, K2, K3 and K4

var
   TTT : MidiOutBlock // You need a MIDI out block associated with the MIDI device of your Twister

 
// Send MIDI value out to twister based on position of a widget
function UpdateTwisterWithValue(ccNumber : integer, widgetValue : double)
var
   cc : ControlChangeMessage
   value : integer

   value = Round(widgetValue * 127) // Convert widget value between 0 and 1 to a MIDI value between 0 and 127

   cc = MakeControlChangeMessage(ccNumber, value);
   TTT.SendNowExternal(cc);
end

// Ultimately these will get declared automatically
// For now, assuming you have four knobs with script names K1, K2,K3,K4 define them here
var
   K1 : Widget
   K2 : Widget
   K3 : Widget
   K4 : Widget

On WidgetValueChange(newValue : double) from K1
   UpdateTwisterWithValue(71, newValue)  // 71 is CC value for K1
end

On WidgetValueChange(newValue : double) from K2
   UpdateTwisterWithValue(1, newValue)  // 71 is CC value for K1
end

On WidgetValueChange(newValue : double) from K3
   UpdateTwisterWithValue(2, newValue)  // 71 is CC value for K1
end

On WidgetValueChange(newValue : double) from K4
   UpdateTwisterWithValue(3, newValue)  // 71 is CC value for K1
end

function UpdateTwisterOnActivate(w : Widget, ccNumber : integer)
var v : integer;
    cc : ControlChangeMessage;

     v = Round( w.GetWidgetValue() * 127);
     cc = MakeControlChangeMessage(ccNumber, v);
     TTT.SendNowExternal(cc);
end

On Activate
   // Get the current widget value when we open this rackspace and set twister
   UpdateTwisterOnActivate(K1, 71);
   UpdateTwisterOnActivate(K2, 1);
   UpdateTwisterOnActivate(K3, 2);
   UpdateTwisterOnActivate(K4, 3);

end

This looks very useful. I use a Novation Zero SL MkII for sending Panic message and controlling the B5 drawbars. I will give this a try with the rotary encoders and switches. I particularly like the OnActivate function.

Hey that looks promising, will test that with my S88 controller from Native instruments.

Very powerful script! I’ll adapt now to my x-touch mini…

One more request: could it be possible to have some “global variables”? I’ll try explain my use case ant the request…

  • I find that instruments playability derive from translating interaction between hardware (keyboard controller, midi controller, pedal) and software in a CONSISTENT and continuous way (if I play a real hammond the volume/expression is a defined value that is mantained if I “play with drawbars” for example…)
  • a midi fighter twister (or a x-touch mini) is a fully “dual-way” controller (value can be sent from the controller, and controller can receive value and adapt/show the new value) --> this script get all things done and give consistency between value shown and value used
  • I now think a “hardware with no return possible” controller, eg a footpedal for expression/volume (connected to a keyboard)… in that case I can change expression/volume (for example say I set to 64, 50% of value), I change my rack/variations, and I would like to have 2 choice…
    1. use the value saved in the widget (and that is possible with “recall on load / recall on activate”)
    2. OVERRIDE SAVED VALUE in the widget (with same/consistent name) contained in the newly selected rack/variation with THE ACTUAL GLOBAL VALUE (last one received from the controller)

I think it could be achieved with a “global variable” that can be saved globally…

MAYBE it is possible doing so with 2.0.4b (…and I’ve failed to realize with my demo scripts…)

Obviously I think it could be done at higher level in RIG configuration, defining a property for each defined Midi Control that say “override saved value with last received value”… but also scripting is a solution…

By the way… ROCK SOLID beta!!! …I’ve added more VST in my home setup and NO PROBLEM arises…

Global variables? Where, in the scripting language? Or global variables across all rackspaces?

The former already exists - just declare a variable outside of a function or callback

The latter is on my list!

Yes I intended across all rackspaces… because, if I’ve correctly understood, a script live in a single rackspace and so the “script-global-variable” live only inside the scope of that rackspace.

But it would be useful also to have some “globally global” variable… so to use in ALL script defined for ALL rackspaces to implement persistence of some important parameters…

This would be useful because I’ve tested now on 2.0.4b that script ARE ALREADY duplicated with rackspaces duplication… so a “global-global” variable implementation of values persistence is quite simple to achieve…

Good to know is in the list!!!