Sysex vs virtual

Hi. I have a preset I’m building that uses SysEx messages extensively. Is it better practice to use the SysEx message type and enter the message with the preset editor or to use a lua function that contains the SysEx message? One factor I’m particularly interested is if one or the other approach uses more memory. Or are they basically equivalent?

Don’t know about memory. If you have occasional use of sysex, you better use the sysex type parameter. It’s easy and clear but tedious to maintain. If you make systematic use of controls for sending sysew you better use lua. Combined with clever parameter numbering and the onchange callback: much easier to maintain

Thanks. I agree. Entering a lot of SysEx messages via the preset editor is tedious work. It also appears to be largely awash in terms of memory. They both add lines to the source JSON file, and I guess the JSON file eventually gets too big for the E1 to handle.
I do use parameter numbers that have an easy correspondence to the synth’s parameter address map numbers. But I need to investigate the onchange callback function. I have not used that before.

1 Like

Imagine you have clusters of parameters that need a different format for their SysEx transmission. For instance you have only one set of controls for controlling a timbre of a multitimbral synth. Then in the format of that control, you’d have to use the chosen timbre section somewhere as a variable. In other controls you don’t have to do that.

Instead of creating all different functions for each format and then assigning those functions to each control separately, I found it more effective to use the parameter map onchange callback, check if the change comes from manual tweaking, verify which cluster the parameter belongs to, and then trigger the desired SysEx send.

Doing so all that SysEx logic is now in one place in lua, and I have the assignable function field for controls still available for other duties.

2 Likes

agreed - the Lua code tends to be easier to implement and maintain since you only look in one place. Also agree that the controls do not need separate MIDI handling procedures and all changes can be funneled through the onChange().

Here is a simple start to a typical onChange() function that I use:
(I also threw in a handful of common byte(s) ↔ nibble(s) that I’ve used)
(I have an internal convention that all ‘local’ controls – page changes, patch selection, any stuff that doesn’t need to send MIDI back to the device, get a parameter number 900 and higher. This is just my convention to prevent unwanted MIDI messages from confusing the device)

--
-- utility functions
--
function make16(first, second)
   local retVal = ((second & 0x00FF) << 8) | (first & 0x00FF)
   return retVal
end

function un16(dataVal)
   local first  = (dataVal & 0x00FF)
   local second = ((dataVal & 0xFF00) >> 8)
   return first,second
end

function un14(dataVal)
   local first  = ((dataVal & 0x3F80) >> 7)
   local second =  (dataVal & 0x007F)

   return first,second
end

function makeByte(first, second)
   local retVal = ((second & 0x0F) << 4) | (first & 0x0F)
   return retVal
end

function unByte(dataVal)
   local first = (dataVal & 0x0F)
   local second  = (dataVal & 0xF0) >> 4
   return first,second
end

function parameterMap.onChange (valueObjects, origin, midiValue)

   -- options here are INTERNAL, MIDI, LUA
   -- only send if user changes things
   if (origin ~= INTERNAL) then return end

   local paramSysex = {}
   local lowB
   local highB

   -- control Id is not used in this preset
   local ctlId = valueObjects[1]:getControl():getId()
   local pNum = valueObjects[1]:getMessage():getParameterNumber()

   -- do not send patch changes or sync - done separately
   if (pNum >= 900) then
      return
   else
      lowB, highB = un16(midiValue)
      paramSysex = {0x3E, 0x0E, 0x00, 0x07, lowB, highB}
      -- portNum defined globally
      midi.sendSysex(portNum, paramSysex)
   end
end
4 Likes

This all makes so much sense. Thank you. It’s going to make my presets much better. I was trying all kinds of longwinded ways to do what a simple onChange function can do. :joy:

Glad it helps. One other thing I keep in mind (usually via a comment in the code) is:

--
--  Electra One control change order of calls is:  parameterMap.onChange(), control function(), control formatter()
--

In other words, you can “do stuff” - MIDI, display, internal data manipulations in a few different places. Sometimes you need to adjust MIDI values or control variables. Knowing the order that the Electra One processes a parameterMap onChange() and the formatter() and function() calls associated with a control can be helpful.

Most of the time you never care about this, but every once in a while you need to do something unique and this might help.

4 Likes

Learning new stuff is fun! Thanks @oldgearguy and @NewIgnis

1 Like

Applying the parameterMap.onChange function allowed me to eliminate about 10k unnecessary lines from the JSON source file. I suck. But now I suck a little less. Have a great weekend!

1 Like

It’s all about learning. We all benefit from each other’s attempts and sharing what we learn.
Glad you were able to take our hints and run with them and it worked for you.

This community continues to surprise me in the best way possible.

3 Likes

New challenge: The Integra has a multi effects section (MFX) that allows use of one of 67 different effects. There are 32 MFX parameters and these vary in name and range depending on the effect selected. For example, parameter 1 could be an on/off switch for one effect, an 8 value list for a second effect, and a 0-256 fader for a third effect, etc. How do I set up the associated controls for the parameters so that they display the selected effect’s parameter name and the correct range for each of the 67 effects? I have the parameters parsed, but the info displayed is a bit meaningless without better formatting.

Typical challenge. You’ll need to go through some of my presets. It involves making a table in which for each effect you assign to a control a range, name and colour. I’ll check which preset might be well positioned.

1 Like

ok, to do it can be a challenge.
In my Korg AM8000R, there are 3 FX slots (1 for delay/reverb and 2 for other FX).

I implemented it with tables and have the control such that you can turn through the FX and when you release the knob, the controls get displayed and populated.

To do this is something that can be non-trivial. The reason is you want to have the displayed control show the current value and range for the parameter.

Until @martin implements a few more things, there’s no obvious way to dynamically assign some kind of formatting function to a control (or build a control completely dynamically).

Couple approaches – depending on how many open pages you have, create all the various type of dedicated controls you need and put them on the higher “unused” pages and/or make them hidden, then after a user selects an effect, move the controls to the main page(s) and update the parameter map (if necessary) with their values. I’ve done this with the Lexicon PM 80 preset (reverb section).

The other option is to create the page(s) of controls, hide ones that aren’t used in an effect and have generic formatter() functions that can handle the units/ranges based on which effect is currently active. You’ll also need to set the appropriate range for each control based on the selected effect as well.

No 100% promises, but if you have the Roland Integra MIDI docs easily available (I haven’t looked on line yet - just sat down at the PC) or have a link, I’ll take a look and see if there’s a decent solution.

1 Like

Thanks. Here is the MIDI doc. The parameter address map starts on page 9. I’m looking at the supernatural synth tone common MFX on page 21-22, and the supernatural acoustic tone common MFX on p23-24. As far as I can tell they are the same (except the starting addresses are different).
INTEGRA-7_MIDI.pdf (658.2 KB)

The 32 MFX parameters start at address offset 00 11 and go through 01 0D (they are each in 4byte/4bit blocks). I have them parsed.

Here are some examples.

https://app.electra.one/preset/ypm2nMo8yp6gYZ4bBytt
Sequential Prophet 6 is a simple example. The parameters did not have different ranges. Still it allows to set names per effectstype.

https://app.electra.one/preset/YEiyHkzSEw8d9duJWv2Y
Korg 03R/W is probably the most useful example, yet try first to understand the P-6 example.

This Korg had 2 effects, each with 7 dynamic parameters. Function setFx controls those parameters, and it finds the settings to use via tables fxIndirectRef (which tells with type of effect each effect is), fxNames (containing the parameter names), ctrlMin (minimum of a range), ctrlMax (maximum of a range). Using some conventions I set myself, I did not need to mention values that I could omit or default, keeping the tables as small as possible.
In the setFx function itself , I derived the colors to use. Something I would no longer advise, as it delivers hard to read code.

https://app.electra.one/preset/xpbhZBNb37MseUMvYWuu
The Zoom MS70 preset is quite a complicated one , because it has 6 simultaneous effects.
Their parameters are all parsed on the two last pages, but on the first page, upon selection of unit and fx type, its 9 parameters adapt dynamically. The ranges were quite complicated because a lot of them are a combination of numerical values and named options in one single option list.
If you look in the lua, pleas notice:

  • formatPar() ; a function that creates the richt label, based on the parameterNumber
  • createOverlays() ; a function that creates all needed overlays
  • fxTypeChar : a table, which, per effect type, describes their names, their parameters with their color, range and format to use
2 Likes

Great thread! Thanks all!

@NewIgnis . I successfully implemented the method in the sequential prophet 6 preset to set the names per effect type. Thanks. I will complete that for all 67 effect types before moving on to controlling the display range as well. I’m not sure about controlling values though, per comment by @oldgearguy.

Also, I wish there was a way to choose a control’s reference # because of course I don’t have them all sequentially ordered and so my loop has to handle breaks and jumps in the ref #.

Well, I guess I could carefully edit the JSON file to reassign control id numbers.

hindsight is 20/20 of course. I’ve gone back and deleted controls and/or temporarily created controls (or group labels) to suck up control IDs so I could have other areas as sequential control Id numbers. Yes, lot of tedious work, but much less coding headaches after the fact. Once the preset was at a good point, I’d go in and delete all the temporary controls/groups I created.

display ranges can be a table. Sunday is a day of rest for me and I try not even to go on-line, but tomorrow I will send some range suggestions for you.

1 Like

Just FYI, I ended up making a normalized Ctrl id array j such that j[i]+i is the i-th Ctrl id# so only 1 loop needed. And absolutely no rush. I’m extremely grateful for the help I have already received.