From cd0a2541cb9b14bedf200a68ee774b506980775c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Apr 2007 17:00:47 +0000 Subject: LV2 MIDI fixes. git-svn-id: http://svn.drobilla.net/lad/ingen@417 a436a847-0d15-0410-975c-d299462d15a1 --- src/common/lv2ext/Makefile.am | 2 +- src/common/lv2ext/lv2-midifunctions.h | 66 +++++++------ src/common/lv2ext/lv2-miditype.h | 171 ---------------------------------- src/libs/engine/LV2Node.cpp | 2 +- src/libs/engine/MidiBuffer.cpp | 8 +- src/libs/engine/MidiBuffer.h | 37 ++++---- 6 files changed, 60 insertions(+), 226 deletions(-) delete mode 100644 src/common/lv2ext/lv2-miditype.h diff --git a/src/common/lv2ext/Makefile.am b/src/common/lv2ext/Makefile.am index 6d6ebb6e..ed382ecc 100644 --- a/src/common/lv2ext/Makefile.am +++ b/src/common/lv2ext/Makefile.am @@ -1 +1 @@ -noinst_HEADERS = lv2-miditype.h lv2-midifunctions.h +noinst_HEADERS = lv2-midiport.h lv2-midifunctions.h diff --git a/src/common/lv2ext/lv2-midifunctions.h b/src/common/lv2ext/lv2-midifunctions.h index 2334eff3..0d309853 100644 --- a/src/common/lv2ext/lv2-midifunctions.h +++ b/src/common/lv2ext/lv2-midifunctions.h @@ -2,7 +2,7 @@ lv2-midifunctions.h - support file for using MIDI in LV2 plugins - Copyright (C) 2006 Lars Luthman + Copyright (C) 2006-2007 Lars Luthman 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 @@ -20,13 +20,18 @@ ****************************************************************************/ +/** @file + This file contains static helper functions for the LV2 MIDI datatype + extension. +*/ + #ifndef LV2_MIDIFUNCTIONS #define LV2_MIDIFUNCTIONS #include #include -#include "lv2-miditype.h" +#include "lv2-midiport.h" /** This structure contains information about a MIDI port buffer, the @@ -73,6 +78,7 @@ static void lv2midi_reset_buffer(LV2_MIDI* midi) midi->size = 0; } + static void lv2midi_reset_state(LV2_MIDIState* state, LV2_MIDI* midi, uint32_t frame_count) { state->midi = midi; @@ -81,28 +87,6 @@ static void lv2midi_reset_state(LV2_MIDIState* state, LV2_MIDI* midi, uint32_t f } -/** This function advances the read/write position in @c state to the next - event and returns its timestamp, or the @c frame_count member of @c state - is there are no more events. */ -static double lv2midi_increment(LV2_MIDIState* state) { - - if (state->position + sizeof(double) + sizeof(size_t) >= state->midi->size) { - state->position = state->midi->size; - return state->frame_count; - } - - state->position += sizeof(double); - size_t size = *(size_t*)(state->midi->data + state->position); - state->position += sizeof(size_t); - state->position += size; - - if (state->position >= state->midi->size) - return state->frame_count; - - return *(double*)(state->midi->data + state->position); -} - - /** This function reads one event from the port associated with the @c state parameter and writes its timestamp, size and a pointer to its data bytes into the parameters @c timestamp, @c size and @c data, respectively. @@ -125,13 +109,35 @@ static double lv2midi_get_event(LV2_MIDIState* state, } *timestamp = *(double*)(state->midi->data + state->position); - *size = *(size_t*)(state->midi->data + state->position + sizeof(double)); + *size = *(uint32_t*)(state->midi->data + state->position + sizeof(double)); *data = state->midi->data + state->position + - sizeof(double) + sizeof(size_t); + sizeof(double) + sizeof(uint32_t); return *timestamp; } +/** This function advances the read/write position in @c state to the next + event and returns its timestamp, or the @c frame_count member of @c state + is there are no more events. */ +static double lv2midi_step(LV2_MIDIState* state) { + + if (state->position + sizeof(double) + sizeof(uint32_t) >= state->midi->size) { + state->position = state->midi->size; + return state->frame_count; + } + + state->position += sizeof(double); + uint32_t size = *(uint32_t*)(state->midi->data + state->position); + state->position += sizeof(uint32_t); + state->position += size; + + if (state->position >= state->midi->size) + return state->frame_count; + + return *(double*)(state->midi->data + state->position); +} + + /** This function writes one MIDI event to the port buffer associated with @c state. It returns 0 when the event was written successfully to the buffer, and -1 when there was not enough room. The read/write position @@ -142,14 +148,14 @@ static int lv2midi_put_event(LV2_MIDIState* state, const unsigned char* data) { if (state->midi->capacity - state->midi->size < - sizeof(double) + sizeof(size_t) + size) + sizeof(double) + sizeof(uint32_t) + size) return -1; *(double*)(state->midi->data + state->midi->size) = timestamp; state->midi->size += sizeof(double); - *(size_t*)(state->midi->data + state->midi->size) = size; - state->midi->size += sizeof(size_t); - memcpy(state->midi->data + state->midi->size, data, (size_t)size); + *(uint32_t*)(state->midi->data + state->midi->size) = size; + state->midi->size += sizeof(uint32_t); + memcpy(state->midi->data + state->midi->size, data, size); state->midi->size += size; ++state->midi->event_count; diff --git a/src/common/lv2ext/lv2-miditype.h b/src/common/lv2ext/lv2-miditype.h deleted file mode 100644 index 5350e4f7..00000000 --- a/src/common/lv2ext/lv2-miditype.h +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************************** - - lv2-miditype.h - header file for using MIDI in LV2 plugins - - Copyright (C) 2006 Lars Luthman - - 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 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 01222-1307 USA - -****************************************************************************/ - -#ifndef LV2_MIDITYPE_H -#define LV2_MIDITYPE_H - -#include - -/** This data structure is used to contain the MIDI events for one run() - cycle. The port buffer for a LV2 port that has the datatype - should be a pointer - to an instance of this struct. - - To store two Note On events on MIDI channel 0 in a buffer, with timestamps - 12 and 35.5, you could use something like this code (assuming that - midi_data is a variable of type LV2_MIDI): - @code - - size_t buffer_offset = 0; - *(double*)(midi_data->data + buffer_offset) = 12; - buffer_offset += sizeof(double); - *(size_t*)(midi_data->data + buffer_offset) = 3; - buffer_offset += sizeof(size_t); - midi_data->data[buffer_offset++] = 0x90; - midi_data->data[buffer_offset++] = 0x48; - midi_data->data[buffer_offset++] = 0x64; - ++midi_data->event_count; - - *(double*)(midi_data->data + buffer_offset) = 35.5; - buffer_offset += sizeof(double); - *(size_t*)(midi_data->data + buffer_offset) = 3; - buffer_offset += sizeof(size_t); - midi_data->data[buffer_offset++] = 0x90; - midi_data->data[buffer_offset++] = 0x55; - midi_data->data[buffer_offset++] = 0x64; - ++midi_data->event_count; - - midi_data->size = buffer_offset; - - @endcode - - This would be done by the host in the case of an input port, and by the - plugin in the case of an output port. Whoever is writing events to the - buffer must also take care not to exceed the capacity of the data buffer. - - To read events from a buffer, you could do something like this: - @code - - size_t buffer_offset = 0; - uint32_t i; - for (i = 0; i < midi_data->event_count; ++i) { - double timestamp = *(double*)(midi_data->data + buffer_offset); - buffer_offset += sizeof(double); - size_t size = *(size_t*)(midi_data->data + buffer_offset); - buffer_offset += sizeof(size_t); - do_something_with_event(timestamp, size, - midi_data->data + buffer_offset); - buffer_offset += size; - } - - @endcode -*/ -typedef struct { - - /** The number of MIDI events in the data buffer. - INPUT PORTS: It's the host's responsibility to set this field to the - number of MIDI events contained in the data buffer before calling the - plugin's run() function. The plugin may not change this field. - OUTPUT PORTS: It's the plugin's responsibility to set this field to the - number of MIDI events it has stored in the data buffer before returning - from the run() function. Any initial value should be ignored by the - plugin. - */ - uint32_t event_count; - - /** The size of the data buffer in bytes. It is set by the host and may not - be changed by the plugin. The host is allowed to change this between - run() calls. - */ - uint32_t capacity; - - /** The size of the initial part of the data buffer that actually contains - data. - INPUT PORTS: It's the host's responsibility to set this field to the - number of bytes used by all MIDI events it has written to the buffer - (including timestamps and size fields) before calling the plugin's - run() function. The plugin may not change this field. - OUTPUT PORTS: It's the plugin's responsibility to set this field to - the number of bytes used by all MIDI events it has written to the - buffer (including timestamps and size fields) before returning from - the run() function. Any initial value should be ignored by the plugin. - */ - uint32_t size; - - /** The data buffer that is used to store MIDI events. The events are packed - after each other, and the format of each event is as follows: - - First there is a timestamp, which should have the type "double", - i.e. have the same bit size as a double and the same bit layout as a - double (whatever that is on the current platform). This timestamp gives - the offset from the beginning of the current cycle, in frames, that - the MIDI event occurs on. It must be strictly smaller than the 'nframes' - parameter to the current run() call. The MIDI events in the buffer must - be ordered by their timestamp, e.g. an event with a timestamp of 123.23 - must be stored after an event with a timestamp of 65.0. - - The second part of the event is a size field, which should have the type - "size_t" (as defined in the standard C header stddef.h). It should - contain the size of the MIDI data for this event, i.e. the number of - bytes used to store the actual MIDI event. The bytes used by the - timestamp and the size field should not be counted. - - The third part of the event is the actual MIDI data. There are some - requirements that must be followed: - - * Running status is not allowed. Every event must have its own status - byte. - * Note On events with velocity 0 are not allowed. These events are - equivalent to Note Off in standard MIDI streams, but in order to make - plugins and hosts easier to write, as well as more efficient, only - proper Note Off events are allowed as Note Off. - * "Realtime events" (status bytes 0xF8 to 0xFF) are allowed, but may not - occur inside other events like they are allowed to in hardware MIDI - streams. - * All events must be fully contained in a single data buffer, i.e. events - may not "wrap around" by storing the first few bytes in one buffer and - then wait for the next run() call to store the rest of the event. If - there isn't enough space in the current data buffer to store an event, - the event will either have to wait until next run() call, be ignored, - or compensated for in some more clever way. - * All events must be valid MIDI events. This means for example that - only the first byte in each event (the status byte) may have the eighth - bit set, that Note On and Note Off events are always 3 bytes long etc. - The MIDI writer (host or plugin) is responsible for writing valid MIDI - events to the buffer, and the MIDI reader (plugin or host) can assume - that all events are valid. - - On a platform where double is 8 bytes and size_t is 4 bytes, the data - buffer layout for a 3-byte event followed by a 4-byte event may look - something like this: - _______________________________________________________________ - | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ... - |TIMESTAMP 1 |SIZE 1 |DATA |TIMESTAMP 2 |SIZE 2 |DATA | ... - - */ - unsigned char* data; - -} LV2_MIDI; - - - -#endif diff --git a/src/libs/engine/LV2Node.cpp b/src/libs/engine/LV2Node.cpp index f05a477b..4ea29d1f 100644 --- a/src/libs/engine/LV2Node.cpp +++ b/src/libs/engine/LV2Node.cpp @@ -187,7 +187,7 @@ LV2Node::set_port_buffer(size_t voice, size_t port_num, Buffer* buf) if (buf->type() == DataType::FLOAT) slv2_instance_connect_port(_instances[voice], port_num, ((AudioBuffer*)buf)->data()); else if (buf->type() == DataType::MIDI) - slv2_instance_connect_port(_instances[voice], port_num, ((MidiBuffer*)buf)->data()); + slv2_instance_connect_port(_instances[voice], port_num, ((MidiBuffer*)buf)->data()->midi); } diff --git a/src/libs/engine/MidiBuffer.cpp b/src/libs/engine/MidiBuffer.cpp index 35bda0a0..3dcb7b4c 100644 --- a/src/libs/engine/MidiBuffer.cpp +++ b/src/libs/engine/MidiBuffer.cpp @@ -38,8 +38,7 @@ MidiBuffer::join(Buffer* buf) _joined_buf = mbuf; - _buf = mbuf->data(); - _state = mbuf->state(); + _state = mbuf->data(); return true; } @@ -49,8 +48,9 @@ void MidiBuffer::unjoin() { _joined_buf = NULL; - _buf = _local_buf; _state = &_local_state; + _state->midi = _buf; + clear(); reset(_this_nframes); } @@ -71,7 +71,6 @@ void MidiBuffer::prepare_read(SampleCount nframes) { assert(!_joined_buf || data() == _joined_buf->data()); - assert(!_joined_buf || state() == _joined_buf->state()); reset(nframes); } @@ -84,7 +83,6 @@ MidiBuffer::prepare_write(SampleCount nframes) reset(nframes); assert(!_joined_buf || data() == _joined_buf->data()); - assert(!_joined_buf || state() == _joined_buf->state()); } diff --git a/src/libs/engine/MidiBuffer.h b/src/libs/engine/MidiBuffer.h index 5a810bc3..79f7098b 100644 --- a/src/libs/engine/MidiBuffer.h +++ b/src/libs/engine/MidiBuffer.h @@ -18,7 +18,6 @@ #ifndef MIDIBUFFER_H #define MIDIBUFFER_H -#include #include #include "Buffer.h" #include "DataType.h" @@ -30,15 +29,18 @@ class MidiBuffer : public Buffer { public: MidiBuffer(size_t capacity) : Buffer(DataType(DataType::MIDI), capacity) - , _state(&_local_state) - , _local_buf(lv2midi_new((uint32_t)capacity)) - , _buf(_local_buf) + , _buf(lv2midi_new((uint32_t)capacity)) , _joined_buf(NULL) { + _local_state.midi = _buf; + _state = &_local_state; + assert(_local_state.midi); + reset(0); clear(); + assert(_local_state.midi == _buf); } - ~MidiBuffer() { lv2midi_free(_buf); } + ~MidiBuffer() { lv2midi_free(_local_state.midi); } void prepare_read(SampleCount nframes); void prepare_write(SampleCount nframes); @@ -49,32 +51,31 @@ public: uint32_t this_nframes() const { return _this_nframes; } - inline LV2_MIDI* data() const - { return ((_joined_buf != NULL) ? _joined_buf->data() : _buf); } + inline LV2_MIDIState* data() + { return ((_joined_buf != NULL) ? _joined_buf->data() : _state); } - inline LV2_MIDIState* state() const - { return ((_joined_buf != NULL) ? _joined_buf->state() : _state); } + inline const LV2_MIDIState* data() const + { return ((_joined_buf != NULL) ? _joined_buf->data() : _state); } inline void clear() - { lv2midi_reset_buffer(_buf); _state->position = 0; } + { assert(_state); assert(_state->midi); lv2midi_reset_buffer(_state->midi); _state->position = 0; } inline void reset(SampleCount nframes) - { lv2midi_reset_state(_state, _buf, nframes); _this_nframes = nframes; } + { assert(_state); assert(_state->midi); lv2midi_reset_state(_state, _state->midi, nframes); _this_nframes = nframes; } inline double increment() - { return lv2midi_increment(_state); } + { assert(_state); assert(_state->midi); return lv2midi_step(_state); } inline double get_event(double* timestamp, uint32_t* size, unsigned char** data) - { return lv2midi_get_event(_state, timestamp, size, data); } + { assert(_state); assert(_state->midi); return lv2midi_get_event(_state, timestamp, size, data); } inline int put_event(double timestamp, uint32_t size, const unsigned char* data) - { return lv2midi_put_event(_state, timestamp, size, data); } + { assert(_state); assert(_state->midi); return lv2midi_put_event(_state, timestamp, size, data); } private: - LV2_MIDIState _local_state; - LV2_MIDIState* _state; - LV2_MIDI* _local_buf; - LV2_MIDI* _buf; + LV2_MIDIState _local_state; + LV2_MIDIState* _state; + LV2_MIDI* const _buf; MidiBuffer* _joined_buf; ///< Buffer to mirror, if joined -- cgit v1.2.1