diff options
Diffstat (limited to 'spa/plugins/bluez5/midi.h')
-rw-r--r-- | spa/plugins/bluez5/midi.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/spa/plugins/bluez5/midi.h b/spa/plugins/bluez5/midi.h new file mode 100644 index 0000000..fbf2702 --- /dev/null +++ b/spa/plugins/bluez5/midi.h @@ -0,0 +1,142 @@ +/* Spa V4l2 dbus + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef SPA_BT_MIDI_H_ +#define SPA_BT_MIDI_H_ + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#include <gio/gio.h> + +#include <spa/utils/defs.h> +#include <spa/support/log.h> + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1" +#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1" +#define BLUEZ_GATT_MANAGER_INTERFACE BLUEZ_SERVICE ".GattManager1" +#define BLUEZ_GATT_PROFILE_INTERFACE BLUEZ_SERVICE ".GattProfile1" +#define BLUEZ_GATT_SERVICE_INTERFACE BLUEZ_SERVICE ".GattService1" +#define BLUEZ_GATT_CHR_INTERFACE BLUEZ_SERVICE ".GattCharacteristic1" +#define BLUEZ_GATT_DSC_INTERFACE BLUEZ_SERVICE ".GattDescriptor1" + +#define BT_MIDI_SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700" +#define BT_MIDI_CHR_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3" +#define BT_GATT_CHARACTERISTIC_USER_DESCRIPTION_UUID "00002901-0000-1000-8000-00805f9b34fb" + +#define MIDI_BUF_SIZE 8192 +#define MIDI_MAX_MTU 8192 + +#define MIDI_CLOCK_PERIOD_MSEC 0x2000 +#define MIDI_CLOCK_PERIOD_NSEC (MIDI_CLOCK_PERIOD_MSEC * SPA_NSEC_PER_MSEC) + +struct spa_bt_midi_server +{ + const char *chr_path; +}; + +struct spa_bt_midi_parser { + unsigned int size; + unsigned int sysex:1; + uint8_t buf[MIDI_BUF_SIZE]; +}; + +struct spa_bt_midi_writer { + unsigned int size; + unsigned int mtu; + unsigned int pos; + uint8_t running_status; + uint64_t running_time_msec; + unsigned int flush:1; + uint8_t buf[MIDI_MAX_MTU]; +}; + +struct spa_bt_midi_server_cb +{ + int (*acquire_notify)(void *user_data, int fd, uint16_t mtu); + int (*acquire_write)(void *user_data, int fd, uint16_t mtu); + int (*release)(void *user_data); + const char *(*get_description)(void *user_data); +}; + +static inline void spa_bt_midi_parser_init(struct spa_bt_midi_parser *parser) +{ + parser->size = 0; + parser->sysex = 0; +} + +static inline void spa_bt_midi_parser_dup(struct spa_bt_midi_parser *src, struct spa_bt_midi_parser *dst, bool only_time) +{ + dst->size = src->size; + dst->sysex = src->sysex; + if (!only_time) + memcpy(dst->buf, src->buf, src->size); +} + +/** + * Parse a single BLE MIDI data packet to normalized MIDI events. + */ +int spa_bt_midi_parser_parse(struct spa_bt_midi_parser *parser, + const uint8_t *src, size_t src_size, + bool only_time, + void (*event)(void *user_data, uint16_t time, uint8_t *event, size_t event_size), + void *user_data); + +static inline void spa_bt_midi_writer_init(struct spa_bt_midi_writer *writer, unsigned int mtu) +{ + writer->size = 0; + writer->mtu = SPA_MIN(mtu, (unsigned int)MIDI_MAX_MTU); + writer->pos = 0; + writer->running_status = 0; + writer->running_time_msec = 0; + writer->flush = 0; +} + +/** + * Add a new event to midi writer buffer. + * + * spa_bt_midi_writer_init(&writer, mtu); + * for (time, event, size) in midi events { + * do { + * res = spa_bt_midi_writer_write(&writer, time, event, size); + * if (res < 0) { + * fail with error + * } else if (res) { + * send_packet(writer->buf, writer->size); + * } + * } while (res); + * } + * if (writer.size > 0) + * send_packet(writer->buf, writer->size); + */ +int spa_bt_midi_writer_write(struct spa_bt_midi_writer *writer, + uint64_t time, const uint8_t *event, size_t event_size); + +struct spa_bt_midi_server *spa_bt_midi_server_new(const struct spa_bt_midi_server_cb *cb, + GDBusConnection *conn, struct spa_log *log, void *user_data); +void spa_bt_midi_server_released(struct spa_bt_midi_server *server, bool write); +void spa_bt_midi_server_destroy(struct spa_bt_midi_server *server); + +#endif |