Skip to content

SysEx implementation

The Electra One MIDI controller can be configured, programmed, and fully controlled using MIDI SysEx (System Exclusive) messages. This document explains how SysEx messages are used to communicate with the controller — including how to send data, request information, and manage its behavior — all through the USB MIDI interface.

In fact, the full Electra One web-based editor running app.electra.one is built entirely on top of this very same SysEx API.

Whether you're building your own tools or integrating Electra One into a larger MIDI setup, this guide will help you understand the key SysEx commands and how to use them effectively.

Note

To utilize the SysEx Implementation described in this document, you must have Firmware version 4.0 or later installed.

Byte Notation

All byte values in this document are written in hexadecimal format, using the 0xNN notation, where NN is a value between 00 and FF.

Unless otherwise noted, all numbers should be interpreted as hexadecimal. If decimal notation is used, it will be clearly stated.

Manufacturer SysEx Id

Every SysEx message must include a manufacturer Id to identify which device or brand the message is intended for. This helps prevent conflicts and ensures that messages are correctly interpreted by the right device.

Electra One uses the official Manufacturer SysEx Id assigned by the MIDI Association to Electra One s.r.o.:

0x00 0x21 0x45

This Id must appear at the beginning of every SysEx message sent to an Electra One controller.

The Management Port

Electra One SysEx messages can be sent through any of the controller’s USB device MIDI ports. However, it is recommended to use the Electra Controller CTRL port whenever possible. Using this dedicated port helps separate Electra’s management SysEx messages from regular MIDI traffic.

On some systems, this port may appear under a different name:

  • Windows: MIDIIN3
  • Linux: PORT 3

Replies to requests - data, ACK and NACK - are sent on the USB device MIDI interface, on the port number the request came in on. A request that arrives on a DIN MIDI port or on the USB Host port is answered on the USB device port with the same number.

Event notifications (triggered by user interaction on the controller) are sent by default to the Electra Controller CTRL port. This behavior can be changed — see Set the MIDI port for UI events for more details.

Request / Response Handshake

Electra One uses a simple request–response protocol for exchanging data over SysEx.
Each message sent to the controller expects a specific type of response. This handshake ensures reliable communication and lets you confirm whether the request was received and handled correctly.

Requests sent to Electra One fall into two main categories:

  • Data Queries – Used to request information from the controller.
    These requests do not modify any state or data on the device. They only fetch and return data.
  • Commands – Used to perform actions or change data on the controller.
    These requests do modify the controller’s internal state or configuration.

When a Data Query is sent, Electra One responds with a message containing the requested data in JSON format.

A Data Query is answered with the data message only:

  • It never gets an ACK or NACK, and a Transaction Id sent with it is not echoed.
  • A query for a preset slot file (Get Preset, Get Lua script, Get Device overrides, Get Persisted data, Get Performance) with a bank number or slot out of range sends nothing.
  • A query for a file that does not exist, such as Get Lua script for a slot without a script, is answered with an empty data message, for example 0xF0 0x00 0x21 0x45 0x01 0x0C 0xF7.

The File Transfer queries are the exceptions: Get Location files answers a descriptor it cannot use with a NACK, and Get file sends the file followed by an ACK, or a NACK.

When a Command is sent, Electra One replies with either:

  • ACK (Acknowledged) – The command was successfully received and executed.
  • NACK (Not Acknowledged) – The command failed (e.g., due to incorrect structure or invalid data).

ACK and NACK responses let you know if the controller accepted your request, so your application can respond in the right way.

An ACK or NACK is only ever sent as the reply to a Command, and each Command gets exactly one. Firmware before 5.0.0 also sent unrequested ACKs when the controller was used, for example one each time a knob was touched or released. These repeated the reply to the first Command received after power-up, including its Transaction Id. A host should ignore any ACK or NACK that does not answer a request it is still waiting for.

Transaction Id

There may be situations where multiple Commands are sent at the same time.
In these cases, it can be difficult to tell which ACK or NACK response belongs to which request. To solve this, Commands can optionally include a Transaction Id. This Id helps you track and match each response to its original request — especially useful when multiple requests are being processed asynchronously or out of order.

If used, the Transaction Id must be inserted immediately after the Manufacturer SysEx Id using the following format:

0x00 0xNN 0xMM

Where:

  • 0xNN is the least significant 7 bits (LSB) of the transaction Id
  • 0xMM is the most significant 7 bits (MSB) of the transaction Id

If a Transaction Id is included in the Command, the corresponding ACK or NACK response will also include the same two bytes, allowing you to match the response to the original command. See, ACK / NACK for more details.

Example

The transaction Id 4183 should be transferred as

0x00 0x77 0x20

Electra One firmware versions earlier than 4.0.0 do not support Transaction Ids. If you include a Transaction Id with a command on older firmware, it will not work as expected. For this reason, your software should always check the firmware version before using this feature.

Operation and Resource Bytes

After the Manufacturer SysEx Id (and optional Transaction Id, if used), the next two bytes in the message define:

  1. The Operation – what kind of action should be performed
  2. The Resource – what type of data the action should apply to

These two bytes are essential for telling the controller exactly what you're asking it to do and where the action should be applied.

Operations

The Operation byte tells Electra One whether the request is a Data query. or a Command that

The operation types include:

  • upload – upload new data (e.g. a preset or Lua script)
  • request - query data stored on the controller
  • create – create a data resource (eg. snapshot)
  • update – make a persitent change to a data resource
  • remove – remove data permanently
  • switch - change active resource
  • updateRuntime - update run-time volatile data

There are additional special operations, which will be described later in this document.

Resource Byte

The second byte identifies the data resource the operation should target.
It tells the controller what kind of data is being queried or changed.

Some example resources include:

  • Preset – the entire preset configuration
  • Control – a single control within a preset
  • System – system-level settings or configuration
  • File – a file or file location
  • Device – information about connected MIDI devices
  • Trace (0x40) – the Lua debugger, see Lua debugger
  • ParameterMap (0x41) – the preset's parameter map

There are many types of data resources available. You'll find their descriptions later in this document.

By combining the Operation and Resource bytes, your message tells Electra One exactly:

  • What to do (operation)
  • And what to do it with (resource)

Payload

Most operations require additional data to work, for example, a preset in JSON format or the number of a preset slot to activate. This extra data is called the Payload, and it comes immediately after the Operation and Resource bytes in the SysEx message.

Depending on the type of operation, the payload format can vary. Some operations require binary payloads, others require data formatted as JSON.

While handling different payload formats may add a bit of complexity for software developers using the SysEx API, this design greatly improves performance by avoiding unnecessary JSON parsing when it's not needed.

When transferring JSON payload, the individual bytes must be transferred using their ASCII codes and stay strickly in 7-bit range.

Message Structure

Now that we’ve covered all the components of a message, we can take a look at the overall structure of a SysEx API message.

Without Transaction Id

A SysEx API message without a Transaction Id:

0xF0 manufacturer-id operation resource payload 0xF7

for example a Command with binary data Payload:

0xF0 0x00 0x21 0x45 0x05 0x01 0x00 0x05 0xF7

or a Command with mixed binary and JSON data Paylaod:

0xF0 0x00 0x21 0x45 0x14 0x07 0x05 0x00 {"name":"Track2"} 0xF7

upon processing the command, the Electra One controller will respond with the ACK or NACK according to the result of the operation.

an example of the ACK response:

0xF0 0x00 0x21 0x45 0x7E 0x01 0x00 0x00 0xF7

With Transaction Id

A SysEx API message with a Transaction Id:

0xF0 manufacturer-id 0x00 transaction-id operation resource payload 0xF7

for example a Command with binary data Payload:

0xF0 0x00 0x21 0x45 0x00 0x77 0x20 0x05 0x01 0x00 0x05 0xF7

Upon processing the command, the Electra One controller will respond with either an ACK or NACK, depending on the result of the operation. If a Transaction Id was included in the request, it will be echoed back in the ACK/NACK response.

an example of the NACK response:

0xF0 0x00 0x21 0x45 0x7E 0x00 0x77 0x20 0xF7

Controller events

A Controller Event is a special type of SysEx message that Electra One sends out when something important occurs. These events are typically triggered by user actions or as part of handling incoming SysEx messages or external MIDI control commands.

The controller may send an event message when:

  • Switching a page
  • Switching a preset
  • Changing the Control Set
  • Touching any knob
  • Connecting a USB device
  • Acknowledging a command
  • Sending a log message at the user's request

Some event messages are always sent when the event occurs. Others require the user (or software) to explicitly subscribe in order to receive them. Details on which events require subscriptions — and how to subscribe — are provided in the sections below.

Querying data from the controller

This section covers the set of queries used to retrieve information from the Electra One controller. The data returned may include runtime information, static configuration, or files stored internally on the controller.

Get Electra info

The Electra One MIDI controller can provide information about its hardware and the currently loaded firmware upon request.

This call is useful when you need to check if the connected Electra One is working properly and to retrieve details about the firmware it is running.

For example, the Electra App and the Electra Editor use this call to verify that the controller is connected correctly and to display the connection status indicator.

Request

0xF0 0x00 0x21 0x45 0x02 0x7F 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x7F info-json-data 0xF7

An example of info-json-data
json
{
   "versionText":"v4.0.0",
   "versionSeq":400000000,
   "serial":"EO2-5301787f",
   "hwRevision":"3.0",
   "model":"mk2",
   "modelNum":2
}

The request may carry one reference byte:

0xF0 0x00 0x21 0x45 0x02 0x7F reference 0xF7

The reply to a request with a reference byte has two more fields: port, the USB device port the request came in on (0 Port 1, 1 Port 2, 2 CTRL), and reference, the byte as it was sent. A host can send the request on each of its ports with a different reference to find out which port is which.

json
{
   "versionText":"v4.0.0",
   "versionSeq":400000000,
   "serial":"EO2-5301787f",
   "hwRevision":"3.0",
   "model":"mk2",
   "modelNum":2,
   "port":2,
   "reference":5
}

Get App info

A request to fetch the name of the application running on the controller and the name of the current preset.

Request

0xF0 0x00 0x21 0x45 0x02 0x7C 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x7C app-info-json-data 0xF7

An example of app-info-json-data
json
{
   "app":"Midi Controller",
   "preset":"ADSR Test"
}

preset is left out when the controller has no preset name to report.

Get Run-time information

A request call to fetch the run-time information from the Electra firmware: memory, uptime, the overrun counters, and the System stats (stats) with the processor load and the latencies of the last minute. The System stats are what the System stats tab of the Controller page in the web application shows, and what a script or an AI assistant tuning a preset reads back.

Request

0xF0 0x00 0x21 0x45 0x02 0x7E 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x7E runtime-json-data 0xF7

An example of runtime-json-data
json
{
  "freeRam": 31245312,
  "uptime": 21627,
  "midiDrops": 0,
  "callbackDrops": 0,
  "callbackRuns": 1240,
  "timerLoad": 12,
  "timerSkipped": 0,
  "scriptAborts": 0,
  "timerErrors": 0,
  "remoteCoalesced": 0,
  "remoteDrops": 0,
  "modes": {
    "lowSensitivity": false,
    "midiLearn": true,
    "debug": false,
    "timer": true,
    "screenshot": false
  },
  "stats": {
    "win": 60,
    "since": 84210,
    "cpu": [23, 41],
    "loop": [998, 960],
    "lat": {
      "router": [171, 912, 3402],
      "midiMap": [1450, 4200, 3402],
      "uiMap": [1120, 2600, 58]
    },
    "mem": { "heap": 31245312, "peak": 2309120, "lua": 212, "stack": [61, "Application Thread"] },
    "q": { "in": 0, "io": 12, "dev": 0, "host": 0, "rtr": 0, "map": 4, "cmd": 0 },
    "over": {
      "timerSkip": 0, "timerErr": 0, "abort": 0,
      "midiOut": 0, "midiIn": 0, "ioTmo": 0, "cb": 0,
      "map": 0, "remote": 0, "router": 0,
      "paintLate": 2, "paintMax": 31
    }
  }
}
The top-level fields
  • freeRam bytes of heap free. uptime milliseconds since boot.
  • midiDrops outgoing packets thrown away because a port stopped draining for 250 ms. callbackDrops / callbackRuns Lua MIDI callbacks shed and run. timerLoad the heaviest timer callback's share of the application thread in parts per thousand, over the last few seconds; timerSkipped ticks given up on; timerErrors callbacks that raised; scriptAborts scripts stopped by force. remoteCoalesced / remoteDrops Remote knob traffic absorbed and lost. All of these count since boot.
The modes section

The modes that change what the controller does, each true while it is on. They are the modes the bottom bar shows an icon for.

  • lowSensitivity the knobs move in fine steps.
  • midiLearn MIDI learn is on: the next incoming message is taken for a control.
  • debug the Lua debugger is attached to the current preset's script.
  • timer a preset timer is running, in any preset that is running, pinned presets included. Reported within a fraction of a second of the timer being enabled or disabled.
  • screenshot a screenshot is being written to the card. The picture itself is taken first, before the flag goes on, so the icon is never in it. The application thread that answers this request is busy while a screenshot is written, so a reply is unlikely to report true.
The System stats (stats)

Compact by design: where the meaning of a position is fixed the value is an array, and every number is an integer. Earlier firmware reports the same object under the key perf.

  • win seconds the window covers, at most 60. since milliseconds since the counters were last reset (see Reset System stats), or since boot.
  • cpu [average, worst second] percent of processor time spent busy, sampled once a second over the window. Idle time is what the scheduler's idle loop accounted for; everything else, interrupts included, is busy.
  • loop [average, slowest second] passes of the application thread's run loop per second. A healthy controller sits near 1000; a low figure means the application thread is being starved, which no other number shows.
  • lat latencies in microseconds, each [average, maximum, count] over the window. router: a MIDI packet's arrival on the USB or DIN thread to its being queued for every routed destination; only forwarded packets count. midiMap: arrival to the parameter map having the value on the application thread, queue wait included. uiMap: a knob turn, button press or screen touch being read to the first parameter map write it causes; an input that writes no parameter, such as a page switch, is not counted. A count of zero means there was no such traffic in the window.
  • mem heap bytes free, peak the most heap ever in use at once, lua the Lua heaps of the active presets in KB, and stack [percent used, thread name] for the thread whose stack has come closest to overflowing (absent where the platform cannot tell).
  • q the fullest each watched queue got in the window, in percent: in incoming MIDI, io outgoing DIN, dev outgoing USB device, host outgoing USB host, rtr the router thread, map parameter updates from the MIDI thread to the application thread, cmd the SysEx command queue. Drops follow at 100.
  • over overruns since the last reset. timerSkip, timerErr, abort are the timer and script counters above, rebased; midiOut outgoing drops; midiIn USB packets dropped on the way in; ioTmo DIN transmit timeouts; cb Lua MIDI callbacks shed; map parameter updates dropped; remote Remote knob events dropped; router packets the router thread dropped; paintLate display passes that overran the 16 ms frame; paintMax the longest display pass in milliseconds. Every one of these is zero on a controller that is keeping up.

The figures cost the firmware nothing worth measuring: a latency sample is a cycle-counter read and a few stores, and the per-second bookkeeping is one comparison per run-loop pass. They are always on.

Get Preset

Get preset request retrieves the preset JSON stored in a specific preset slot on the controller. If no bank number or slot number is provided, the controller will return the preset from the currently active slot. If both parameters are provided, the controller will fetch the preset from the specified bank and slot.

A preset is stored as a preset.json file in the preset slot.

Request

Retrieve the JSON of the currently active preset:

0xF0 0x00 0x21 0x45 0x02 0x01 0xF7

Retrieve a preset by specifying its bank number and slot number:

0xF0 0x00 0x21 0x45 0x02 0x01 bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x01 preset-json-data 0xF7

Electra One MIDI controller responds with the SysEx message that has exactly the same format as the Preset upload message. Thus, a SysEx message downloaded with the Get preset call can be used to upload the preset to Electra's active preset slot later on.

Detailed information about preset-json-data is provided at Preset format description

An example of preset-json-data
json
{
   "version": 2,
   "name": "ADSR Test",
   "projectId": "d8WjdwYrP3lRyyx8nEMF",
   "pages": [
      ...
   ],
   "devices": [
      ...
   ],
   "overlays": [
      ...
   ],
   "groups": [
      ...
   ],
   "controls": [
      ...
   ]
}

Get Lua script

Get Lua script request retrieves the main Lua script in a specific preset slot on the controller. If no bank number or slot number is provided, the controller will return the Lua script from the currently active slot. If both parameters are provided, the controller will fetch the Lua script from the specified bank and slot.

The main Lua script refers to the script file that runs when the preset is initialized. This request only retrieves the main script, it cannot be used to fetch additional Lua files. Any extra Lua files must be accessed separately using the SysEx File Transfer API.

A Lua script is stored as a main.lua file in the preset slot.

Request

Retrieve the Lua script of the currently active preset:

0xF0 0x00 0x21 0x45 0x02 0x0C 0xF7

Retrieve a Lua script by specifying its bank number and slot number:

0xF0 0x00 0x21 0x45 0x02 0x0C bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x0C script-script-code 0xF7

Detailed information about developing Lua script applications is provided at Electra One Preset Lua Extension documentation.

An example of script-script-code
lua
-- Demo application

-- the Setup
clockCounter = 0
beatEnabled = 0

-- User functions
function myPrint(text)
    print("my Lua: " .. text)
end

-- Standard callbacks
function midi.onClock(midiInput)
    if beatEnabled == 1 then
        if math.mod(clockCounter, 24) == 0 then
            myPrint("midi beat: interface=" .. midiInput.interface)
        end
    end
    clockCounter = clockCounter + 1
end

function onButtonDown(buttonId)
    myPrint("button " .. buttonId .. " pressed")

    if buttonId == BUTTON_1 then
        myPrint("Beat enabled")
        beatEnabled = 1
    elseif buttonId == BUTTON_4 then
        myPrint("Beat disabled")
        beatEnabled = 0
    end
end

Get Device overrides

This request retrieves the Device overrides stored in a specific preset slot on the controller. If no bank or slot number is provided, the controller will return the overrides from the currently active preset. If both parameters are provided, it will return the overrides from the specified bank and slot.

A Device override is a custom modification of the devices used in a preset. It allows users to change the MIDI ports and channels assigned to devices without modifying the preset itself, making it easier to adapt presets to different setups or hardware configurations.

A Device overrides definition is stored as an overrides.json file in the preset slot. Its format is described in Device Overrides format.

Request

Retrieve the Device overrides of the currently active preset:

0xF0 0x00 0x21 0x45 0x02 0x0F 0xF7

Retrieve a Device overrides by specifying its bank number and slot number:

0xF0 0x00 0x21 0x45 0x02 0x0F bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x0F preset-devices-json-data 0xF7

An example of preset-devices-json-data
json
{
   "version":1,
   "devices":[
      {
         "id":1,
         "name":"Selection Device",
         "interfaces":[
            "midiIo",
            "midiUsbDev",
            "midiUsbHost"
         ],
         "port":"port1",
         "channel":4,
         "rate":10
      },
      {
         "id":2,
         "name":"OP-XY",
         "interfaces":[
            "midiUsbHost"
         ],
         "port":"port1",
         "channel":1,
         "rate":10
      }
   ],
   "buttons":{
      "leftTop":{},
      "leftMiddle":{},
      "leftBottom":{},
      "rightTop":{},
      "rightMiddle":{},
      "rightBottom":{}
   }
}

Get Persisted data

This request retrieves the persisted preset data stored in a specific preset slot on the controller. If no bank or slot number is provided, the controller returns the persisted data from the currently active slot. If both parameters are provided, the data is retrieved from the specified bank and slot.

Persisted preset data is a JSON file that contains a Lua table previously saved using the persist() function. Preset developers can use this feature to store custom configuration settings, runtime values, and other important data that should remain available even after the controller is restarted.

A Persisted data is stored as a data.json file in the preset slot.

Request

Retrieve persisted data of the currently active preset:

0xF0 0x00 0x21 0x45 0x02 0x12 0xF7

Retrieve persisted data by specifying its bank number and slot number:

0xF0 0x00 0x21 0x45 0x02 0x12 bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x12 datafile-json-data 0xF7

An example of datafile-json-data
json
{
   array = { 1, 2, 3 },
   objArray = {
      { key1 = "text" },
      { key2 = 1.2 },
      { key3 = true }
   },
   number = 1.42,
   text = "hello table",
   boolean = false
}

Get Performance

Get Performance request retrieves the performance JSON stored in a specific preset slot on the controller. If no bank number or slot number is provided, the controller will return the performance data from the currently active slot. If both parameters are provided, the controller will fetch the performace from the specified bank and slot.

A Performance is a structured JSON file that defines a custom page made up of controls and macro controls that reference existing controls within the preset. It allows users to build a personalized performance view with re-arranged layout, without modifying the original preset.

A Performance is stored as a performance.json file in the preset slot.

Request

Retrieve the performance of the currently active preset:

0xF0 0x00 0x21 0x45 0x02 0x11 0xF7

Retrieve the performance by specifying its bank number and slot number:

0xF0 0x00 0x21 0x45 0x02 0x11 bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x11 performance-json-data 0xF7

Detailed information about performance-json-data is provided at Performance format description

An example of performance-json-data
json
{
   "version":1,
   "references":[
      {
         "controlSetId":1,
         "potId":1,
         "controlId":1,
         "name":"Fader A"
      },
      {
         "controlSetId":1,
         "potId":6,
         "valueRefs":[
            {
               "controlId":1,
               "valueId":"value",
               "channel":1,
               "mode":"dataPipe",
               "pipe": {
                  "name":"output",
                  "bankNumber":5,
                  "slot":1
               }
            },
            {
               "controlId":2,
               "valueId":"value",
               "mode":"setValue",
               "depth":50
            }
         ],
         "name":"All faders"
      }
   ],
   "groups":[
      {
         "id":4,
         "pageId":1,
         "name":"GROUP LABEL",
         "color":"ffffff",
         "bounds":[
            14,
            6,
            993,
            171
         ]
      }
   ]
}

Get Configuration

A request to fetch the current Electra One configuration. This configuration file defines the general behavior and settings of the controller

Request

0xF0 0x00 0x21 0x45 0x02 0x02 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x02 configuration-json-data 0xF7

Detailed information about configuration-json-data is provided at Configuration format description

An example of configuration-json-data
json
{
   "version": 2,
   "router": {
      ...
   },
   "presetBanks": [
      ...
   ],
   "pinnedSlots": [
      ...
   ],
   "usbHostAssignments": [
      ...
   ],
   "midiControl": {
      ...
   },
   "remote": {
      ...
   },
   "uiFeatures": {
      ...
   },
   "hardware": {
      ...
   },
   "satellite": {
      ...
   }
}

Get List of presets

This request retrieves a list of all presets that are currently saved on the controller.

Request

0xF0 0x00 0x21 0x45 0x02 0x04 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x04 preset-list-json-data 0xF7

An example of preset-list-json-data
json
{
   "version":1,
   "current":{
      "bankNumber":5,
      "slot":0
   },
   "presets":[
      {
         "slot":0,
         "bankNumber":5,
         "name":"EMM Ctrl 10.52",
         "projectId":"4bJi5KIqgQB8th333Na7",
         "hasLua":true,
         "hasRouter":false,
         "isPinned":false,
         "active":true,
         "alreadyLoaded":true
      },
      {
         "slot":3,
         "bankNumber":5,
         "name":"VCV Rack 2",
         "projectId":"4rIzUF8a60kXiYsyvlTN",
         "hasLua":true,
         "hasRouter":true,
         "isPinned":true,
         "active":true,
         "alreadyLoaded":true
      },
      {
         "slot":11,
         "bankNumber":5,
         "name":"Rhodes Chroma",
         "projectId":"HxepQNRfBdIo0CyMyCqu",
         "hasLua":false,
         "hasRouter":false,
         "isPinned":false,
         "active":false,
         "alreadyLoaded":false
      }
   ]
}

The list contains only the slots that hold a preset.

  • hasLua says whether the slot has a Lua script, main.lua.
  • hasRouter says whether the slot has a router script, a router.lua that is not empty. See Preset router scripts.
  • isPinned says whether the slot is pinned - whether the preset in it keeps running when the user switches away. A host can change it with Pin a Preset slot.
  • active says whether the preset is running now, either on the screen or pinned in the background.
  • alreadyLoaded says whether the preset has been loaded since the controller started. It goes back to false when the slot's preset is replaced.

Get Preset slot information

This request retrieves information about the Preset slot and the preset stored in it. When the bank number and slot are left out, the request describes the currently active slot.

Request

0xF0 0x00 0x21 0x45 0x02 0x08 bankNumber slot 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x08 preset-slot-json-data 0xF7

An example of preset-slot-json-data
json
{
   "version":1,
   "bankNumber":0,
   "slot":0,
   "name":"Demo preset",
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "hasLua":true,
   "hasRouter":false,
   "isPinned":false,
   "active":true,
   "alreadyLoaded":true,
   "files":[
      {
         "name":"preset.json",
         "md5":"b58f9ee9391b7e49f471fcbb2deb536c"
      },
      {
         "name":"main.lua",
         "md5":"7f00373c5818f254ef19a82217a18be0"
      },
      {
         "name":"overrides.json",
         "md5":"5dec6bf7eebb098dda3d706fe6c2f115"
      }
   ]
}

The slot fields are those of preset-list-json-data. files lists every file in the slot with its MD5 digest.

Get List of snapshots

A request to fetch the list of snapshots for a preset associated with a specific projectId.

Request

0xF0 0x00 0x21 0x45 0x02 0x05 snaphost-list-request-json-data 0xF7

An example of snapshot-list-request-json-data
json
{
  "projectId": "IJopUYMf2TW1PH7GNYxD"
}

Response

0xF0 0x00 0x21 0x45 0x01 0x05 snapshot-list-json-data 0xF7

An example of snapshot-list-json-data
json
{
   "version":1,
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "snapshots":[
      {
         "slot":0,
         "bankNumber":0,
         "name":"A0",
         "color":"FFFFFF",
         "filename":"s4380877.json"
      }
   ]
}

Get Snapshot data

A request to fetch snapshot data stored in a specific snapshot bank and slot.

Request

0xF0 0x00 0x21 0x45 0x02 0x03 snapshot-request-json-data 0xF7

An example of snapshot-request-json-data
json
{
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "bankNumber":0,
   "slot":0
}

Response

0xF0 0x00 0x21 0x45 0x01 0x03 snapshot-json-data 0xF7

An example of snapshot-json-data
json
{
   "version":1,
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "name":"House piano",
   "color":"E4660E",
   "parameters":[
      {
         "deviceId":1,
         "messageType":"cc7",
         "parameterNumber":102,
         "midiValue":1
      },
      {
         "deviceId":2,
         "messageType":"nrpn",
         "parameterNumber":2,
         "midiValue":3800,
         "overrideText":"-12 dB"
      }
   ]
}

name and color are the same values a snapshot-list-json-data entry reports for this slot. They make snapshot-json-data a complete, standalone document: the Upload Snapshot command reads name/color straight back out of a file with this shape, so downloading a snapshot and re-uploading the same file reproduces it exactly, name and color included.

Each entry of parameters is one parameter the snapshot sets:

  • deviceId the id of the device in the preset
  • messageType the message type as a name: virtual, cc7, cc14, nrpn, rpn, note, program, sysex, start, stop, tune, atpoly, atchannel, pitchbend, spp, relcc or none
  • parameterNumber the parameter number
  • midiValue the MIDI value
  • overrideText the value text override stored with the parameter. It is present only when the override is on.

Get List of captures

A request to fetch the list of captures for a preset associated with a specific projectId.

Request

0xF0 0x00 0x21 0x45 0x02 0x31 capture-list-request-json-data 0xF7

An example of capture-list-request-json-data
json
{
  "projectId": "IJopUYMf2TW1PH7GNYxD"
}

Response

0xF0 0x00 0x21 0x45 0x01 0x31 capture-list-json-data 0xF7

An example of capture-list-json-data
json
{
   "version":1,
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "captures":[
      {
         "slot":0,
         "bankNumber":0,
         "name":"A0",
         "color":"FFFFFF",
         "filename":"s5620078.mid",
         "midiInterface":"midiUsbDev",
         "port":0,
         "syncToClock":false,
         "loop":false,
         "rootNote":"C4"
      }
   ]
}

port is 0-based, the same convention used everywhere else in this API (see Set Events MIDI port) - 0 is Port 1.

syncToClock, loop and rootNote describe how the capture plays back - see Update Capture for what each one does.

Get Capture data

A request to fetch capture data stored in a specific capture bank and slot.

A capture is a raw MIDI file, so unlike every other payload in this API it is not 7-bit safe. The controller Base64 encodes it before it goes in the SysEx body; decode it back to bytes after removing the framing.

Request

0xF0 0x00 0x21 0x45 0x02 0x30 capture-request-json-data 0xF7

An example of capture-request-json-data
json
{
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "bankNumber":0,
   "slot":0
}

Response

0xF0 0x00 0x21 0x45 0x01 0x30 capture-data 0xF7

Get List of snapshot banks

A request to fetch the names of the snapshot banks of a preset associated with a specific projectId.

Snapshot banks are called Bank 1 .. Bank n until the user gives them names of their own. The reply lists every bank the controller has, named or not, and an unnamed bank comes back with the very label the controller shows on screen - so a host application can label its own bank buttons without reproducing that rule.

Request

0xF0 0x00 0x21 0x45 0x02 0x38 bank-list-request-json-data 0xF7

An example of bank-list-request-json-data
json
{
  "projectId": "IJopUYMf2TW1PH7GNYxD"
}

Response

0xF0 0x00 0x21 0x45 0x01 0x38 bank-list-json-data 0xF7

An example of bank-list-json-data
json
{
   "version":1,
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "banks":[
      {
         "bankNumber":0,
         "name":"Lead sounds"
      },
      {
         "bankNumber":1,
         "name":"Bank 2"
      }
   ]
}

Get List of capture banks

The same for capture banks. Snapshot banks and capture banks are named independently of one another.

Request

0xF0 0x00 0x21 0x45 0x02 0x3A bank-list-request-json-data 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x3A bank-list-json-data 0xF7

The payloads are exactly those of Get List of snapshot banks.

Get USB Host devices

A request to fetch a list of all devices currently connected to the controller’s USB Host port.

Request

0xF0 0x00 0x21 0x45 0x02 0x10 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x10 usb-host-devices-json-data 0xF7

An example of usb-host-devices-json-data
json
{
   "version":1,
   "devices":[
      {
         "manufacturer":"ESI",
         "product":"Xjam",
         "serialNumber":"123456",
         "vid":9587,
         "pid":54,
         "driver":"MIDI",
         "ports":[
            {
               "devicePort":1,
               "name":"Port 1",
               "electraPort":"port1"
            },
            {
               "devicePort":2,
               "name":"Port 2"
            }
         ]
      }
   ]
}
  • driver is the driver that claimed the device: MIDI for a MIDI device, DMX for a uDMX dongle.
  • ports lists the MIDI cables of the device. It is present only for MIDI devices.
  • electraPort is the Electra port the cable is routed to. It is left out when the cable is not routed. See usbHostAssignments in the Configuration format.

Get Parameter map

A request to fetch the parameter map of the current preset: every parameter the preset's controls use, with its current MIDI value.

Request

0xF0 0x00 0x21 0x45 0x02 0x41 0xF7

Response

0xF0 0x00 0x21 0x45 0x01 0x41 parameter-map-json-data 0xF7

An example of parameter-map-json-data
json
{
   "version":1,
   "projectId":"IJopUYMf2TW1PH7GNYxD",
   "parameters":[
      {
         "deviceId":1,
         "messageType":"cc7",
         "parameterNumber":10,
         "midiValue":64
      },
      {
         "deviceId":1,
         "messageType":"nrpn",
         "parameterNumber":1024,
         "midiValue":8191,
         "overrideText":"6.2dB"
      }
   ]
}

The entries have the same fields as the parameters of snapshot-json-data. When no preset is loaded, the controller sends nothing.

Uploading data to the controller

The commands in this section are used to upload data to the Electra One controller. They allow you to send presets, Lua scripts, and other data files directly to the device.

Since an upload is a command, the controller will respond with an ACK if the operation was successful, or a NACK if it failed.

Upload Preset

The preset upload command is used to send a new preset to the Electra One MIDI controller. The preset is always uploaded to the currently selected (active) preset slot.

Once the upload is complete, the preset is immediately activated and ready to use. An uploaded preset is stored as a preset.json file in the preset slot.

0xF0 0x00 0x21 0x45 0x01 0x01 preset-json-data 0xF7

Detailed information about preset-json-data is provided at Preset format description

On success this also triggers a Preset list change event.

Upload Lua script

The Lua script upload command is used to upload and execute a new Electra One Preset Lua Extension script. The script is uploaded to the currently selected (active) preset slot.

The Lua script refers to the main script file that runs when the preset is initialized. This command cannot be used to upload additional Lua files. Any extra Lua files must be uploaded separately using the SysEx File Transfer API.

An uploaded Lua script is stored as a main.lua file in the preset slot.

0xF0 0x00 0x21 0x45 0x01 0x0C script-source-code 0xF7

Detailed information about developing Lua script applications is provided at Electra One Lua script documentation.

Upload Device overrides

The Device Overrides upload command is used to upload and replace the device definitions in the current preset. The overrides are uploaded to the currently selected (active) preset slot.

A Device Override is a custom modification of the devices used in a preset. It allows users to change the MIDI ports and channels assigned to devices without modifying the preset itself, making it easier to adapt presets to different setups or hardware configurations.

An uploaded Devices definition is stored as an overrides.json file in the preset slot, and is applied to the preset that is loaded. Its format is described in Device Overrides format.

0xF0 0x00 0x21 0x45 0x01 0x0F preset-devices-json-data 0xF7

On success this also triggers a Preset list change event.

Upload Persisted data

The Persisted data upload command is used to upload and replace the JSON data that will be interpreted as a persisted Lua table in the current preset. The data is uploaded to the currently selected (active) preset slot.

Persisted preset data is a JSON file that contains a Lua table previously saved using the persist() function. This data can be loaded back into a Lua table using the recall() function. Preset developers can use this feature to store custom configuration settings, runtime values, and other important data that should remain available even after the controller is restarted.

An uploaded Persisted data is stored as a data.json file in the preset slot.

0xF0 0x00 0x21 0x45 0x01 0x12 datafile-json-data 0xF7

On success this also triggers a Preset list change event.

Upload Performace

The Performance upload command is used to upload and replace the performance JSON data in a specific preset slot on the controller. The data is always uploaded to the currently selected (active) slot.

A Performance is a structured JSON file that defines a custom page made up of controls and macro controls that reference existing controls within the preset. It allows users to build a personalized performance view with re-arranged layout, without modifying the original preset.

An uploaded Performance data is stored as a performance.json file in the preset slot.

0xF0 0x00 0x21 0x45 0x01 0x11 performance-json-data 0xF7

On success this also triggers a Preset list change event.

Upload Configuration

The configuration upload call is meant to upload and apply a new Electra One configuration to the controller.

0xF0 0x00 0x21 0x45 0x01 0x02 configuration-json-data 0xF7

Detailed information about configuration-json-data is provided at Configuration format description

Upload Snapshot

The Snapshot upload command imports a snapshot file into a bank and slot. Unlike the other uploads in this section, the destination isn't the currently active slot - send Set Snapshot slot first to arm the bank/slot the upload lands in.

The snapshot's name and color come from the file itself, not from a separate JSON field - it's the same format Get Snapshot data returns, with a name/color header the way a snapshot-list-json-data entry describes one.

messageType may be given as a name, as Get Snapshot data returns it, or as a number. A snapshot file stored on the card by earlier firmware uses the number.

On success this also triggers a Snapshot list change event, the same as any other snapshot mutation.

0xF0 0x00 0x21 0x45 0x01 0x03 snapshot-json-data 0xF7

Upload Capture

The Capture upload command imports a .mid file as a capture into a bank and slot. As with Upload Snapshot, send Set Capture slot first to arm the destination.

A capture is a raw MIDI file, so like Get Capture data this is not 7-bit safe - Base64 encode the file before sending it. Unlike a snapshot file, a raw MIDI file has nowhere to carry a name/color header of its own, so the imported capture is stored with a generated name and color, no recorded MIDI source (midiInterface/port left unset), syncToClock/loop both false, and rootNote defaulted to "C4"; follow up with Update Capture to set them - a client that wants a Get/Upload round trip to preserve everything (e.g. the electraone CLI's capture get/capture import) reads them from capture-list-json-data and reapplies them with Update Capture after the upload.

On success this also triggers a Capture list change event, the same as any other capture mutation.

0xF0 0x00 0x21 0x45 0x01 0x30 capture-data 0xF7

Persistent commands

Persistent commands make permanent changes to the data stored on the controller. This means that any changes made using persistent commands will still be in effect even after the controller is powered off and restarted.

Remove Preset

The Remove Preset command permanently deletes a preset identified by its bank number and slot. The controller reflects this change by replacing the original preset with an empty one. The command remove all additional files related to the preset.

0xF0 0x00 0x21 0x45 0x05 0x01 bank-number slot 0xF7

On success this also triggers a Preset list change event.

Remove Lua script

The Remove Lua Script command permanently deletes the main Lua script file associated with a specific bank number and slot. This command cannot be used to remove additional files; to delete those, use the Clear Preset Slot files command instead.

0xF0 0x00 0x21 0x45 0x05 0x0C bank-number slot 0xF7

On success this also triggers a Preset list change event.

Remove Config

The Remove Configuration command permanently deletes the configuration file from the controller.

0xF0 0x00 0x21 0x45 0x05 0x02 0xF7

Remove Snapshot

The Remove Snapshot command permanently deletes a snapshot from the controller.

0xF0 0x00 0x21 0x45 0x05 0x06 snapshot-id-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the snapshot-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 2,
   "slot": 5
}

Remove Capture

The Remove Capture command permanently deletes a capture from the controller.

0xF0 0x00 0x21 0x45 0x05 0x32 capture-id-json-data 0xF7

On success this also triggers a Capture list change event.


An example of the capture-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 0,
   "slot": 0
}

Clear Preset slot

The Clear Preset Slot command permanently removes all files stored in the preset slot identified by the bank number and slot. This command does not reload the preset on the controller, meaning the original preset remains in the controller's volatile memory.

0xF0 0x00 0x21 0x45 0x05 0x08 bank-number slot 0xF7

On success this also triggers a Preset list change event.

Update Snapshot

The Update Snapshot command updates the attributes of an existing snapshot.

0xF0 0x00 0x21 0x45 0x04 0x06 snapshot-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the snapshot-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 0,
   "slot": 5,
   "name": "House piano",
   "color": "E4660E"
}

Update Capture

The Update Capture command updates the attributes of an existing capture.

midiInterface, port, syncToClock, loop and rootNote are all optional and only touched when present - sending just name/color leaves every other attribute alone, so a rename doesn't need to know or resend the rest.

0xF0 0x00 0x21 0x45 0x04 0x32 capture-json-data 0xF7

On success this also triggers a Capture list change event.


An example of the capture-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 1,
   "slot": 4,
   "name": "Synths bank",
   "color": "DD1530",
   "midiInterface": "midiUsbDev",
   "port": 0,
   "syncToClock": false,
   "loop": true,
   "rootNote": "C3"
}

midiInterface is one of midiIo, midiUsbDev, midiUsbHost, or midiAll. port is 0-based, the same convention used everywhere else in this API (see Set Events MIDI port) - it matches the port a capture-list-json-data entry reports, so a value read from a list can be written straight back.

syncToClock (boolean) plays the capture in step with incoming MIDI clock instead of following the tempo map recorded in the file - use it for a capture that needs to stay locked to an external sequencer or DAW. loop (boolean) restarts the capture from the beginning when it reaches the end, instead of stopping.

rootNote (string) is the note the capture is considered to have been played at; playback triggered from a note other than the capture's own rootNote transposes the whole performance by the distance between the two. Asking for a capture's own rootNote plays it back untransposed. It is written as a note name, not a MIDI number - "C4", "C#4", and so on, where C4 is middle C (MIDI note 60) and the valid range is C-1 through G9 (MIDI notes 0-127). Only sharps are ever sent back by the controller, but both sharps (C#4) and flats (Db4) are accepted on input. A value that doesn't parse as a note name is ignored, leaving the stored root note unchanged - same as omitting the field.

Update Snapshot bank

The Update Snapshot Bank command sets the name of a snapshot bank. A bank name may be up to 20 characters long; anything longer is cut to 20. Names are stored per projectId, so the same preset loaded into two slots shares them.

0xF0 0x00 0x21 0x45 0x04 0x37 snapshot-bank-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the snapshot-bank-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 0,
   "name": "Lead sounds"
}

An empty name is taken as the user removing the name, and does exactly what Remove Snapshot bank name does. A bankNumber the controller does not have is refused with a NACK.

Update Capture bank

The same for a capture bank.

0xF0 0x00 0x21 0x45 0x04 0x39 capture-bank-json-data 0xF7

On success this also triggers a Capture list change event.


The payload is exactly that of Update Snapshot bank.

Remove Snapshot bank name

Puts one snapshot bank back to its default Bank n name.

0xF0 0x00 0x21 0x45 0x05 0x37 snapshot-bank-id-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the snapshot-bank-id-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "bankNumber": 0
}

Remove all Snapshot bank names

Puts every snapshot bank of one project back to its default Bank n name. The bank list resource is used rather than the bank one, the same way Remove files from location addresses a whole location rather than a single file.

0xF0 0x00 0x21 0x45 0x05 0x38 project-id-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the project-id-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY"
}

Remove Capture bank name

Puts one capture bank back to its default Bank n name.

0xF0 0x00 0x21 0x45 0x05 0x39 capture-bank-id-json-data 0xF7

On success this also triggers a Capture list change event.


The payload is exactly that of Remove Snapshot bank name.

Remove all Capture bank names

Puts every capture bank of one project back to its default Bank n name.

0xF0 0x00 0x21 0x45 0x05 0x3A project-id-json-data 0xF7

On success this also triggers a Capture list change event.


The payload is exactly that of Remove all Snapshot bank names.

Swap Snapshots

The Swap Snapshots command exchanges the snapshots between two snapshot slots. If one of the slots is empty, the operation becomes a simple move instead of a swap.

0xF0 0x00 0x21 0x45 0x06 0x06 snapshot-ids-json-data 0xF7

On success this also triggers a Snapshot list change event.


An example of the snapshot-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "fromBankNumber": 0,
   "fromSlot": 5,
   "toBankNumber": 0,
   "toSlot": 4
}

Swap Captures

The Swap Captures command exchanges the captures between two capture slots. If one of the slots is empty, the operation becomes a simple move instead of a swap.

0xF0 0x00 0x21 0x45 0x06 0x32 capture-ids-json-data 0xF7

On success this also triggers a Capture list change event.


An example of the capture-json-data
json
{
   "projectId": "SCI1mU1v6ojnm8IojuhY",
   "fromBankNumber": 0,
   "fromSlot": 0,
   "toBankNumber": 1,
   "toSlot": 0
}

Runtime commands

Runtime commands change how the controller behaves while it’s running, but these changes are not saved and will be lost after a restart.

Switch Preset slot

The Preset lot switch command changes the active preset slot. If the selected slot contains a preset, it will be loaded. If the slot is empty, it becomes the active slot and can be used to load a new preset.

0xF0 0x00 0x21 0x45 0x09 0x08 bank-number slot 0xF7

On success this also triggers a Preset switch event with the bank number and slot. A bank number or slot out of range is answered with a NACK.

Load Preloaded preset

The Load Preloaded preset command copies a preloaded preset into a preset slot and activates it. This allows the controller to quickly load and switch to a prepared preset without using standard upload procedures.

Preloaded presets are stored in special location on the controller. Users can upload presets to these locations either by using the USB mass storage mode in the bootloader or by using the SysEx File Transfer API.

0xF0 0x00 0x21 0x45 0x04 0x08 preset-slot-json-data 0xF7

On success this also triggers a Preset switch event with the bank number and slot.


An example of the preset-slot-json-data
json
{
   "bankNumber": 5,
   "slot": 1,
   "preset": "xot/ableton/Cabinet"
}

Pin a Preset slot

A pinned preset keeps running after the user switches away from it: it goes on receiving MIDI, running its Lua script and its router, without being on the screen. The pin is a property of the slot, and the preset list publishes it as isPinned.

The same Update / Preset slot message carries it - a document with pinned instead of preset changes the slot's pin and nothing else. The controller answers with an ACK and then sends a Preset list change event, so a host showing the list redraws from what the controller says rather than from what it asked for.

0xF0 0x00 0x21 0x45 0x04 0x08 preset-slot-json-data 0xF7

An example of the preset-slot-json-data
json
{
   "bankNumber": 0,
   "slot": 3,
   "pinned": true
}

Unpinning a preset that is running in the background stops it. Pinning a slot that has not been loaded marks it: it starts when the slot is next entered, and at every boot once SAVE STATE has written the controller's pinnedSlots list. Storing another preset in a pinned slot clears the pin.

A pin lives in the controller's memory until it is saved. This message changes what is running now; it does not write anything. A host that wants its pins to come back after a power cycle sends Save the application state once it has set them - and again after unpinning, or the slot comes back pinned.

Switch Page

The Switch Page command is used to change the active page.

0xF0 0x00 0x21 0x45 0x09 0x0A page-number 0xF7

A page-number out of range is answered with a NACK. The controller sends the Page switch event only while the host is subscribed to Page events, see Subscribe Events.

Switch Control Set

The Switch Control set command changes the currectly selected set of knobs assigned to the on-sreen controls.

0xF0 0x00 0x21 0x45 0x09 0x0B control-set-id 0xF7

A control-set-id out of range is answered with a NACK. The controller sends the Control Set switch event only while the host is subscribed to Control Set events, see Subscribe Events.

Set Preset slot

The Set Preset Slot command changes the currently selected preset bank and slot. However, it does not activate or load the preset in that slot, unlike the Switch Preset Slot command. Instead, Set Preset Slot simply arms the slot as selected for subsequent operations, such as uploading preset files.

0xF0 0x00 0x21 0x45 0x14 0x08 bank-number slot 0xF7

On success this also triggers a Preset list change event. A bank number or slot out of range is answered with a NACK.

Set Snapshot slot

The Set Snapshot Slot command changes the currently selected snapshot bank and slot. The selected slot is then armed for use with subsequent snapshot operations.

0xF0 0x00 0x21 0x45 0x14 0x09 snapshot-slot-json-data 0xF7

An example of snapshot-slot-json-data
json
{
   "projectId":"4bJi5KIqgQB8th333Na7",
   "bankNumber":0,
   "slot":3
}

Set Capture slot

The Set Capture Slot command changes the currently selected capture bank and slot. The selected slot is then armed for use with subsequent capture operations.

0xF0 0x00 0x21 0x45 0x14 0x33 capture-slot-json-data 0xF7

An example of capture-slot-json-data
json
{
   "projectId":"4bJi5KIqgQB8th333Na7",
   "bankNumber":5,
   "slot":11
}

Execute Lua command

The Run Lua Command executes arbitrary Lua commands, effectively serving as an API endpoint for controlling Electra One presets from external devices and applications.

It allows you to remotely manage Electra One presets using Lua commands, offering a powerful way to interact with the controller from external sources. The maximum allowed length of a Lua command is 65,535 bytes.

However, we recommend keeping commands short — commands shorter than 65 bytes are executed significantly faster than longer ones.

To optimize performance, it is better to use this SysEx call to trigger Lua functions defined in a previously uploaded Lua script, rather than sending large blocks of arbitrary Lua code.

0xF0 0x00 0x21 0x45 0x08 0x0D lua-command-text 0xF7

For backwards compatibility, the follwoing message structure is supported too:

0xF0 0x00 0x21 0x45 0x08 0x0C lua-command-text 0xF7

The lua-command-text is free form string containing Lua command to be executed. It is recommended to call predefined functions.

An example of the lua-command-text
lua
hideControl (1)

or

lua
print ("Hello MIDI world!")

Reload Preset slot

The Reload Preset Slot command reinitializes and restarts the preset stored in the specified preset slot. The preset instance currently running in that slot will be terminated. If available, associated Lua scripts, Device Overrides, and Performance data will also be reinitialized.

Reload the preset in the currently active slot:

0xF0 0x00 0x21 0x45 0x08 0x08 0xF7

Reload the preset in a specific bank and slot:

0xF0 0x00 0x21 0x45 0x08 0x08 bankNumber slot 0xF7

On success this also triggers a Preset switch event with the bank number and slot.

Update control

A call to update the name, color, and visibility of a control. These changes are applied at runtime only, which means they will be lost when the Electra One is powered off.

0xF0 0x00 0x21 0x45 0x14 0x07 control-id-lsb control-id-msb control-upadate-json-data 0xF7

The controlId is split into two 7-bit parts: a most significant byte (MSB) and a least significant byte (LSB), using the following logic:

control-id-msb = controlId >> 7
control-id-lsb = controlId & 0x7F

The control-update-json-data may include up to four optional attributes: name, color, visibility, and value. When the control update command is received, any provided attributes will be applied to the control. You only need to include the attributes you want to change — all others can be left out.

Updating the value attribute allows you to set value.text only, which is equivalent to using the SysEx call for overriding the value text.

An example of the control-json-data

change all attrinbutes:

json
{
   "name": "Track 1",
   "color": "FFFFFF",
   "visible": true
}

one attribute only:

json
{
   "name": "Track 2"
}

overriding a value text:

json
{
   "value": {
       "id": "value",
       "text": "6.2dB"
   }
}

Note, when overriding a value text the "id": "value" is not required for single value controls, such as faders, pads, and relative controls. The text is text string of printable ASCII characters, maximum length is 20 characters. Setting the text string with 0 bytes length cancels the value override. When cancelled, the controller will display the current value according to its settings.

Override value text

The Override Value Text command replaces the control’s current displayed value with custom text. It gives developers full control over what is shown on the screen, which is especially useful when working with Relative Control Change messages.

The custom text also overrides the output from Lua Value formatters.

Although value texts can also be overridden using the Control Update command, the Override Value Text command is a more performance-optimized option, as it avoids the overhead of JSON parsing and valueId translation.

0xF0 0x00 0x21 0x45 0x14 0x0E control-id-lsb control-id-msb numeric-value-id text 0xF7

The controlId is split into two 7-bit parts: a most significant byte (MSB) and a least significant byte (LSB), using the following logic:

control-id-msb = controlId >> 7
control-id-lsb = controlId & 0x7F

The numeric-value-id identifies Electra One’s MIDI port as follows. Note: the value Ids must be selected according to the type of control being used.

  • 0x00 default value of single value controls (fader, pads, and relative controls)
  • 0x01 attack, l1, x
  • 0x02 decay, hold, release, r1, y
  • 0x03 sustain, decay, break, release, l2
  • 0x04 release, sustain, slope, r2
  • 0x05 release, sustain, l3
  • 0x06 release, r3
  • 0x07 l4
  • 0x08 r4

The text is text string of printable ASCII characters, maximum length is 19 characters. A longer text is cut to 19 characters. Setting the text string with 0 bytes length cancels the value override. When cancelled, the controller will display the current value according to its settings.

Set Bottom Bar text

The Set Bottom Bar Text command replaces the default text shown in the status bar at the bottom of the screen. The custom text remains visible until the command is called again with a string of 0 bytes in length, which clears the text and restores the default display.

0xF0 0x00 0x21 0x45 0x14 0x77 text 0xF7

The text is text string of printable ASCII characters, maximum length is 32 characters. A longer text is cut to 32 characters. Setting the text string with 0 bytes length cancels the value override. When cancelled, the controller will display the current value according to its settings.

A text that starts with a one-letter tag and a colon, for example E:Validation failed, is shown without the tag on a red bar. Use it to report a failure to the person at the controller.

The controller uses the same red bar on its own for problems it has found: an SD card that is missing or cannot be read, a preset script that did not load, or a preset timer that overruns its period or had to be stopped. Such a report takes precedence over any text set with this command and stays until the problem is gone.

Set Events MIDI port

The Set Event Port command sets the MIDI port used to transmit event notifications triggered by user actions on the controller (e.g., page switching).

0xF0 0x00 0x21 0x45 0x14 0x7B port-number 0xF7

The port-number identifies Electra's MIDI port as follows:

  • 0x00 Port 1
  • 0x01 Port 2
  • 0x02 CTRL

A port-number greater than 0x02 is answered with a NACK.

Subscribe Events

The Subscribe Events command tells the controller which SysEx event messages should be sent out when specific events occur.

0xF0 0x00 0x21 0x45 0x14 0x79 event-flags 0xF7

The event-flags a byte with the following bits (flags). The individual flags must be ORed to produce the final byte value:

  • 0x00 None
  • 0x01 (bit 0) Page events
  • 0x02 (bit 1) Control Set events
  • 0x04 (bit 2) USB Host events
  • 0x08 (bit 3) Pots events
  • 0x10 (bit 4) Touch events
  • 0x20 (bit 5) Button events
  • 0x40 (bit 6) Window events

Page, Control Set, USB Host and Pots events are supported. The Touch, Button and Window bits are reserved and currently send nothing. All other controller events are always sent and need no subscription.

to reset the subscribed events, send a message with the flags set to 0x00 (None).

Control Logger Output

This system call is used to control whether Electra One sends debugging log messages. The command sets a non-volatile flag inside the controller, meaning the logger's status remains saved even after the controller is powered off.

However, startup log messages are always sent, regardless of the logger's enabled or disabled state.

Debug log messages generated by the Lua print() function are always sent out.

0xF0 0x00 0x21 0x45 0x7F 0x7D status log-level 0xF7

List of possible status values:

  • 0x00 disable the logger
  • 0x01 enable the logger. Any value other than 0x00 enables the logger.

The log-level sets the verbosity of log messages sent by the Electra One controller. Higher log levels add extra messages to stream of log messages. The log-level parameter is ignored when the status parameter is set to 0x00.

  • 0x00 critical messages (that cannot be disabled)
  • 0x01 warning messages
  • 0x02 informative messages
  • 0x03 tracing messages

Set Logger MIDI port

The Set Log Port command sets the USB device MIDI port used to transmit log messages. By default, log messages are sent to the Electra Controller CTRL port.

Note: Although log messages are considered a type of controller event, they do not follow the Event Port settings. Instead, they use their own dedicated port, which is configured using this SysEx command.

0xF0 0x00 0x21 0x45 0x14 0x7D port-number reserved 0xF7

The port-number identifies Electra's MIDI port as follows:

  • 0x00 Port 1
  • 0x01 Port 2
  • 0x02 CTRL

Control Window repaints

The Window Repaint command provides control over the graphic component repainting process. It can be used to accumulate multiple individual repaint requests into a single repaint operation, improving overall performance.

0xF0 0x00 0x21 0x45 0x7F 0x7A command reserved 0xF7

The command must be one of the following:

  • 0x00 Stop the window repainting process
  • 0x01 Repaint the window and resume the window repainting process

Note: When repaints are stopped, the controller does not update any graphics on the screen and may appear unresponsive.

Control Debugging

Retired

The single-byte 0x7C debug command described in earlier revisions of this document is not implemented. 0x7C is not an operation byte, so the controller ignores such a message and does not answer it. As a resource byte, 0x7C is Get App info.

Use the Lua debugger commands below instead.

Control Midi learn

The Set MIDI Learn command enables or disables the MIDI Learn functionality on the controller. When enabled, the controller sends MIDI Learn event messages back to the host for all incoming MIDI messages.

While MIDI Learn is active, incoming MIDI messages are not processed in the standard way.

The MIDI Learn event message is described in the Controler events section.

0xF0 0x00 0x21 0x45 0x03 status 0xF7

List of possible status values:

  • 0x00 disable the MIDI learn
  • 0x01 enable the MIDI learn

Any other status value disables MIDI learn. The controller answers with an ACK.

Take a screenshot

The Screenshot command writes a picture of what is currently on the controller's screen to its scratch folder, as a 16-bit BMP named scrn000.bmp, scrn001.bmp and so on. The scratch folder is emptied every time the controller boots, so the numbering starts again from zero after a restart.

0xF0 0x00 0x21 0x45 0x7F 0x76 0xF7

The controller answers with an ACK once the file has been written. That takes a few seconds - the whole framebuffer is read back over the display bus and written to the SD card - so allow a longer reply timeout than for other commands.

The picture is fetched with the File Transfer API: list the tmp location to see what is there, and download one with a Get file request naming {"location":"tmp","type":"screenshot","name":"scrn000"}. A screenshot is the one file the API serves that is not text, so it arrives base64 encoded - see Binary files.

Reset System stats

Starts the System stats (stats) of the run-time information afresh: the latency, load and queue windows are cleared and the overrun counters rebased, so the next Get Run-time information describes only what happened after this call. Send it before a measurement - load a preset, play, then read - so the figures are not diluted by what came before.

0xF0 0x00 0x21 0x45 0x14 0x7E 0xF7

The controller acknowledges with an ACK. The counters shown at the top level of the run-time information keep counting since boot; only the System stats (stats) are rebased.

Save the application state

The Save state command writes the controller's settings, its configuration and the list of pinned preset slots to the SD card. It is the SAVE STATE button in the controller's own settings, reached over SysEx.

0xF0 0x00 0x21 0x45 0x7F 0x75 0xF7

The controller answers with an ACK.

A pin does not survive a power cycle on its own.Pin a preset slot changes what is running now and nothing else; the list read back at the next boot is only written when this command asks for it. So a host that pins slots and never sends this loses every pin when the controller is next powered on. Unpinning is the same the other way round: a slot unpinned but not saved comes back pinned.

Send it once, after the pins are as they should be, rather than after each one

  • it writes three files.

Available since firmware 5.0.0a.

Reboot

The Reboot command restarts the controller.

0xF0 0x00 0x21 0x45 0x7F 0x78 0xF7

The controller answers with an ACK and then restarts.

Lua debugger

The controller carries a source-level debugger for preset Lua scripts. It is driven entirely over the management port: one command family going in, and a stream of JSON events coming back.

Everything in this section is a 0x14 Update runtime operation on the 0x40 Trace resource. The byte after the resource is the sub-command, and some sub-commands take a second byte as an argument or a text payload:

0xF0 0x00 0x21 0x45 0x14 0x40 sub-command [argument | payload] 0xF7

Each of these is acknowledged with an ACK as soon as it is received. The acknowledgement means the request arrived, not that it has been carried out - the answer arrives separately as one or more debugger events. Set breakpoints is the exception: its payload is checked first, and a payload that is not valid JSON or not a JSON array is answered with a NACK.

Debugger sub-commands

Sub-commandNameArgumentRequires a stopped script
0x00Detach-no
0x01Attach-no
0x02Step in-yes
0x03Step out-yes
0x04Step over-yes
0x05Continue-yes
0x06Get localsstack level, default 0x00yes
0x07Get globals0x01 to include built-insno, but see below
0x08Get stack trace-yes
0x09retired--
0x0AGet parameter map-no
0x0BReload preset-no
0x0CEvaluateLua chunkyes
0x0DExpand tableLua expressionyes
0x0EGet threads-no
0x0FLine streaming0x01 to enableno
0x10Pause-no
0x11Get upvaluesstack level, default 0x00yes
0x5BSet breakpointsJSON arrayno
0x7FReset-no

A request that needs a stopped script and does not have one is answered with an error event rather than being dropped. While a script is stopped, requests wait in a queue for the stopped thread; a request that finds the queue full is answered with an error event whose message is debug queue full.

Getting the globals of a running script is refused for the same reason it would be unsafe to read them: the script is between instructions somewhere unknown.

0x09 was a "value stack" dump of the raw C API stack. It is retired and answers with an error event; use the stack trace, locals or upvalues instead. Its number is not reused, so an old client sending it gets a clear answer.

Attaching and detaching

Attach (0x01) installs the debug hook on the script of the current preset, and answers with an enabled event carrying the number of breakpoints in force and the name and slot of the preset. If the current preset has no Lua script, enabled is followed by a noScript event. The debugger stays on, and the next script to be loaded on screen is hooked.

While the debugger is on, it follows the preset on screen. Entering another preset, or replacing the script of the current one, sends an attached event with reason presetEntered or stateReplaced, or a noScript event when that preset has no script.

0xF0 0x00 0x21 0x45 0x14 0x40 0x01 0xF7

Detach (0x00) removes the hook and answers with a disabled event. Reset (0x7F) detaches, clears the breakpoints and turns line streaming off.

Attaching or detaching is carried out by the thread that owns the script, not by the thread that received the command. That is not an implementation detail worth hiding: installing the hook has to walk the script's live call frames, and doing that while another thread is executing them is not safe.

Breakpoints

Breakpoints are replaced wholesale by sub-command 0x5B with a JSON array as the payload. A payload that is not valid JSON, or not an array, is answered with a NACK and leaves the breakpoints as they were. Two element shapes are accepted:

json
[12, 40, 128]
json
[{"line": 12}, {"line": 40, "source": "helpers.lua"}]

source, when given, is matched against the end of the chunk name, so main.lua matches ctrlv2/slots/b00/p05/main.lua. Without a source a breakpoint fires on that line number in any chunk, which matters for a preset that requires modules.

TIP

0x5B is also the ASCII code for [. A client may therefore send the JSON array on its own, with no sub-command byte in front of it, and its opening bracket serves as the sub-command. This is deliberate and both forms are the same bytes on the wire - but it means a sub-command byte must not be prefixed to the array, or the payload becomes [[12, 40] and the request is rejected.

The controller holds up to 32 breakpoints. The reply is a breakpoints event giving how many were accepted, how many were offered and the capacity, so an editor can show what will actually happen rather than what it asked for.

0xF0 0x00 0x21 0x45 0x14 0x40 0x5B 0x31 0x32 0x5D 0xF7

sets a single breakpoint on line 12 ([12]).

Stopping, and what stopping costs

A script runs on whichever thread called it. Preset timers, parameter-map changes and pot and touch handlers run on the application thread; a custom control's paint callback runs on the display thread; midi.onMessage and midi.onSysex run on the MIDI thread. Whichever thread reaches a breakpoint is the thread that stops, and the stopped event names it.

While a script is stopped:

  • Other threads do not wait for it. Any callback that would have entered the stopped script is given up instead. Nothing blocks, and the controller stays responsive to the management port throughout.
  • Those callbacks are counted, per kind, and reported in the resumed event. A stopped script freezes the display and drops MIDI callbacks by design, and these counts are how that can be told from a fault.
  • Timer ticks are dropped, not queued. Resuming does not deliver a burst of every tick that elapsed while you were reading your variables.
  • Other presets are unaffected. Each preset's script has its own lock.

One thread cannot be stopped: the one that carries these commands, which on current firmware is the MIDI thread. Stopping it would leave nothing able to deliver a continue, so a breakpoint inside midi.onMessage or midi.onSysex is reported with a stopSkipped event and the script runs on. The controller identifies that thread from the commands it receives, so nothing needs configuring.

Evaluating an expression

Sub-command 0x0C takes Lua source as its payload and runs it in the frame the script stopped in, with that frame's locals and upvalues in scope:

0xF0 0x00 0x21 0x45 0x14 0x40 0x0C <ASCII Lua source> 0xF7

The chunk is tried as an expression first and then as a statement, so both tickCount * 2 and tickCount = 0 work. Reads see the frame's variables; assignments do not travel back into locals - a new global is created instead. The frame is whichever level was last asked for with Get locals or Get upvalues, so selecting a frame is a matter of asking for its locals first.

Sub-command 0x0D is the same but expands a single table result into field variables, which is how a table is opened in a variables view.

The Lua console (Execute Lua command, 0x08/0x0C) does not work while a script is stopped, and says so in the log: it is carried out by the application thread, which is usually the thread that is stopped. Use Evaluate instead - it also has the advantage of seeing local variables.

Line streaming

With line streaming on (0x0F with argument 0x01) the controller sends a line event for every executed source line. It is off by default: on a preset with a 20 ms timer this is a continuous stream of SysEx competing with the MIDI the preset exists to send. A cursor following execution does not need it - the stopped event carries the line.

Debugger events

Every answer the debugger produces is a 0x01 File upload of the 0x40Trace resource whose payload is a single complete JSON object:

0xF0 0x00 0x21 0x45 0x01 0x40 <JSON> 0xF7

Every object has an event field naming it. A report that has many items - a stack trace, a locals list - is sent as one message per item, framed by a ...Begin and a ...End event, rather than as one large document. Each message is therefore valid JSON on its own, and no message has to be held open while the next arrives.

Bytes that cannot travel on a 7-bit SysEx wire appear as \\uXXXX escapes in string values.

An event is at most 480 bytes of JSON. An event that would be longer is sent as {"event":"<name>","truncated":true}, with no other fields. A long string value, for example a variable holding a long text, can cause this.

Session events

eventFieldsMeaning
enabledbreakpoints, preset, slotthe hook is installed
noScriptpreset, slotthe preset on screen has no script; the debugger waits for one
attachedreason, preset, slot, breakpointsthe debugger followed a preset that was entered (presetEntered) or whose script was replaced (stateReplaced)
disabled-the hook is removed
reset-detached, breakpoints cleared
detachedreasonthe debugger let go of a script that is being closed
lineStreamenabledline streaming was turned on or off
breakpointsaccepted, offered, capacitythe breakpoint list was replaced
pausePending-a pause was requested, waiting for the next line
errorrequest, messagea request could not be carried out. An Expand table error also carries expression; an attach error carries slot

Execution events

json
{"event":"stopped","reason":"breakpoint","line":16,
 "source":"ctrlv2/slots/b00/p05/main.lua","name":"","thread":"Application Thread",
 "depth":1}

reason is breakpoint, step or pause. thread is the ThreadX thread that stopped. depth is how many frames are on the stack.

json
{"event":"resumed","mode":"continue","note":"",
 "skipped":{"paint":0,"midi":16,"timer":0,"parameterMap":0,"input":0,"other":0}}

mode is continue, stepIn, stepOut, stepOver, reload or abandoned. abandoned means the script was closed while it was stopped, for example when the preset is reloaded or a new script is uploaded; the debugger stays on and hooks the script that replaces it. note is empty or explains the mode, for example outermost frame, continuing for a step out of the outermost frame. skipped counts the callbacks that were given up while the script was stopped, by kind.

json
{"event":"stopSkipped","reason":"breakpoint","line":51,
 "source":"ctrlv2/slots/b00/p05/main.lua","thread":"MIDI Thread",
 "message":"stopping this thread would strand the debugger"}
json
{"event":"line","line":140}

sent for every executed line while line streaming is on.

Variable events

stackBegin / frame / stackEnd:

json
{"event":"frame","level":0,"source":"ctrlv2/slots/b00/p05/main.lua","line":16,
 "name":"","namewhat":"","what":"Lua","lineDefined":13,"upvalues":2}

name is empty for a function called from the firmware, which is every preset hook - lineDefined identifies it instead. namewhat and what are the Lua debug library's descriptions of the name and of the function (Lua, C or main), and upvalues is the number of upvalues of the function.

stackBegin carries no fields; stackEnd carries frames, the number of frames sent.

localsBegin / variable / localsEnd, and the same shape for upvaluesBegin, globalsBegin and tableBegin:

json
{"event":"variable","scope":"local","index":1,"name":"before","type":"number",
 "value":"253","expandable":false}

scope is local, vararg, upvalue, global, field or result. index is the Lua index of a local or upvalue, and a negative number for a vararg. For a global or field it is the position in the report, counted from 0, and for a result the position of the result, counted from 1. expandable is true for tables, which can be opened with Expand table.

The framing events carry these fields:

eventFields
localsBeginlevel, line
localsEndlevel, count
upvaluesBeginlevel
upvaluesEndlevel, count
globalsBegin-
globalsEndcount, builtinsHidden, truncated
tableBeginexpression
tableEndexpression, count, truncated

count is the number of variable events sent. The globals and table reports stop after 200 variables, and truncated is then true.

The globalsEnd event carries builtinsHidden: the standard library, the E1 modules and the several hundred PT_*, POT_* and colour constants are left out unless asked for, so what remains is what the preset itself declared.

json
{"event":"evalResult","expression":"tickCount * 2 + before","ok":true,"results":1,
 "truncated":false}

followed by one variable per result, or with ok false and an error field. truncated is true when the frame has more variables than can be brought into scope for the chunk (200); the rest are not visible to it.

Parameter map events

json
{"event":"parameter","index":0,"deviceId":1,"messageType":"cc7",
 "parameterNumber":10,"midiValue":125}

framed by parameterMapBegin and parameterMapEnd, which carries count. This is what Get parameter map returns while a script is stopped. When nothing is stopped the same request returns the whole map as one document instead, on the 0x41 Parameter map resource - the bulk form the editor already uses, see Get Parameter map.

Thread events

json
{"event":"thread","index":0,"name":"Application Thread","priority":8,
 "state":"ready","runCount":93039,"stackSize":16384,"stackPeak":7968,
 "flags":["self","stopped"]}

framed by threadsBegin and threadsEnd, which carries count. runCount is how many times the thread has been scheduled, stackSize its stack size in bytes and stackPeak the most of it ever used. flags may contain self (the thread that answered), stopped (the thread holding a stopped script) and debugCommands (the thread that carries debugger commands, and therefore cannot be stopped).

stackPeak is a high-water mark, not the current depth. It is worth watching: Lua's C recursion is expensive on this hardware, so a script that nests calls through pcall, a metamethod or a coroutine spends kilobytes of thread stack per level, and the display thread has the least room of the threads that run script. A runCount that is not moving answers "why did my breakpoint not fire" - that thread is not being scheduled.

Controller events

Controller events are sent from the controller to the host computer. Their primary purpose is to keep the host informed about important actions or changes occurring on the controller, such as page switches, preset changes, knob touches, and device connections.

By default, controller events that are triggered by user actions (not initiated by SysEx API commands) are transmitted through the Electra Controller CTRL MIDI port. This default behavior can be changed using the Set Event Port command, allowing developers to route these user-driven event messages to a different USB device MIDI port if needed — keeping event traffic separated from other MIDI streams.

However, events triggered as a response to SysEx API commands are always sent back on the USB device interface, over the port number on which the original SysEx API command was received. This ensures that responses remain properly linked to their initiating requests, even if a custom event port has been configured.

ACK

Acknowledged. Informs the host that the last operation was successfully completed.

0xF0 0x00 0x21 0x45 0x7E 0x01 transaction-id-lsb transaction-id-msb 0xF7

Where:

  • transaction-id-lsb is the least significant 7 bits (LSB) of the transaction Id
  • transaction-id-msb is the most significant 7 bits (MSB) of the transaction Id

The Transaction Id is split into two 7-bit parts: a most significant byte (MSB) and a least significant byte (LSB), using the following logic:

transaction-id-msb = transactionId >> 7
transaction-id-lsb = transactionId & 0x7F

If a Transaction Id is included in the Command, the corresponding ACK or NACK response will also include the same two bytes, allowing you to match the response to the original command.

Example

The ACK with transaction Id 4183 should be transferred as

0xF0 0x00 0x21 0x45 0x7E 0x01 0x77 0x20 0xF7

If no Transaction ID was included in the request, a Transaction ID of 0 will be present in the ACK response.

NACK

Not acknowledged. Informs the host that the last operation did not succeed.

0xF0 0x00 0x21 0x45 0x7E 0x00 transaction-id-lsb transaction-id-msb 0xF7

Where:

  • transaction-id-lsb is the least significant 7 bits (LSB) of the transaction Id
  • transaction-id-msb is the most significant 7 bits (MSB) of the transaction Id

The Transaction Id is split into two 7-bit parts: a most significant byte (MSB) and a least significant byte (LSB), using the following logic:

transaction-id-msb = transactionId >> 7
transaction-id-lsb = transactionId & 0x7F

If a Transaction Id is included in the Command, the corresponding ACK or NACK response will also include the same two bytes, allowing you to match the response to the original command.

Example

The NACK with transaction Id 4183 should be transferred as

0xF0 0x00 0x21 0x45 0x7E 0x00 0x77 0x20 0xF7

If no Transaction ID was included in the request, a Transaction ID of 0 will be present in the NACK response.

Preset switch

The Preset switch event informs the host that the user has changed the preset on the controller. It is also sent after the Switch Preset slot, Reload Preset slot and Load Preloaded preset commands.

0xF0 0x00 0x21 0x45 0x7E 0x02 bank-number slot 0xF7

Snapshot list change

The Snapshot list change Event informs the host that the list of snapshots has been modified. It is sent whenever a snapshot is added, updated, imported, or removed, and also when a snapshot bank is renamed. On receiving it, the host may want to query the snapshot list again.

0xF0 0x00 0x21 0x45 0x7E 0x03 0xF7

Capture list change

The Capture list change Event informs the host that the list of captures has been modified. It is sent whenever a capture is added, updated, imported, or removed, and also when a capture bank is renamed.

0xF0 0x00 0x21 0x45 0x7E 0x0B 0xF7

Pot touch

The Pot touch event informs the host when the user touches or releases a potentiometer (knob) on the controller.

0xF0 0x00 0x21 0x45 0x7E 0x0A pot-id control-id-lsb control-id-msb touched 0xF7

One event is sent when a knob is touched and one when it is released, whether or not a control is assigned to it. The controlId is the id of the control the knob drives on the current page, or 0 when it drives none. Pot touch events are sent only while the host is subscribed to Pots events, see Subscribe Events. No ACK goes with them.

Preset list change

The Preset list change event informs the host that the list of presets has been modified. It is sent whenever a preset is added, updated, or removed.

0xF0 0x00 0x21 0x45 0x7E 0x05 0xF7

Page switch

The Page switch event informs the host that the user has changed the active page on the controller.

0xF0 0x00 0x21 0x45 0x7E 0x06 page-number 0xF7

Page switch events are sent only while the host is subscribed to Page events, see Subscribe Events.

Control Set switch

The Control Set switch event informs the host that the user has changed the active Control Set on the controller.

0xF0 0x00 0x21 0x45 0x7E 0x07 control-set-number 0xF7

Control Set switch events are sent only while the host is subscribed to Control Set events, see Subscribe Events.

Preset bank switch

The Preset bank switch event informs the host that the user has changed the active preset bank on the controller.

0xF0 0x00 0x21 0x45 0x7E 0x08 preset-bank-number 0xF7

USB Host change notification

Informs the host that a new device was connected or an existing device was disconnected from the USB Host port.

0xF0 0x00 0x21 0x45 0x7E 0x09 0xF7

The event carries no detail. Query the device list with Get USB Host devices to see what changed. It is sent only while the host is subscribed to USB Host events, see Subscribe Events. Firmware before 5.0.0 never sent it.

Snapshot bank switch

Informs the host that the user changed current snapshot bank. The host can send the same message to switch the bank itself; the controller replies with ACK/NACK in that direction, and on success it also sends the Snapshot bank switch event back.

0xF0 0x00 0x21 0x45 0x7E 0x04 bank-number 0xF7

Capture bank switch

Informs the host that the user changed current capture bank. The host can send the same message to switch the bank itself; the controller replies with ACK/NACK in that direction, and on success it also sends the Capture bank switch event back.

0xF0 0x00 0x21 0x45 0x7E 0x0C bank-number 0xF7

Config change

Informs the host that the controller has rewritten its configuration file. It is sent whenever the controller saves the configuration itself - a settings screen closing, the SAVE STATE button on the mk2's System settings, the SAVE button on the mini's settings screen, or the SysEx save. A host that holds a copy of the configuration should fetch it again.

0xF0 0x00 0x21 0x45 0x7E 0x0D 0xF7

Midi learn info

When Electra has the MIDI learn enabled it sends a MIDI message with description of MIDI messages received on user ports to. It is always sent on the Electra Controller CTRL port.

0xF0 0x00 0x21 0x45 0x03 midilearn-json-data 0xF7

An example of midilearn-json-data

non-SysEx:

json
{
   "port": 1,
   "msg": "cc7",
   "channel": 2,
   "parameterId": 10,
   "value": 119
}

SysEx:

json
{
   "port": 1,
   "msg": "sysex",
   "data": [ "F0", "43", "20", "00", "F7" ]
}
  • port is the MIDI port the message came in on, counted from 1: 1 is Port 1, 2 is Port 2. It is not 0-based like the other ports in this API.
  • msg is one of cc7, cc14, nrpn, rpn, note, program, atpoly, atchannel, pitchbend, spp or sysex.
  • channel, parameterId and value describe the message. They are not sent for sysex.
  • data holds the bytes of a SysEx message as two-digit hexadecimal strings, from F0 to F7.

Log message

A log message is a text that is transmitted to the host computer in order to provide the user with information what is happening in the controller. The log messages are generated either by the firmware or user's Lua script.

0xF0 0x00 0x21 0x45 0x7F 0x00 log-message 0xF7

The log-message is a text string that start with a number representing milliseconds from the start of the controller, followed by the space, and then the text of the message.

An example of log-message
147362 ElectraApp: preset successfully loaded

Electra One proudly uses Lua and ArduinoJson.
For support contact info@electra.one · © 2019-2026 Electra One