This is a Zephyr implementation of the BLE-MIDI service specification, which allows for wireless transfer of MIDI data over Bluetooth low energy. The implementation covers the entire BLE MIDI packet encoding specification, including running status, timestamp wrapping and single and multi packet system exclusive messages.
To minimize latency, a connection interval of 7.5 ms is requested, which is the smallest interval allowed by the Bluetooth low energy specification. Note that a central may or may not accept this value.
By default, outgoing MIDI messages are sent in separate BLE packets. When building for nRF SoCs, outgoing non-sysex messages can optionally be buffered and transmitted in a single BLE packet the start of the next connection event to reduce latency, see CONFIG_BLE_MIDI_TX_MODE_NRF_RADIO_NOTIF
. This technique uses the MPSL radio notifications API of the nRF Connect SDK as described in this post.
The BLE MIDI service implementation is contained in a Zephyr module. The sample app's CMakeLists.txt file shows one way of adding this module to an app.
The public API is defined in ble_midi.h.
The sample app shows how to send and receive MIDI data. The app requires a board with at least four buttons and three LEDs, for example nrf52840dk_nrf52840.
- Button 1 - Send three simultaneous note on/off messages
- Button 2 - Send a short sysex message
- Button 3 - Send a long, streaming sysex message
- Button 4 - Send enqueued messages (only if
CONFIG_BLE_MIDI_TX_MODE_MANUAL
is set) - LED 1 - On when connected to a BLE MIDI central
- LED 2 - Toggles on/off when receiving sysex messages
- LED 3 - Toggles on/off when receiving non-sysex messages
When CONFIG_BLE_MIDI_TX_MODE_NRF_RADIO_NOTIF
is enabled, it is assumed that the core that runs the BLE MIDI service has a radio peripheral and that the MPSL radio notifications API is available. This is true for a single core SoC like the nRF52840 or when running the entire application on the network core of a multi core SoC like the nRF5340. When running the BLE controller and host on separate cores, you currently have these options:
- Send one MIDI message per BLE packet using
CONFIG_BLE_MIDI_TX_MODE_SINGLE_MSG
. - Roll your own mechanism for relaying radio notifications from the network core to the application core to achieve BLE packet transmission synchronized to the start of connection events. See
CONFIG_BLE_MIDI_TX_MODE_MANUAL
.
CONFIG_BLE_MIDI_SEND_RUNNING_STATUS
- Set toy
to enable running status (omission of repeated channel message status bytes) in transmitted packets. Defaults ton
.CONFIG_BLE_MIDI_SEND_NOTE_OFF_AS_NOTE_ON
- Determines if transmitted note off messages should be represented as note on messages with zero velocity, which increases running status efficiency. Defaults ton
.CONFIG_BLE_MIDI_TX_PACKET_MAX_SIZE
- Determines the maximum size of transmitted BLE MIDI packets (clamped to the MTU - 3).- Use one of the following options to control how transmission of outgoing BLE packets is triggered:
CONFIG_BLE_MIDI_TX_MODE_SINGLE_MSG
- Outgoing MIDI messages are sent in separate BLE packets. May have a negative impact on latency but does not rely on MPSL radio notifications (and likely uses less power). This is the default option.CONFIG_BLE_MIDI_TX_MODE_NRF_RADIO_NOTIF
- Buffer outgoing MIDI messages and send them in a single BLE packet at the start of the next connection interval to reduce latency as described here.CONFIG_BLE_MIDI_TX_MODE_MANUAL
- Buffer outgoing MIDI messages and leave it up to the caller to trigger transmission. Can be useful in combination with a custom radio notification mechanism, like relaying notifications from the net core to the app core via IPC.