Sending OSC text numbers as sysex help needed

Hi there.

I’m having a go at setting up EQ control of a Behringer X32 rack via osc text/sysex. I’ve managed to get basic control of some functions like this but now I’m stumped.

I want to use an E1 knob to sweep the frequency 20Hz to 20,000Hz, I can send sysex to set the frequency of eq 2 on channel 1 for instance by sending ‘/ch/01/eq/2/f 1020’ as a hex string, the number 1020 equates (pun intended) to 31303230 so my problem is that I have absolutely no idea even where to start with this. How do I get 3230 to sweep to 3230303030?

If anyone can point me in the right direction, it would be great.

Shouldn’t you be able to do something like string.format("%x", 1020)? What exactly is the obstacle you’re facing? Maybe this discussion helps: Reddit - The heart of the internet

Hi, thanks for the reply.

Unfortunately for me I have no idea what string.format("%x", 1020) means or does, (I play guitar all day).
The obstacle I’m facing is trying program an Electra One knob with a sysex command to change the frequency on a specified channel on a Behringer X32 rack mixer which uses OSC commands. I have to translate the OSC text commands into sysex/hex then send it from the E1. The problem is that the majority of the sysex string I need to send is fixed, I can specify a frequency to change easily and send it but I would like to sweep the frequency obviously. The frequency range is 20Hz to 20000Hz which in OSC text to sysex hex is 3230 to 3230303030 so how do I create a command for knob in the E1 that will sweep smoothly between these two hex representations of numbers? I have no idea where to start, do I need to start looking at LUA? Is it even possible with the E1? I know that I can create a sysex knob with a fixed sysex portion and a variable but how do I get that variable to represent the range I specified?

Any guidance is greatly appreciated.

I see. I wasn’t aware that the X32 actually supports OSC commands via MIDI Sysex, but this wiki entry claims so: x32_midi_table [Behringer World Wiki]

The page says this:

Most X32/M32 OSC commands can be sent via midi sysex hex string in the following format:

F0 00 20 32 32 TEXT F7 

where TEXT is the X32 OSC command

So you’d need to make a function OnX32EqPotTwist somewhere in your .lua script that you upload to the E1 via its browser preset editor. The function should roughly look like this:

function OnX32EqPotTwist(valueObject, value)
    -- Create the message string
    local oscCommand = "/ch/01/eq/2/f " .. tostring(value)
    
    -- Wrap the message string in a MIDI Sysex message
    local sysexMessage = string.char(0xF0, 0x00, 0x20, 0x32, 0x32) .. oscCommand .. string.char(0xF7)
    
    -- Send out message, you can use any port here of the E1 you wish
    midi.sendSysex(PORT_1, sysexMessage)
    
    -- For debugging: print the result
    print(sysexMessage)
end

Then, assign the knob you want to use to the function “OnX32EqPotTwist” in the browser preset editor. You’ll also have to make sure that PORT_1 is the port you want to send out the message. Also, make sure that you set the value range of your pot to the values you want to send to the X32 (I guess 20 as minimum and 20000 as maximum).

Not familiar with OSC, but 3230 is actually the ASCII codes for 20
32 is the ASCII hex value for 2, 30 is the ASCII hex value for 0.
Using a chart like this one you can see (in the second column) the numbers 0 - 9 are represented by the ASCII codes 30 to 39.

So the problem is in two parts - first part is to create a control that sweeps from 20 to 20000.
If you make it a virtual control, you can attach a function to it that will send out the required string like the OnX32EqPotTwist() above.

But - inside that function you need to take the value of the control (say it is 147) and convert that into separate values of 31 34 37 and then send that.

I don’t have time this morning to come up with a clean simple way to do that, but if no one else responds, I will try to work up something later.

ok, maybe something like this:

function OnX32EqPotTwist(valueObject, value)
    -- Create the message string
   local divisor = 10000
   local nonzero = false
   local oscCommand = "/ch/01/eq/2/f "

   while divisor >= 1 do
      local nxt = math.floor(val / divisor)

      if (nonzero == false) and (nxt > 0) then 
         nonzero = true 
      end

      if (nonzero == true) then
         oscCommand = oscCommand .. " 3" .. nxt
      end

       val = val - (nxt * divisor)
       divisor = divisor / 10
   end    
    
    -- Wrap the message string in a MIDI Sysex message
    local sysexMessage = string.char(0xF0, 0x00, 0x20, 0x32, 0x32) .. oscCommand .. string.char(0xF7)
    
    -- Send out message, you can use any port here of the E1 you wish
    midi.sendSysex(PORT_1, sysexMessage)
    
    -- For debugging: print the result
    print(sysexMessage)
end

Some explanation - because the range is 20,000 down to 20, and you (probably) don’t want to send 00020 for 20 Hz, you want to just send 20, I look for the first nonzero result and then start collecting from that point. That also keeps any zeros inside a number (like 1047 Hz)

I loop from 10,000 down until we look at every place in the number and add a "3"n to the osc string with a space before it.

Hey chaps thanks for that! I guess it’s time for me to dig into LUA, I’ll see if I can get this working.

Hey.

So I tried this but got an error: error running function ‘runFunction’: ctrlv2/slots/p062.lua:9: bad argument #2 to ‘sendSysex’ (table expected, got string)

Mint gecko.eproj (1.1 KB)
I don’t see any activity on the Midi 1 out indicator.

Hey there.

I tried yours but I get an error:error running function ‘runFunction’: ctrlv2/slots/p062.lua:8: attempt to perform arithmetic on a nil value (global ‘val’)

If I add the lua function to the sysex data via ‘edit sysex data’ the E1 locks up and I have to pull the plug. I see no activity on midi 1 out.

OGG.eproj (1.5 KB)
Thanks.

Yeah, sorry, change val to value anywhere it’s used

That’s what I get for rushing the cut n paste

I’ll have to look closer how that sysex string was formed in the original function example.

On the road today and it’s really hard to work with the Electra One in the car driving 70 mph.
Lol

If it needs a table, you’ll need to convert the message string of both the hex and the ASCII version into a table. Right before midi.SendSysex, do something like this:

    local sysexTable = {}
    for i = 1, #sysexMessage do
        sysexTable[i] = string.byte(sysexMessage, i)
    end

    -- Send out message, you can use any port here of the E1 you wish
    midi.sendSysex(PORT_1, sysexTable)

On the phone, so just a guess!

I think the original sysex message posted did not take into account some of the Electra One specifics.

From the X32 guide (or another tech reference):

Setting channel 01, EQ 2 frequency to 1kHz (actually 1020Hz, due to known discrete values)
OSC: /ch/01/eq/2/f~~~,f~~[0.57]
<OSCtext>: /ch/01/eq/2/f 1020
Sysex: F0 00 20 32 32 2F 63 68 2F 30 31 2F 65 71 2F 32 2F 66 20 31 30 32 30 F7

So you can see that the actual sysex bytes that need to be sent are the ASCII codes for the text characters. Please take a moment to verify you understand this part because it is key to adding more commands.

you can always leave this part the same:  F0 00 20 32 32 (see later for a tweak to this)
This part:  2F 63 68 is the codes for /ch  and so on.

Now for the Electra One specific stuff:
using the midi.sendSysex() command, you need to specify a port on the Electra One. Think of this as which physical connection you are using. If you have a MIDI DIN cable connected to port 1, then use PORT_1 and if connected to port 2, use PORT_2.
The second thing you need is a series of MIDI bytes that is the sysex message. The Electra One function expects this to be a series of numbers separated by commas.

In addition, I always specify the values as hexadecimal because it ends up matching what companies document (that’s why every value has 0x in front of it).
Finally, the Electra One automatically adds the F0 to the beginning and the F7 to the end, so you do not need to specify those bytes.

Putting this together to start a message would now look like this:
local sysexMessage = {0x00, 0x20, 0x32, 0x32, 0x2f, 0x63, 0x68, 0x2f, chHi, chLow, 0x2F, 0x65. 0x71, 0x2f, eqNum, 0x2f, 0x66, 0x20}

This way, you can use this comand and easily change the channel number and the EQ number and then append the frequency from the control being turned.

I’ll try to put it all into one function with values set for the EQ and channel. Hopefully it gets you something happening.

function OnX32EqPotTwist(valueObject, value)
    -- Create the message string
   local divisor = 10000
   local nonzero = false
   local chHi = 0 + 0x30
   local chLow = 1 + 0x30
   local eqNum = 2 + 0x30

   local sysexMessage = {0x00, 0x20, 0x32, 0x32, 0x2f, 0x63, 0x68, 0x2f, chHi, chLow, 0x2F, 0x65, 0x71, 0x2f, eqNum, 0x2f, 0x66, 0x20}

   while divisor >= 1 do
      local nxt = math.floor(value / divisor)

      if (nonzero == false) and (nxt > 0) then 
         nonzero = true 
      end

      if (nonzero == true) then
         sysexMessage[#sysexMessage+1] = (0x30+nxt)
      end

       value = value - (nxt * divisor)
       divisor = divisor / 10
   end    
    
    -- Send out message, you can use any port here of the E1 you wish
    midi.sendSysex(PORT_1, sysexMessage)
 end

The slightly obtuse syntax: sysexMessage[#sysexMessage+1] = (0x30+nxt) is:
the length (number of values) in the sysexMessage array is given by #sysexMessage
so, in the last position + 1, insert the next EQ value
every time through the loop, the size is 1 bigger, so the characters get added to the end.

The local variables chHi, chLow, eqNum are writeen the way they are to help remember that in the OSC world, they need to be ASCII numbers.

1 Like

Brilliant thanks, that is connecting but the frequency sweeps only from 20Hz to 129.1Hz I tried setting the min and max for the control to 20 and 20,000 but although it gave greater range it jumped about erratically, what do I need to do to get a larger range of sweep?

In the X32 docs, does it mention the actual frequency values that are allowed for the EQ? It may be that they do not actually support all values between 20 and 20k

Take a screen shot of the control, like this:

Hi.

it does mention the frequencies, I’ve included some screenshots as well as the control screen shot.



in your control definition, change the ‘bi-polar’ to uni-polar. It doesn’t really matter for this, but it’s good practice for later since the EQ frequencies are always positive.
In the bottom area, change the 0 and 127 to 20 and 20000 and see what happens.
You also should change the message type to virtual since the function (OnX32EqPotTwist) is doing all the work.

(unless you actually have additional sysex messages that need to be sent, but my guess is no)

Brilliant, that works now. So presumably in that same LUA script I can define further functions and attach them to other knobs and other functions within the X32 and only the portion of the LUA script associated with that function will be executed on the knob twist?

Thanks so much for your help on this.

I apologize ahead of time in case the level of info is too simple (or too complex).
I realize that the majority of folks here are no software developers by trade and most just want to whip up some quick controls and remote access to gear with a underwhelming UI or none at all.

Because of that, I try to work in stages with folks to (hopefully) help them understand what is being done rather than simply cutting and pasting w/o really comprehending the workings. My feeling is that once you start to understand what is being done, you can then extend it on your own and reach back here for only the more problematic implementation issues.

Since I’m also trying to wrap my head around the presets I’m working on and debugging the weirdness inside, I am not always in a position to spin up full new functions in real time.

Given all that, what I would do as a start is to copy that function to a different name for each type of control you want.

The reason being is that inside the Eq() function is specific codes/characters to handle the OSC communication to the EQ.

Then for each of those controls, set the control range and the name of the function as appropriate.
If you know of 1 or 2 other controls you’d like to set up, post the info here and we can talk through how best to do it.

After you get more comfortable with what is going on and why it is happening, then we can get more streamlined/clever. For now, since the Electra One has a lot of RAM and processing power, making copies and changing the name is the easiest way to progress.

Thanks for that, I’m away from the gadgets for a bit but I’ll be back on to it soon.