From 03409192de79cad1ea15a4274b32ff02e67dbf0e Mon Sep 17 00:00:00 2001 From: piegames Date: Sat, 12 Oct 2019 15:44:06 +0200 Subject: [PATCH] Copy Midi API to Message API --- common/JackMessageAPI.cpp | 160 +++++++++++++++++++++++++++++++ common/jack/messageport.h | 197 ++++++++++++++++++++++++++++++++++++++ common/wscript | 1 + 3 files changed, 358 insertions(+) create mode 100644 common/JackMessageAPI.cpp create mode 100644 common/jack/messageport.h diff --git a/common/JackMessageAPI.cpp b/common/JackMessageAPI.cpp new file mode 100644 index 00000000..61d77e12 --- /dev/null +++ b/common/JackMessageAPI.cpp @@ -0,0 +1,160 @@ +/* +Copyright (C) 2007 Dmitry Baikov +Original JACK MIDI implementation Copyright (C) 2004 Ian Esten + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackError.h" +#include "JackMidiPort.h" +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + LIB_EXPORT uint32_t jack_midi_get_event_count(void* port_buffer); + + LIB_EXPORT int jack_midi_event_get(jack_midi_event_t* event, + void* port_buffer, uint32_t event_index); + + LIB_EXPORT void jack_midi_clear_buffer(void* port_buffer); + + LIB_EXPORT void jack_midi_reset_buffer(void* port_buffer); + + LIB_EXPORT size_t jack_midi_max_event_size(void* port_buffer); + + LIB_EXPORT jack_midi_data_t* jack_midi_event_reserve(void* port_buffer, + jack_nframes_t time, size_t data_size); + + LIB_EXPORT int jack_midi_event_write(void* port_buffer, + jack_nframes_t time, const jack_midi_data_t* data, size_t data_size); + + LIB_EXPORT jack_nframes_t jack_midi_get_lost_event_count(void* port_buffer); + +#ifdef __cplusplus +} +#endif + +using namespace Jack; + +LIB_EXPORT +uint32_t jack_midi_get_event_count(void* port_buffer) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (!buf || !buf->IsValid()) { + return 0; + } + return buf->event_count; +} + +LIB_EXPORT +int jack_midi_event_get(jack_midi_event_t *event, void* port_buffer, uint32_t event_index) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (!buf || !buf->IsValid()) { + return -EINVAL; + } + if (event_index >= buf->event_count) { + return -ENOBUFS; + } + JackMidiEvent* ev = &buf->events[event_index]; + event->time = ev->time; + event->size = ev->size; + event->buffer = ev->GetData(buf); + return 0; +} + +LIB_EXPORT +void jack_midi_clear_buffer(void* port_buffer) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (buf && buf->IsValid()) { + buf->Reset(buf->nframes); + } +} + +LIB_EXPORT +void jack_midi_reset_buffer(void* port_buffer) +{ + MidiBufferInit(port_buffer, BUFFER_SIZE_MAX, BUFFER_SIZE_MAX); +} + +LIB_EXPORT +size_t jack_midi_max_event_size(void* port_buffer) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (buf && buf->IsValid()) { + return buf->MaxEventSize(); + } + return 0; +} + +LIB_EXPORT +jack_midi_data_t* jack_midi_event_reserve(void* port_buffer, jack_nframes_t time, size_t data_size) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (! buf) { + jack_error("jack_midi_event_reserve: port buffer is set to NULL"); + return 0; + } + if (! buf->IsValid()) { + jack_error("jack_midi_event_reserve: port buffer is invalid"); + return 0; + } + if (time >= buf->nframes) { + jack_error("jack_midi_event_reserve: time parameter is out of range " + "(%lu >= %lu)", time, buf->nframes); + return 0; + } + if (buf->event_count && (buf->events[buf->event_count - 1].time > time)) { + jack_error("jack_midi_event_reserve: time parameter is earlier than " + "last reserved event"); + return 0; + } + return buf->ReserveEvent(time, data_size); +} + +LIB_EXPORT +int jack_midi_event_write(void* port_buffer, + jack_nframes_t time, const jack_midi_data_t* data, size_t data_size) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (!buf || !buf->IsValid()) { + return -EINVAL; + } + if (time >= buf->nframes || (buf->event_count && buf->events[buf->event_count - 1].time > time)) { + return -EINVAL; + } + jack_midi_data_t* dest = buf->ReserveEvent(time, data_size); + if (!dest) { + return -ENOBUFS; + } + memcpy(dest, data, data_size); + return 0; +} + +LIB_EXPORT +uint32_t jack_midi_get_lost_event_count(void* port_buffer) +{ + JackMidiBuffer *buf = (JackMidiBuffer*)port_buffer; + if (buf && buf->IsValid()) { + return buf->lost_events; + } + return 0; +} diff --git a/common/jack/messageport.h b/common/jack/messageport.h new file mode 100644 index 00000000..3fbf2126 --- /dev/null +++ b/common/jack/messageport.h @@ -0,0 +1,197 @@ +/* + Copyright (C) 2004 Ian Esten + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + +#ifndef __JACK_MIDIPORT_H +#define __JACK_MIDIPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + + +/** Type for raw event data contained in @ref jack_midi_event_t. */ +typedef unsigned char jack_midi_data_t; + + +/** A Jack MIDI event. */ +typedef struct _jack_midi_event +{ + jack_nframes_t time; /**< Sample index at which event is valid */ + size_t size; /**< Number of bytes of data in \a buffer */ + jack_midi_data_t *buffer; /**< Raw MIDI data */ +} jack_midi_event_t; + + +/** + * @defgroup MIDIAPI Reading and writing MIDI data + * @{ + */ + +/** Get number of events in a port buffer. + * + * @param port_buffer Port buffer from which to retrieve event. + * @return number of events inside @a port_buffer + */ +uint32_t +jack_midi_get_event_count(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; + + +/** Get a MIDI event from an event port buffer. + * + * Jack MIDI is normalised, the MIDI event returned by this function is + * guaranteed to be a complete MIDI event (the status byte will always be + * present, and no realtime events will interspered with the event). + * + * This rule does not apply to System Exclusive MIDI messages + * since they can be of arbitrary length. + * To maintain smooth realtime operation such events CAN be deliverd + * as multiple, non-normalised events. + * The maximum size of one event "chunk" depends on the MIDI backend in use. + * For example the midiseq driver will create chunks of 256 bytes. + * The first SysEx "chunked" event starts with 0xF0 and the last + * delivered chunk ends with 0xF7. + * To receive the full SysEx message, a caller of jack_midi_event_get() + * must concatenate chunks until a chunk ends with 0xF7. + * + * @param event Event structure to store retrieved event in. + * @param port_buffer Port buffer from which to retrieve event. + * @param event_index Index of event to retrieve. + * @return 0 on success, ENODATA if buffer is empty. + */ +int +jack_midi_event_get(jack_midi_event_t *event, + void *port_buffer, + uint32_t event_index) JACK_OPTIONAL_WEAK_EXPORT; + + +/** Clear an event buffer. + * + * This should be called at the beginning of each process cycle before calling + * @ref jack_midi_event_reserve or @ref jack_midi_event_write. This + * function may not be called on an input port's buffer. + * + * @param port_buffer Port buffer to clear (must be an output port buffer). + */ +void +jack_midi_clear_buffer(void *port_buffer) JACK_OPTIONAL_WEAK_EXPORT; + +/** Reset an event buffer (from data allocated outside of JACK). + * + * This should be called at the beginning of each process cycle before calling + * @ref jack_midi_event_reserve or @ref jack_midi_event_write. This + * function may not be called on an input port's buffer. + * + * @deprecated Please use jack_midi_clear_buffer(). + * + * @param port_buffer Port buffer to reset. + */ +void +jack_midi_reset_buffer(void *port_buffer) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; + + +/** Get the size of the largest event that can be stored by the port. + * + * This function returns the current space available, taking into account + * events already stored in the port. + * + * @param port_buffer Port buffer to check size of. + */ +size_t +jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT; + + +/** Allocate space for an event to be written to an event port buffer. + * + * Clients are to write the actual event data to be written starting at the + * pointer returned by this function. Clients must not write more than + * @a data_size bytes into this buffer. Clients must write normalised + * MIDI data to the port - no running status and no (1-byte) realtime + * messages interspersed with other messages (realtime messages are fine + * when they occur on their own, like other messages). + * + * Events must be written in order, sorted by their sample offsets. + * JACK will not sort the events for you, and will refuse to store + * out-of-order events. + * + * @param port_buffer Buffer to write event to. + * @param time Sample offset of event. + * @param data_size Length of event's raw data in bytes. + * @return Pointer to the beginning of the reserved event's data buffer, or + * NULL on error (ie not enough space). + */ +jack_midi_data_t* +jack_midi_event_reserve(void *port_buffer, + jack_nframes_t time, + size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; + + +/** Write an event into an event port buffer. + * + * This function is simply a wrapper for @ref jack_midi_event_reserve + * which writes the event data into the space reserved in the buffer. + * + * Clients must not write more than + * @a data_size bytes into this buffer. Clients must write normalised + * MIDI data to the port - no running status and no (1-byte) realtime + * messages interspersed with other messages (realtime messages are fine + * when they occur on their own, like other messages). + * + * Events must be written in order, sorted by their sample offsets. + * JACK will not sort the events for you, and will refuse to store + * out-of-order events. + * + * @param port_buffer Buffer to write event to. + * @param time Sample offset of event. + * @param data Message data to be written. + * @param data_size Length of @a data in bytes. + * @return 0 on success, ENOBUFS if there's not enough space in buffer for event. + */ +int +jack_midi_event_write(void *port_buffer, + jack_nframes_t time, + const jack_midi_data_t *data, + size_t data_size) JACK_OPTIONAL_WEAK_EXPORT; + + +/** Get the number of events that could not be written to @a port_buffer. + * + * This function returning a non-zero value implies @a port_buffer is full. + * Currently the only way this can happen is if events are lost on port mixdown. + * + * @param port_buffer Port to receive count for. + * @returns Number of events that could not be written to @a port_buffer. + */ +uint32_t +jack_midi_get_lost_event_count(void *port_buffer) JACK_OPTIONAL_WEAK_EXPORT; + +/*@}*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* __JACK_MIDIPORT_H */ + + diff --git a/common/wscript b/common/wscript index afc251a2..aa13edaa 100644 --- a/common/wscript +++ b/common/wscript @@ -58,6 +58,7 @@ def build(bld): 'JackAudioPort.cpp', 'JackMidiPort.cpp', 'JackMidiAPI.cpp', + 'JackMessageAPI.cpp', 'JackEngineControl.cpp', 'JackShmMem.cpp', 'JackGenericClientChannel.cpp',