Midi Out From Gig File, Scriptlet or Global Rackspace

In the way you describe, that would be a wishlist item.

Are you a Mac or Windows user? I’ve done a basic test on Mac and think it should work…

There could be an option of handling this completely in the Gig script if your widgets are mapped to a virtual midi port (with the Sync option enabled).

  • When the incoming message is received from the fcb1010, the gig script should insert this (with value conversion) to the input of the virtual port. As the virtual port is the one mapped to the widget, it will update it as expected.

  • The widget ‘Sync’ button will generate a message on the virtual port when the widgets are changed within GP. Because it’s a virtual port, this returned message via ‘Sync’ will also be seen by the Gig script. So you have another callback to pick up this message and then send out the message required to the fcb1010 to update the LED.

Why not ignore that ‘sync’ mechanism and just use rackspace OnWidgetChanged parameters to do this?

@tombo86 mentioned earlier he was already doing this with success.
So I guess it’s digging deeper on this comment:

It is very large and is difficult to edit if the rackspace configuration changes, and even harder if I create a new rackspace with different plugins and widgets.

If you are using the same handles for the widgets between each rackspace, then it’s not that much overhead.

@tombo86 it’s also worth highlighting that you can reference a script from your drive using:

Include “myScriptName”

So you can manage a single version of the script and not have to make updates in each individual rackspace script.

rank13 has it correct. I appreciate the tip on the Include statement. That will help tremendously. I will also try your virtual midi port suggestion. I am on Windows, but it should be the same behavior as on MacOS.

Your suggestion about using the same plugin GPScript names in different rackspaces is also a good one, but part of the issue I have run into already is that I don’t always use the same number of plugins. For example, I already use generic names for amp sims: Amp1, Amp2, Amp3, and Amp4. However, I need to remove all references to Amp2, 3 and 4 in the script when I am in a rackspace with only one amp sim. Since there is no Find and Replace feature in the GPScript editor, I need to copy and paste the entire script into notepad++, find and replace all of the references I want to remove, then paste back in. This is part of the difficult I referred to in editing or maintaining the script.

I may just use Bome Midi Translator for now, as it seems like it may be the easiest system to maintain in the long run, but I’ll post here once I have settled on a solution.

Thanks again to all of you for the suggestions!

Tom

I’m running in to the same problem, but my case is different - I have X-Touch Mini controller with endless (rotatary) encodes that have a very serious drawback - one needs to rotate encoder the A LOT to get full 0-127 range. Fortunately each knob has configurable CC range so one can set it to say 0-31 and then use a scriptlet to upscale to 0-128 and inject to “Local GP port”. But the problem is the widget sends upscaled (0-127) value back to controller and there is no place I can put a scriptlet to intercept CC sent to “Local GP Port” from widget and downscale it.

Anyway, I’m trying to have a single GPscript file and then include it in each rackspace with:

include "F:\Sergei\XTouchMini.gpscript"

But I get this compilation error

Rackspace (Rackspace) -  - Syntax Error in "Main": Line 1, Col 1: Unexpected or unrecognized token: 'include'
Extraneous input 'include' expecting {<EOF>, Var, Initialization, On, Function, Builtin}

What am I doing wrong?

What version of GP are you using?

GP 4.1.5 Trial

Here’s my script:

Var
   XTOUCH_IN: MidiInBlock
   XTOUCH_OUT : MidiOutBlock
   KNOB1, KNOB2, KNOB3, KNOB4, KNOB5, KNOB6, KNOB7, KNOB8 : Widget
   knobs : Widget Array
   scaled_max, ccval, scaled_ccval : Integer
   xtouch_channel : Integer
   xtouch_knob_cc : Integer Array

Initialization
    xtouch_channel = 11 // Change this to the midi channel used for your X-Touch knobs.
    xtouch_knob_cc = [21,22,23,24,25,26,27,28] // Change this to the CC numbers for your X-Touch knobs 1-8.
    scaled_max = 42 // Change this to the max midi value you want scaled to 127 e.g. setting to 40 will mean received values 0-40 will become 0-127.
    knobs = [KNOB1, KNOB2, KNOB3, KNOB4, KNOB5, KNOB6, KNOB7, KNOB8]
End

Function ScaleKnob(cc : Integer, ccval : Integer, knob_i : Integer)
    if ccval > scaled_max then 
        ccval = scaled_max 
        SendNowExternal(XTOUCH_OUT,MakeControlChangeMessageEx(cc, scaled_max, xtouch_channel))
    end
    scaled_ccval = ScaleInt(ccval, 0, scaled_max, 0, 127)
    SetWidgetValue(knobs[knob_i], MidiToParam(scaled_ccval))
End

On ControlChangeEvent(m : ControlChangeMessage)from XTOUCH_IN
    var i : integer
    for i = 0; i < Size(xtouch_knob_cc); i = i + 1 do 
        if GetCCNumber(m) == xtouch_knob_cc[i] then
            ScaleKnob(xtouch_knob_cc[i], GetCCValue(m), i)
        end
    end
End

Have you experimented with the widget scaling feature, as another way to scale a smaller range from the x-touch to 0-127?

Don’t use back slashes in your string, please. It should be

Include “F:/Sergei/XTouchMini.gpscript”

If you’re talking about “Value” tab in widget properties, then I think it deals with scaling of widget values (i.e. plugin values).

Yes, that works! Thanks!

Yes, and that is normally what the end goal is. Are you not mapping the x-touch encoders to a widget?

The widget scaling can convert an incoming 0-31 to a 0-127 range for the mapped widget/parameter.

Thanks, by your advice I experimented a bit with widget scaling. The only way to upscale is to draw a curve like


This will indeed upscale CC value received from MIDI controller and upscale the value sent to it but there are 2 no-go’s in this approach:

  • One needs to draw this curve for each mapped widget, and given that there is no easy way to do it (no quick preset for such type a curve) this makes it pretty impractical. Also if one day I decide to change the scaling (CC range) on my X-Touch mini I’ll have to update curves in each widget in each rackspace - non-feasible.
  • As shown in picture there will be difference between values that widget’s “arrow” points to (downscaled range) and values of the gradient bar around it that’s shows the “real” (e.g. plugin) value. Very confusing.

For now I’m sticking to per-rackspace approach - have a template rackspace with widgets corresponding to midi controller and rackspace gpscript consisting of single include line. For each rackspace that I need to create I start with the template one and remap widgets to plugin as I need. This is suboptimal indeed and I hope one day “Local GP port” feature will evolve enough to so that I could have proper “add widget → assign knob from rig manager → bind to plugin” flow :slight_smile:

The curve can be saved and then loaded for additional widgets (or duplicate widget). So at least you only have to draw it once.

FWIW the suggestion I provided above about using virtual MIDI ports works.
I have an X-Touch Mini and converted one of the encoders to be a 0-30 range.

The Gig Script I have is below. The incoming conversion is the same as what we’ve been discussing.
But when using the ‘Sync’ button on the widget, it will send the return messages to the virtual port, which is then picked up again by the Gig script → and re-scaled and sent back to the X-Touch Mini.

In my test it worked perfectly.

Var
    XTOUCH : MidiInDevice
    IAC_Driver_1 : MidiInDevice
    XTOUCH_CHANNEL : Integer = 11

// Original incoming message from the X-Touch Mini. The 0-30 range of the CC is scaled to 0-127.
On ControlChangeEvent(m : ControlChangeMessage) Matching 11 from XTOUCH
    Var newValue : Integer = ScaleInt(GetCCValue(m), 0, 30, 0, 127)
    InjectMidiEventViaRigManager(IAC_Driver_1, MakeControlChangeMessage(11, newValue))
End

// Message sent from the widget due to the bi-directional 'Sync' setting. This CC value is scaled from 0-127 back to 0-30 and then sent to the X-Touch Mini MIDI out port.
On ControlChangeEvent(m : ControlChangeMessage) Matching 11 from IAC_Driver_1
    Var newValue : Integer = ScaleInt(GetCCValue(m), 0, 127, 0, 30)
    SendNowToMidiOutDevice("X-TOUCH MINI", MakeControlChangeMessageEx(11, newValue, XTOUCH_CHANNEL))
End

I said I would report back once I decided how I was going to address this. I have been working on a solution for the last two weeks. The good news is that it is working great so far. The bad news is that it is not very duplicatable. I decided to write a C# program to handle all of the MIDI translation between my FCB1010 and Gig Performer. The translation from/to the FCB never needs to change and since I couldn’t find a good way to keep it global within Gig Performer, using an external program makes sense. I could have used Bome Midi Translator, but I wound up implementing some fairly complex logic such as using one pedal as a shift pedal and supporting long presses. Both of these are possible to implement in GPScript or Bome, but much easier to debug in Visual Studio. If anyone is interested in my “FCB Translator” let me know. However, you will need the Eureka PROM for the FCB1010, as well: eurekasound.com.

I don’t understand — this can be done either with a Gig Script in Gig Performer 4 and that code will work for the entire gig.

Yes, that is why I said these things could be done in Gig Performer. However, my initial question in this thread had to do with how to access midi outputs form a Gig level script. Here was the key statement:

I can’t find any way to capture midi going to a MidiOutBlock (typically from a widget binding) and convert it before it is sent to the actual MIDI out port.

The only workaround was a clever one from rank13 on 11/26 that involves using loopback midi ports. However, once I need to involve loopback ports, that takes away one advantage of keeping everything internal to Gig Performer.

In addition, the translation is actually quite complex. I have 1,500 lines of code in my external program. Debugging something like that in GPScript would be a challenge to say the least.