Finding the control identifier

Out of a value function callback, how do you get from the valueObject to its corresponding Control identifier?

I’m trying to change control attributes such as the color based on its value, but above is the link I’m missing to be able to call setColor for the right control

function getValues (valueObject, value)
    local message = valueObject:getMessage ()
    local control = valueObject:getControl ()
    print ("Control Name:" .. control:getName ())
    print ("Control ID:" .. control:getId ())
    print ("Device Id: " .. message:getDeviceId ())
    print ("Type: " .. message:getType ())
    print ("Parameter Number: " .. message:getParameterNumber ())
    print ("Current value: " .. message:getValue (default))

edit: the code snippet has been edited by @martin


Thank you @mIIwaukee, this info was very useful indeed! It helped me a lot :pray:

:warning::warning::warning: BUT… beware! :warning::warning::warning:

The forum software here seems to automatically change 2 dot/period/full stop characters (henceforth referred to as ‘dot characters’) to a special ellipsis character that the LUA editor does not understand!

So if you copy and paste the above code into the online LUA extension editor, it will fail to run, and it won’t tell you why! I wasted a good 30 minutes trying to figure out what was going wrong with, what appeared to be, well formatted LUA code!

But it wasn’t well formatted after all, because the forum software had automatically replaced ‘..’ with ‘…’, and the LUA interpreter gave up as a result :man_shrugging:

LUA needs two individual dot characters to join separate strings in a print statement such as this:

print ("This is a well formatted" .. " LUA print statement")

But if you’re posting on this forum and you happen to type ‘..’ (two dot characters), the forum software will automatically substitute a fancy ellipsis character instead, thus breaking your code example!

print ("This is NOT a well formatted LUA print statement")

@martin Please take note! Thanks both.

Forum also changes ‘--’ (LUA comment) to ‘–’ which LUA interpreter also doesn’t understand.

@benstat thanks for spotting this. I will adjust the app editor to validate the source code that non-ascii characters are reported.

With this in mind, I strongly suggest that code snippets should be marked as code in the forum message editor:

also, I will edit the posts that do not have it to prevent the forum from spreading the non-working code.


Unfortunately does not seem to work for me, when I have the following function (called as a function to resolve a SysEx byte):

function getMSB8bit(valueObject, value)
  local message = valueObject:getMessage ()
  local control = valueObject:getControl ()

When running the script, I immediately get the error:

error running function 'runTemplateFunction': ctrlv2/p003.lua:35: method 'getMessage' is not callable (a nil value)

And then the E1 hangs, Google Chrome acts weirdly, no more presets can be loaded, the E1 does not reconnect and a full PC reset seems the only way to restore services.

So how do I get from a function in a SysEx , called from a parameter , driven by a control, to the min and max display values of the control ?

are you calling getMSB8bit() directly or is it a callback assigned to the control?

None of them. It’s part of the SysEx json of a control.

Its function is to be different based on control attributes like min and max display value. I need this to be flexible because in Korg SysEx the byte after the value byte might behave differently based on context for the same Sysex Parameter!

Example: the SysEx below is from a Korg FX parameter. When used for a Reverb this parameter has values between 0 and 200, and then getMS8bit must be “1” when value > 128. But when used for an EQ effect, the very same parameter will have display parameters between -12 and +12, and in that case not only two’s complement with 8 bits will do the trick, but I must also give getMS8bit a “255” when value >128.

    "type": "function",
    "name": "getChannelByte"
    "type": "value"
    "type": "function",
    "name": "getMSB8bit"

The reason for asking is that - are you sure the function is getting passed a valueObject and value? (and they are both instantiated to some good data)

The error you’re getting is as if the valueObject parameter is not actually a valueObject with good data.
Can you just print the value parameter to see what is in there? If so, is it valid?

I think I found the reason, but not a solution.

A function in a sysEx json is not transmitting (valueObject,value) but (deviceObject,value).
As a result no information is transmitted regarding the control, the message, the parameter number :frowning:
I’ll make a feature request for it

I’ve solved my issue as follows: instead of using SysEx byte functions in combination with SysEx controllers (where no relationship with the controller’s attributes from within the SysEx byte function is possible), I changed the controller into virtual ones. Within a virtual controller I do have the access to the controller’s attribute so I can influence the behavior of all SysEx bytes and then transmit the SysEx using the midi SysExsend.
Below the example on how I now use function sendFx on a virtual controller to change it in a SysEx controller.
This works well, for sending, I haven’t given it a thought yet on how to parse received SyseEx data yet. Is not for today anyway.

function sendFx(valueObject,value)
  local message = valueObject:getMessage ()
  local parNum = message:getParameterNumber ()
  local control = valueObject:getControl ()
  local ctrlValue = control:getValue ("")
  local minValue = ctrlValue:getMin()
  local byte1 = value
  local byte2 = 0
  if  value < 0 then
    byte1 = value+128
    byte2 = 127
  elseif  value >127 then 
    byte1 = value%128
    byte2 = math.floor(value/128)
 midi.sendSysex (devport, {0x42, getChannelByte(device), 0x30, 0x41,parNum-128,0x01,byte1,byte2})

in the example I originally needed the minimum control values to influence behavior, but you’ll see in the example that in the end I could work out both bytes based on ‘value’ only. So why going through the trouble of it all instead of using the standard SysEx controllers?

=> Because the ‘value’ is a different one: the value available in the Sysex byte function is a MIDI value, so only positive integers, whereas in the example the values are display values, so they can be anything you want via the control display limits and/or the overlays.

I really hope not too many manufacturers make their Sysex that complicated…

1 Like