Dynamic composition of a SysEx message with variable content and length

I just created a rackspace and a script to mimic what you did except that I’m sending the MIDI message to an external MIDI Monitor. As you can see from the image below, SendNowExternal works fine

So there’s either a problem with MIDI on Windows (I did this experiment on a Mac) or your physical device just can’t handle the speed at which the messages are being sent. The question is, how do we narrow this down.

2019-08-16%2006_32_23

Is there a clever way to slightly delay the action of the slider callbacks for testing purpose ? The idea is to slightly increase the delay between two successive SendNowExternal functions.

Hmm, perhaps try inserting a FOR loop in the code?

Doing nothing ?

Well, it’s going to increment its loop, right – requires CPU cycles

For example the for loop in the code below takes about 100ms to run on my machine

On WidgetValueChanged(newValue : double) from FADER_1   
   var i : integer
       startTime, stopTime : double
   
   SendNowExternal(ControlSurfaceOut, MakeMidiMessage(176, 111, Round(newValue*127)));   
   startTime = TimeNow()
   for i = 0; i < 1000000; i = i + 1 do
     // Pass time
   end
   stopTime = TimeNow();
   Print("Delay: " + (stopTime - startTime))
End

Thanks for your help, I confirm that everything is working fine from GP side, it seems, I have to set a delay of about 350ms between the slider moves to get all slider at the right position. :disappointed::disappointed::disappointed:

I don’t understand, I found videos on youtube where people were using this control surface with a DAW and they could recall the position of all the fader at the “same” time. Could it be that I missed something :thinking:

You should contact the manufacturer — sounds like they can’t handle the speed at which the data is being sent. They ought to be buffering the incoming MIDI events.

I will do so, thanks.

Let us know what you hear back.

Of course.

I am wondering how they do this:

With the delay I introduced I need ~3sec to recall all faders to the right position :thinking: (there are no internal banks, banks come from the DAW)

I think you should reach out to them and tell them what’s going on.

I send them a mail, but I think I just found how to solve the problem. The standard MCP configuration is to use a pitch bend message for the fader with one different channel per fader. I just modified this with the RIG manager and the fader are recalled properly. For the moment no idea if it is due to the pitch bend message or to the different channels used, but it works properly like this.

1 Like

I just had a feedback from Icon, it was a bug in the Platform control surface. They just released a firmware Platform M+ v2.07beta, where they solved the issue. I have to admit, that for the moment, I am impressed by their support. They gave me all the information to control the Platform M+ from Gig performer and fixed the bug with the delay to move the faders with CCxx rather than with Pitch Bend messages.
So, as it is still tricky to use knobs working in incremental mode (the scripting workaround makes you loose the advantage of the RIG manager) ), and the Platform M+ knobs are not surrounded from a LED circle (:-1:) so they probably did’nt think that it is necessary to let the knobs synchonize with the value from a PC host.
I know that working with knobs in incremental mode is in your list, but I also asked Icon to consider adding the possibility to synchronize their knobs with a value coming from GP.

Understand this thread is a bit old, but was there ever a way added to get hex characters from an ASCII string for use with SM_CreateSysexFromString(m, s) so you could do, for example:

var manager : SysexManager
SM_CreateSysexFromString(manager, "#f0 (...) " + stringtohex(s) + " (...) f7")

Thanks

Hi @rbmj, the solution I used for this is described here:

1 Like

Thanks! That’s quite the hack but it works great! I just wrote code to show the current rackspace name on my Arturia Keylab mk2’s LCD screen. A couple notes/wishlist items, and I’ll share the code at the bottom:

  • Global Scripts would be nice. If the interacted with the rig system that would be even better (though you’d probably need to add oop and inheritance to GPScript for the last bit so I understand that’s a stretch :D)
  • Some sort of way to share code between rackspaces, even if it’s just a basic #include style copypaste
  • Understand that documentation is a pain, especially for something like this. Maybe make it a wiki or host it on github so that the community can help?
  • Add me to the list of people asking for OnSongActivate - Looks like from another thread you’ve written the code so hopefully it’s easy!
  • String constant expressions are pass by reference, which leads to the rather confusing behavior that var s : String; s = "foo"; bar(s); is not equivalent to bar("foo"); if bar modifies its argument. If all non-primitive types exhibit this behavior it would be helpful if it was explained in the tutorial.

I’ll share my code in case anyone else is using the keylab:

var
    Keylab2          : MidiOutBlock;
    SysEx            : SysexManager;
    KEYLAB2_LCD_PRE  : String;
    KEYLAB2_LCD_SEP  : String;
    KEYLAB2_LCD_END  : String;
    ASCII_STRING     : String;
    ASCII_HEX_STRING : String array;

Initialization
    ASCII_STRING = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[Y]^_`abcdefghijklmnopqrstuvwxyz{|}><";
    ASCII_HEX_STRING = ["20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F","30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F","40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F","50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F","60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F","70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F"];
    KEYLAB2_LCD_PRE = "# F0 00 20 6B 7F 42 04 00 60 01 ";
    KEYLAB2_LCD_SEP = " 00 02 ";
    KEYLAB2_LCD_END = " 00 F7";
 End
    
Function StringToHexString(str : String) Returns String
   var i : Integer
   result = "";

   For i=0; i<Length(str) ; i=i+1 Do
     result = result + ASCII_HEX_STRING[IndexOfSubstring(ASCII_STRING, CopySubstring(str,i,1), True)];
   End
End
    
Function Keylab2LCD(line0 : String, line1 : String)
    If Length(line0) > 16
	Then
		line0 = CopySubstring(line0, 0, 16);
    End
    line0 = StringToHexString(line0);
    
    If Length(line1) > 16
    Then
        line1 = CopySubstring(line1, 0, 16);
    End
    line1 = StringToHexString(line1);


    SM_CreateSysexFromString(SysEx, KEYLAB2_LCD_PRE + line0 + KEYLAB2_LCD_SEP + line1 + KEYLAB2_LCD_END); 
    SM_SendMidiOut(SysEx, Keylab2);
End

On Activate
    var s : String;
    s = "Rackspace:";
    Keylab2LCD(s, GetRackspaceName());
End
3 Likes

Wow — I continue to be flabbergasted by how people have used GP Script, a language that was intended for writing 10-20 line programs for minor MIDI hacking :slight_smile:

Having said that, I’ll mention a couple of things (although not everything) happening (just) with GP Script (which sorely needs a new name, particularly since it’s not really a scripting language, it gets compiled!) for upcoming versions of Gig Performer. I’ll add the usual caveat that nothing is guaranteed as I don’t want someone to buy GP with the assumption that a particular feature will definitely be there and then be annoyed if it isn’t!

  1. GP4 will have the notion of a global script. I’m not sure what you mean by interacting with the rig system though. The global script can respond to certain events such as SongChanged and you can send sysex messages out through any midi output device. That will let you centralize such things as updating a display, without having to put code in every rackspace.

  2. Sharing code is a high priority — for various obscure reasons, it has turned out to be much harder to implement than expected but it’s on my high priority list, we’ll get there!

  3. GP4 will also have the notion of song scripts, paralleling rackspace scripts. Song scripts have On Activate. You can of course combine that local “On Activate” with a global “On Song Changed”

  4. Variable declarations will allow initialization as well so you will be able to write things like

var 
KEYLAB2_LCD_PRE : String = "# F0 00 20 6B 7F 42 04 00 60 01 ";

simplifying code significantly.

In principle this is a bug! Incoming variables are generally call-by-value but (similar to Java or Smalltalk), if the variable is an object, you can change stuff inside that object. String constants were implemented as simple objects so that I didn’t have to copy strings. At the time (very first version of GP Script) I was concerned much more about efficiency. As it turns out, subsequent improvements to the compiler and runtime system have pretty much eliminated that concern. I’ve put this issue in our tracking system.

Thanks for your comments.

2 Likes

Looking forward to all the improvements! By interacting with the rig system I simply mean that you could send a MIDI in/out block a message/signal, and it could intelligently decide what to do with it, or if no MIDI block had that GP Script tag in that rackspace then it might be gracefully ignored. I imagine such functionality would be rather niche - the bigger thing would definitely be global scripts, etc.

generally call-by-value but (similar to Java or Smalltalk)

Gotcha. Lazy C++ programmer me was just assuming they were char* based on the way that strings are manipulated - so I was rather surprised when line0 = StringToHexString(line0) decided to repeatedly encode itself every time the function was called :joy:

Thanks for responding - really cool to see how active you all are here.

1 Like

hi rbmj,
attention complete noob here…
i tried your script allthough i had to change from your “Keylab2” to “KeyLab_mkII_49”
i asume that is correct because the compiler is not “arguing”.but now i am stuck as before i can compile i get the error message:
Semantic error: Line 42, Col 27: Identifier not declared: KeyLab_mkII_49
i did not change anything but the name,the line looks like this:
SM_SendMidiOut(SysEx, KeyLab_mkII_49);
i hope i am not doing something basic wrong-i called up the script editor in edit rackspace mode.
thanks for your help