How to add other data than parameters into Sysex message? constants and other variables

Hi,
I have the following challenge I want to resolve when sending Sysex-messages (in this case to a KingKorg, but this will apply to other synths too):

  • The second byte in any KingKorg Sysex is a concatenation of a fixed ‘3’ and the midi-channel minus 1:
    • if the synth is on midi-channel 1, the SysEx byte to create is “30”
    • if the synth is on midi-channel 12, the SysEx byte to create is “3B”

questions:

  • how do I create a value in JSON, in which the first 4 bits are a constant, representing ‘3’ ?
  • how can I retrieve the device’s midi channel as a value between 0…15 (subtracting value of 1 thus) and represented as a hexidecimal to include in the SysEx? My attempts so far were without success…
  • is there a way I could store multiple bytes of the SysEx message as one variable in lua (like the ever reoccuring midi channel dependent part of the SysEx header), so it makes it easier to manage/reuse SyseX JSON lists assigned to controls ?
    • If yes, can someone make me a lua example where the challenge here above is entered as a lua variable for the KingKorg’s header string [“42”, “3g”, “00”, “01”, “18”], where g is to be replaced with the midi channels hexa-representation?

Thanks in advance

Hi,

the way to go is to use Lua function within the sysex message (it works for both outgoing sysex templates as well as for patch requests). I decided to rely on Lua in this because almost every manufacturer does some magic calculations with the midi channel or device Id encoding in the sysex messages.

To see it in action please see the Yamaha TX7 preset.

eg:

[
  "43",
  {
    "type": "function",
    "name": "getChannelByte"
  },
  "00",
  "7B",
  {
    "type": "value",
    "rules": [
      {
        "type": "sysex",
        "parameterNumber": 123,
        "bitWidth": 5,
        "byteBitPosition": 0
      }
    ]
  }
]

and the Lua function:

-- returns a byte that TX7 uses to identify the MIDI channel
-- for a parameter change message
function getChannelByte(device)
  return (0x10 + (device:getChannel() - 1))
end

I hope it helps. If not, let me know.

I’m not getting the results I expected.
This is my lua script. Remark the print I’ve inserted in the function as a check.

deviceId = 1
device = devices.get(deviceId)

function getChannelByte(device)
local result = 0x30 + (device:getChannel() - 1)
print (result)
return (0x30 + (device:getChannel() - 1))
end

Here’s one after the other the sysex message for filter cut-off and the one for resonance. Only the 9th byte is different: “1F” for cutoff, “20” for resonance.

[
“42”,
{
“type”: “function”,
“name”: “getChannelByte”
},
“00”,
“01”,
“18”,
“41”,
“02”,
“00”,
“1F”,
“00”,
{
“type”: “value”
},
“00”,
“00”
]

[
“42”,
{
“type”: “function”,
“name”: “getChannelByte”
},
“00”,
“01”,
“18”,
“41”,
“02”,
“00”,
“20”,
“00”,
{
“type”: “value”
},
“00”,
“00”
]

A weird thing happens:

  • whatever channel I put the first device on, when I turn the cutoff, the logviewer returns ‘59’.
  • however when I turn the resonance, the logviewer returns the expected value, which is 47+channel number… it is the same function getChannelByte I recall. why a different answer?

image

The logviewer above shows the following sequence while device 1 is on channel 7:

  • playing note 60
  • 3 changes to the cutoff control
  • playing note 60 again
  • 3 changes to the resonance control

by the way I changed names of other controls on purpose to ascertain the E1 was indeed receiving the changed preset.

can’t get my head around this one…

Please, send me a link to the preset. That will be the easiest way to review. Thx!

1 Like

@martin , I’m actually having a series of unexpected behaviour, of which I can’t tell which ones are by design and which aren’t. They all feel like the memory allocation is going haywire. It’s become a long message , sorry about that.

The issue above is found in preset “Kingkorg v0
Just look at the orange controls, the other ones don’t count. ‘Cutoff stuck12’ is not changing its bytes according to the device’s channel, while the others, having the same code, do change along…

But the weird behaviour started before that : I’ll try to give 4 observations in chronological order below

1 . Memory question for preset “NewIgnis Notes transmittor V3

In this preset there is a user function “assignActive” I call very often, which is meant to populate various arrays with values of those midi channels the E1 needs to respond to when a MidiCC, NoteOn NoteOff and the likes are received.
However I found that when I call this function with the very first control (which has parameter number 1001), the value of the function itself " function assignActive (valueObject, value)" and the value of “local activeValue=parameterMap.get (deviceId, PT_VIRTUAL, 1001)” are different. It’s like the ‘value’ does contains the new value reached by the control, whereas requesting the same value with parameterMap (into variable ‘activeValue’), is giving me the value the control was in before I moved it. So the paramterMap contains a buffered value from before changing it, while invoking the control function. Is that by design?
I worked my way around this by assigning parameter numbers carefully, so I could split them in a pageGroup (for instance 1000) and a midichannel (for instance 01), and depending from where the function was called, I’m using either the value from the function itself, or the value via the parameterMap, as shown below, where I look for both function value and activeValue:

– this updates the active tables ------------------------------------------------------- ACTIVE TABLES
> function assignActive (valueObject, value)
local message = valueObject:getMessage()
> local channel = tonumber(message:getParameterNumber()) % 100
local pageGroup = tonumber(message:getParameterNumber())-channel
print("pageGroup = "…pageGroup)
> local activeValue=parameterMap.get (deviceId, PT_VIRTUAL, 1000+channel )
local assignValue=parameterMap.get (deviceId, PT_VIRTUAL, 2000+channel)
local pbValue=parameterMap.get (deviceId, PT_VIRTUAL, 3000+channel)
local atValue=parameterMap.get (deviceId, PT_VIRTUAL, 3100+channel)
local voicesValue=parameterMap.get (deviceId, PT_VIRTUAL, 5000+channel)
etc…

  1. ParameterMap is not initialised

When further developing this preset into the current draft version “Clone of NewIgnis Notes transmittor V4”, I wanted to have more control over the velocity sensitivity (amount ànd inversion) when receiving a noteOn.The values of how to convert velocity per channel are maintained with the 16 controls on the 2nd half of page 9, where I’ve given them parameterNumbers 9101-9116. I kind of expected that I could simply read those parametes when setting the variable velSens in the script, but that didn’t work: the parameterMap seemed not to be filled with the default settings of the controls when starting the preset. These controls had to be tweaked before the value makes it into the parameterMap which is not my intention… So I created an initialisation code to read in all default values from those 16 controls and then use these to set the parameterMap of those same controls myself. Is that by design?

for i= 1,16 do – initializing
local control = controls.get ((9-1)*36+18+i)
local value= control:getValue (“default”)
local default= value:getDefault ()
parameterMap.set (deviceId, PT_VIRTUAL, 9100+i, default)
applyColor (0,i)
end

  1. Visualisation bug

When further developing this preset into the current draft version “Clone of NewIgnis Notes transmittor V4”, I wanted to color all the controls as of page 2 in RED, if the corresponding midi channel in page 1 was not yet active. Because of the previous initialisation challenge, I settled for now coloring them all red, with a user function called applyColor (colourValue, channelNumber). That works. But when I call off the same function applyColor via controls 1-16 (each one has control function assignActive, which in turns calls applyColor ) of page 1, it does some weird stuff: apart from what it was supposed to do (coloring controls BLUE, WHITE or RED), it also changes the type, color and name of the controls 19-34 of page 1. It’s clearly some kind of bug, because whenever I change focus on page 1, these ill-represented controls are again replaced by the original controls I configured in there.

function applyColor (value,channel)
local color = BLUE
if channel < 1 or channel > 16 then return end
if value ==0 then
color =RED
elseif math.floor((channel-1)/4) == 0 or math.floor((channel-1)/4) == 2 then
color = WHITE
end

controls.get ( 36+channel):setColor (color)
controls.get ( 54+channel):setColor (color)
controls.get ( 72+channel):setColor (color)
controls.get ( 90+channel):setColor (color)
controls.get (108+channel):setColor (color)
controls.get (216+channel):setColor (color)
controls.get (234+channel):setColor (color)
controls.get (252+channel):setColor (color)
controls.get (288+channel):setColor (color)
controls.get (306+channel):setColor (color)
controls.get (324+channel):setColor (color)
controls.get (342+channel):setColor (color)

end

  1. E1 freezing

I haven’t gone beyond this stage anymore with that preset, because of this apparent last bug. However, I notice that during use but also on startup the Electra 1 sometimes freezes, which I hadn’t had before. Only way to resolve is disconnect its power.

1 Like

Hi @NewIgnis,

thanks for the report! I will go through the points one by one as time permits me…

I took a look at the preset and I can see that Filter type and Cutoff Stuck12 controls are linked to device with the MIDI channel set to 12. the Cutoff control is linked to Device on channel 1. With this in mind I think the data sent out is correct. I have tried to changed the channels (of these two devices) and it looked ok - meaning the changes were reflected accordingly.

one side note. following Lua should be sufficient:

function getChannelByte(device)
  local result = 0x30 + (device:getChannel() - 1)
  print (result)
  return result
end

The global part is not needed. getChannelByte() is a callback and the device parameter is provided by the Electra firmware. The device that you define in the global part is not used.

I will look at the other stuff later. If you have qs, let me know.

1 Like

dammit, why didn’t I think of it sooner to check the device linked to the control. :thinking:
stupid mistake of mine.
thanks for figuring this out so quickly, I was blinded

@Martin,
based on the example below: can i make a variable out of the parameterNumber in a SysEx? I actually would like to give controls of type SysEx a parameterNumber from which I can derive bytes that are needed within the SysEx.

  • Simple example: I want the 5th byte of the SysEx of parameter number 45 to equal…45.
    Can I do that ? It would allow that almost all SysEx commands in a preset could be copied and pasted…
  • A more complex example: I want to set the 5th byte equal to the modulo of the parameterNumber, and the 6th byte to the thousand of a same parameterNumber. If the parameterNumber would then equal 45, the 5th byte should be 45 and the sixth = 0. But if the parameterNumber would equal 2045, the 5th byte should be 45 and the sixth = 2.
[
  "43",
  {
    "type": "function",
    "name": "getChannelByte"
  },
  "00",
  "7B",
  {
    "type": "value",
    "rules": [
      {
        "type": "sysex",
        "parameterNumber": 123,
        "bitWidth": 5,
        "byteBitPosition": 0
      }
    ]
  }
]