This library contains a GATT server and a GATT client for the BLE-MIDI service, MIDI 1.0 packet encoder and decoder. The client and server can work by themselves, or a higher level application can switch between client and server modes. It implements the Specification for MIDI over Bluetooth Low Energy (BLE-MIDI) 1.0. Downloading this standard requires a free login from the midi.org website.
This library expects to be built using pico-sdk version
2.0 or later and it expects to execute on a Raspberry Pi Pico W board
with a RP2040 processor and a WiFi/Bluetooth module
that uses the Infineon CYW43439 WiFi/Bluetooth chip.
Before using this library in a commercial application, please read the
LICENSE file and the comments in each source code header file. I
have tried to structure this library to make as much code as possible
MIT License.
For a simple example that uses the BLE-MIDI server to send and receive MIDI data, see the pico-w-ble-midi-server-demo project. For a more practical demo, see the ble-midi2usbhost project.
You must initialize the Bluetooth hardware by calling cyw43_arch_init()
once before calling the init() function for either library.
This library enables the user application to send and receive MIDI 1.0 data
via standard MIDI 1.0 byte streams. The ble_midi_server_lib library
provides all Bluetooth functions an application needs to send and receive MIDI 1.0 byte streams.
It supports a simple profile that contains only the MIDI service and the
device's GAP_DEVICE_NAME characteristic.
It uses the ble_midi_service_lib library for the MIDI data transfers,
and it handles all other control messages between Bluetooth stack and the application.
If you want to make a more
complicated profile than the one ble_midi_server_lib supports,
you can use ble_midi_service_lib to implement it. For example,
you might want to add a battery service to your profile if your
project is battery powered. However, the code that replaces
ble_midi_server_lib library will be more complicated.
The ble_midi_service_lib INTERFACE
library uses the ble_midi_pkt_codec INTERFACE library
to encode the MIDI byte stream to BLE-MIDI 1.0 packets
time-stamped with the system time. It then sends the
BLE-MIDI encoded data to the connected BLE-MIDI client.
The Accessory Guidelines for Apple Products
specifies a minumum connection interval of 15ms and latency of 30ms (i.e., 2 connection
intervals). The midi_service_stream_handler.c code specifies a minimum interval
of 7.5ms and a maximum interval of 15ms with a maximum latency of 0. My iPad consistently
connects at 15ms with 0 latency. It is probably worth experimenting with this because
ideally the connection interval would be 7.5 ms with 0 latency to minimize timing jitter and latency.
When the BLE-MIDI client sends BLE-MIDI 1.0 data to this server, the
ble_midi_service_lib works with the the ble_midi_pkt_codec to
decode the packet to an array of time-stamped byte stream
structures and buffers them for the application to process.
It is up to the application to handle the timestamps
for presentation order and jitter reduction. Currently,
ble_midi_server_lib does not manage timestamps.
The ble_midi_server_init() function requires a profile_data
argument. The definition of profile_data is normally
automatically generated from a .gatt file that has this
form
PRIMARY_SERVICE, GAP_SERVICE
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "Your device name goes here"
#import <midi_service.gatt>
When your application
builds the code, it should generate the GATT database .h using
the Pico SDK cmake function pico_btstack_make_gatt_header. Be
sure to add the path to this library to your call to pico_btstack_make_gatt_header or else the script won't be able
to find the file referenced in the line #import <midi_service.gatt>.
When the application includes this .h, it will have
the definition of the profile_data variable. The
The file ble_midi_server.h contains the server API.
The file midi_server_stream_handler.h contains the service API.
The user application must call midi_service_stream_init() before
it uses the other two functions. The user application must call
this function with a non-NULL pointer to a btstack_packet_handler_t packet
handler function. This packet handler function must, at a minimum,
handle the BTSTACK_EVENT_STATE event to start advertising when
the Bluetooth stack starts functioning. The callback must also
process the HCI_EVENT_GATTSERVICE_META event and use the
GATTSERVICE_SUBEVENT_SPP_SERVICE_CONNECTED event to capture
the connection handle that is a required argument to
midi_service_stream_read() and to midi_service_stream_write().
The callback should also handle security manager messages if
encryption is required.
After your application calls midi_service_stream_init(), it
must turn on the Bluetooth chip by calling the function
hci_power_control(HCI_POWER_ON).
Once the main application's btstack_packet_handler_t packet
handler function records a valid connection handle, the program's
main loop may process MIDI data received by polling
midi_service_stream_read(). It may also call midi_service_stream_write()
to generate BLE-MIDI messages in response to button presses,
control movement, incoming MIDI 1.0 stream from non-BLE sources, etc.
The files in this directory require the following libraries:
pico_stdlib
ble_midi_service_lib
pico_btstack_cyw43
pico_cyw43_arch_none
ring_buffer_lib
The ring_buffer_lib library is custom code that can be found
here. The CMakeLists.txt
for this project expects the ring_buffer_lib source directory to be
located at the same directory level as the source files for this project.
For example, if this project is a subdirectory of proj/lib, then
the ring_buffer_lib source files should be stored in proj/lib/ring_buffer_lib.
The ring_buffer_lib needs to have a configuration file called ring_buffer_lib_config.h
stored somewhere in the project's include path. Because of the required ring
buffer sizes to support this library, please define the RING_BUFFER_SIZE_TYPE
macro to be a 16-bit data type or larger. For example
#define RING_BUFFER_SIZE_TYPE uint16_t
Note that the default definition is uint8_t, which is too small for
Bluetooth MIDI ring buffers.
This ble_midi_client_lib library implements the basic functions
you need to implement a BLE-MIDI client. A client needs some
sort of UI to manage scanning, connecting, and disconnecting.
The library provides printf type console library output and
is best suited for a command line interpreter-based application.
The client also advertises the GAP_DEVICE_NAME charateristic.