summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-04-08 17:00:47 +0000
committerDavid Robillard <d@drobilla.net>2007-04-08 17:00:47 +0000
commitcd0a2541cb9b14bedf200a68ee774b506980775c (patch)
tree97a88e9fe661017e18080f106eef80b90f0ea16e /src
parentb59584b387c4b77d09ba4c791eb711597f67c8c8 (diff)
downloadingen-cd0a2541cb9b14bedf200a68ee774b506980775c.tar.gz
ingen-cd0a2541cb9b14bedf200a68ee774b506980775c.tar.bz2
ingen-cd0a2541cb9b14bedf200a68ee774b506980775c.zip
LV2 MIDI fixes.
git-svn-id: http://svn.drobilla.net/lad/ingen@417 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/common/lv2ext/Makefile.am2
-rw-r--r--src/common/lv2ext/lv2-midifunctions.h66
-rw-r--r--src/common/lv2ext/lv2-miditype.h171
-rw-r--r--src/libs/engine/LV2Node.cpp2
-rw-r--r--src/libs/engine/MidiBuffer.cpp8
-rw-r--r--src/libs/engine/MidiBuffer.h37
6 files changed, 60 insertions, 226 deletions
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 <lars.luthman@gmail.com>
+ Copyright (C) 2006-2007 Lars Luthman <lars.luthman@gmail.com>
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 <string.h>
#include <stdlib.h>
-#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 <lars.luthman@gmail.com>
-
- 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 <stdint.h>
-
-/** 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
- <http://ll-plugins.nongnu.org/lv2/ext/miditype> 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 <lv2ext/lv2-miditype.h>
#include <lv2ext/lv2-midifunctions.h>
#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