summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-08-02 18:33:34 +0000
committerDavid Robillard <d@drobilla.net>2007-08-02 18:33:34 +0000
commite671a1e03df0d327691b9d13fb3bd753fb58a85c (patch)
treed2458bd7a0c2463d391a6f672c9876e877ab2e71 /src
parent191b78d09365112a868ddaf3f813ef2b5bc2c252 (diff)
downloadingen-e671a1e03df0d327691b9d13fb3bd753fb58a85c.tar.gz
ingen-e671a1e03df0d327691b9d13fb3bd753fb58a85c.tar.bz2
ingen-e671a1e03df0d327691b9d13fb3bd753fb58a85c.zip
Fix MIDI patching.
Remove ugly C LV2 MIDI functions and moved functionality into MidiBuffer. git-svn-id: http://svn.drobilla.net/lad/ingen@671 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.h168
-rw-r--r--src/libs/engine/AudioBuffer.hpp2
-rw-r--r--src/libs/engine/Buffer.hpp4
-rw-r--r--src/libs/engine/InputPort.cpp3
-rw-r--r--src/libs/engine/JackMidiDriver.cpp7
-rw-r--r--src/libs/engine/MidiBuffer.cpp138
-rw-r--r--src/libs/engine/MidiBuffer.hpp48
-rw-r--r--src/libs/engine/OSCBuffer.cpp1
-rw-r--r--src/libs/engine/OSCBuffer.hpp3
10 files changed, 155 insertions, 221 deletions
diff --git a/src/common/lv2ext/Makefile.am b/src/common/lv2ext/Makefile.am
index ed382ecc..a4dceb45 100644
--- a/src/common/lv2ext/Makefile.am
+++ b/src/common/lv2ext/Makefile.am
@@ -1 +1 @@
-noinst_HEADERS = lv2-midiport.h lv2-midifunctions.h
+noinst_HEADERS = lv2-midiport.h
diff --git a/src/common/lv2ext/lv2-midifunctions.h b/src/common/lv2ext/lv2-midifunctions.h
deleted file mode 100644
index 0f47ca5d..00000000
--- a/src/common/lv2ext/lv2-midifunctions.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-
- lv2-midifunctions.h - support file for using MIDI in LV2 plugins
-
- 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
- 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
-
-****************************************************************************/
-
-/** @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-midiport.h"
-
-
-/** This structure contains information about a MIDI port buffer, the
- current period size, and the position in the MIDI data buffer that
- we are currently reading from or writing to. It needs to be recreated
- or at least reinitialised every process() call. */
-typedef struct {
-
- /** The MIDI port structure that we want to read or write. */
- LV2_MIDI* midi;
-
- /** The number of frames in this process cycle. */
- uint32_t frame_count;
-
- /** The current position in the data buffer. Should be initialised to 0. */
- uint32_t position;
-
-} LV2_MIDIState;
-
-
-inline static LV2_MIDI* lv2midi_new(uint32_t capacity)
-{
- LV2_MIDI* midi = (LV2_MIDI*)malloc(sizeof(LV2_MIDI));
-
- midi->event_count = 0;
- midi->capacity = capacity;
- midi->size = 0;
- midi->data = (unsigned char*)malloc(sizeof(unsigned char) * capacity);
-
- return midi;
-}
-
-
-static void lv2midi_free(LV2_MIDI* midi)
-{
- free(midi->data);
- free(midi);
-}
-
-
-static void lv2midi_reset_buffer(LV2_MIDI* midi)
-{
- midi->event_count = 0;
- midi->size = 0;
-}
-
-
-static void lv2midi_reset_state(LV2_MIDIState* state, LV2_MIDI* midi, uint32_t frame_count)
-{
- state->midi = midi;
- state->frame_count = frame_count;
- state->position = 0;
-}
-
-
-/** 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.
- It does not advance the read position in the MIDI data buffer, two
- subsequent calls to lv2midi_get_event() will read the same event.
-
- The function returns the timestamp for the read event, or the @c frame_count
- member of @c state if there are no more events in the buffer. */
-static double lv2midi_get_event(LV2_MIDIState* state,
- double* timestamp,
- uint32_t* size,
- unsigned char** data) {
-
- if (state->position >= state->midi->size) {
- state->position = state->midi->size;
- *timestamp = state->frame_count;
- *size = 0;
- *data = NULL;
- return *timestamp;
- }
-
- *timestamp = *(double*)(state->midi->data + state->position);
- *size = *(uint32_t*)(state->midi->data + state->position + sizeof(double));
- *data = state->midi->data + state->position +
- 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
- is advanced automatically. */
-static int lv2midi_put_event(LV2_MIDIState* state,
- double timestamp,
- uint32_t size,
- const unsigned char* data) {
-
- if (state->midi->capacity - state->midi->size <
- sizeof(double) + sizeof(uint32_t) + size)
- return -1;
-
- *(double*)(state->midi->data + state->midi->size) = timestamp;
- state->midi->size += sizeof(double);
- *(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;
-
- return 0;
-}
-
-
-#endif
-
diff --git a/src/libs/engine/AudioBuffer.hpp b/src/libs/engine/AudioBuffer.hpp
index d0644d27..d0379895 100644
--- a/src/libs/engine/AudioBuffer.hpp
+++ b/src/libs/engine/AudioBuffer.hpp
@@ -55,7 +55,7 @@ public:
void prepare_read(SampleCount nframes);
void prepare_write(SampleCount nframes) {}
- void reset(SampleCount nframes) const {}
+ void rewind() const {}
void resize(size_t size);
void filled_size(size_t size) { _filled_size = size; }
diff --git a/src/libs/engine/Buffer.hpp b/src/libs/engine/Buffer.hpp
index b3f7fe3c..bdca2c07 100644
--- a/src/libs/engine/Buffer.hpp
+++ b/src/libs/engine/Buffer.hpp
@@ -40,8 +40,8 @@ public:
/** Clear contents and reset state */
virtual void clear() = 0;
- /** Reset state (ie reset read ptr), but leave contents */
- virtual void reset(SampleCount nframes) const = 0;
+ /** Rewing (ie reset read pointer), but leave contents unchanged */
+ virtual void rewind() const = 0;
virtual void prepare_read(SampleCount nframes) = 0;
virtual void prepare_write(SampleCount nframes) = 0;
diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp
index 1580dc81..6466dee3 100644
--- a/src/libs/engine/InputPort.cpp
+++ b/src/libs/engine/InputPort.cpp
@@ -182,6 +182,9 @@ InputPort::pre_process(SampleCount nframes, FrameTime start, FrameTime end)
for (uint32_t i=0; i < _poly; ++i)
_buffers.at(i)->prepare_read(nframes);
+
+ if (_type == DataType::MIDI)
+ cerr << path() << " nevents: " << ((MidiBuffer*)_buffers.at(0))->event_count() << endl;
if (!do_mixdown) {
assert(_buffers.at(0)->is_joined_to((*_connections.begin())->buffer(0)));
diff --git a/src/libs/engine/JackMidiDriver.cpp b/src/libs/engine/JackMidiDriver.cpp
index 4d608beb..9abe83f6 100644
--- a/src/libs/engine/JackMidiDriver.cpp
+++ b/src/libs/engine/JackMidiDriver.cpp
@@ -85,10 +85,13 @@ JackMidiPort::prepare_block(const SampleCount block_start, const SampleCount blo
jack_midi_event_t ev;
jack_midi_event_get(&ev, jack_buffer, i);
- patch_buf->put_event(ev.time, ev.size, ev.buffer);
+ bool success = patch_buf->append(ev.time, ev.size, ev.buffer);
+ if (!success)
+ cerr << "WARNING: Failed to write MIDI to port buffer, event(s) lost!" << endl;
}
- //cerr << "Jack MIDI got " << event_count << " events." << endl;
+ //if (event_count)
+ // cerr << "Jack MIDI got " << event_count << " events." << endl;
}
diff --git a/src/libs/engine/MidiBuffer.cpp b/src/libs/engine/MidiBuffer.cpp
index 4d515f2e..4ec63524 100644
--- a/src/libs/engine/MidiBuffer.cpp
+++ b/src/libs/engine/MidiBuffer.cpp
@@ -15,6 +15,8 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define __STDC_LIMIT_MACROS 1
+#include <stdint.h>
#include <iostream>
#include "MidiBuffer.hpp"
@@ -22,21 +24,43 @@ using namespace std;
namespace Ingen {
+
+/** Allocate a new MIDI buffer.
+ * \a capacity is in bytes (not number of events).
+ */
MidiBuffer::MidiBuffer(size_t capacity)
: Buffer(DataType(DataType::MIDI), capacity)
- , _buf(lv2midi_new((uint32_t)capacity))
, _joined_buf(NULL)
{
- _local_state.midi = _buf;
- _state = &_local_state;
- assert(_local_state.midi);
+ if (capacity > UINT32_MAX) {
+ cerr << "MIDI buffer size " << capacity << " too large, aborting." << endl;
+ throw std::bad_alloc();
+ }
+
+ int ret = posix_memalign((void**)&_local_buf, 16, sizeof(LV2_MIDI));
+ if (ret) {
+ cerr << "Failed to allocate MIDI buffer. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ ret = posix_memalign((void**)&_local_buf->data, 16, capacity);
+ if (ret) {
+ cerr << "Failed to allocate MIDI buffer contents. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ _local_buf->capacity = (uint32_t)capacity;
+ _buf = _local_buf;
reset(0);
- clear();
- assert(_local_state.midi == _buf);
//cerr << "Creating MIDI Buffer " << _buf << ", capacity = " << _buf->capacity << endl;
}
+MidiBuffer::~MidiBuffer()
+{
+ free(_local_buf->data);
+ free(_local_buf);
+}
/** Use another buffer's data instead of the local one.
@@ -47,14 +71,18 @@ bool
MidiBuffer::join(Buffer* buf)
{
MidiBuffer* mbuf = dynamic_cast<MidiBuffer*>(buf);
- if (!mbuf)
+ if (mbuf) {
+ _position = mbuf->_position;
+ _buf = mbuf->local_data();
+ _joined_buf = mbuf;
+ return false;
+ } else {
return false;
+ }
//assert(mbuf->size() == _size);
_joined_buf = mbuf;
-
- _state = mbuf->_state;
return true;
}
@@ -64,10 +92,7 @@ void
MidiBuffer::unjoin()
{
_joined_buf = NULL;
- _state = &_local_state;
- _state->midi = _buf;
-
- clear();
+ _buf = _local_buf;
reset(_this_nframes);
}
@@ -86,19 +111,15 @@ MidiBuffer::is_joined_to(Buffer* buf) const
void
MidiBuffer::prepare_read(SampleCount nframes)
{
- assert(!_joined_buf || data() == _joined_buf->data());
-
- reset(nframes);
+ rewind();
+ _this_nframes = nframes;
}
void
MidiBuffer::prepare_write(SampleCount nframes)
{
- clear();
reset(nframes);
-
- assert(!_joined_buf || data() == _joined_buf->data());
}
/** FIXME: parameters ignored */
@@ -107,16 +128,91 @@ MidiBuffer::copy(const Buffer* src_buf, size_t start_sample, size_t end_sample)
{
MidiBuffer* src = (MidiBuffer*)src_buf;
clear();
- src->reset(_this_nframes);
+ src->rewind();
const uint32_t frame_count = min(_this_nframes, src->this_nframes());
double time;
uint32_t size;
unsigned char* data;
while (src->increment() < frame_count) {
src->get_event(&time, &size, &data);
- put_event(time, size, data);
+ append(time, size, data);
+ }
+}
+
+/** Increment the read position by one event.
+ *
+ * Returns the timestamp of the now current event, or this_nframes if
+ * there are no events left.
+ */
+double
+MidiBuffer::increment() const
+{
+ if (_position + sizeof(double) + sizeof(uint32_t) >= _buf->size) {
+ _position = _buf->size;
+ return _this_nframes; // hit end
}
+
+ _position += sizeof(double) + sizeof(uint32_t) + *(uint32_t*)(_buf->data + _position);
+
+ if (_position >= _buf->size)
+ return _this_nframes;
+ else
+ return *(double*)(_buf->data + _position);
+}
+
+
+/** Append a MIDI event to the buffer.
+ *
+ * \a timestamp must be > the latest event in the buffer,
+ * and < this_nframes()
+ *
+ * \return true on success
+ */
+bool
+MidiBuffer::append(double timestamp,
+ uint32_t size,
+ const unsigned char* data)
+{
+ if (_buf->capacity - _buf->size < sizeof(double) + sizeof(uint32_t) + size)
+ return false;
+
+ *(double*)(_buf->data + _buf->size) = timestamp;
+ _buf->size += sizeof(double);
+ *(uint32_t*)(_buf->data + _buf->size) = size;
+ _buf->size += sizeof(uint32_t);
+ memcpy(_buf->data + _buf->size, data, size);
+ _buf->size += size;
+
+ ++_buf->event_count;
+
+ return true;
+}
+
+
+/** Read an event from the current position in the buffer
+ *
+ * \return the timestamp for the read event, or this_nframes()
+ * if there are no more events in the buffer.
+ */
+double
+MidiBuffer::get_event(double* timestamp,
+ uint32_t* size,
+ unsigned char** data) const
+{
+ if (_position >= _buf->size) {
+ _position = _buf->size;
+ *timestamp = _this_nframes;
+ *size = 0;
+ *data = NULL;
+ return *timestamp;
+ }
+
+ *timestamp = *(double*)(_buf->data + _position);
+ *size = *(uint32_t*)(_buf->data + _position + sizeof(double));
+ *data = _buf->data + _position + sizeof(double) + sizeof(uint32_t);
+ return *timestamp;
}
} // namespace Ingen
+
diff --git a/src/libs/engine/MidiBuffer.hpp b/src/libs/engine/MidiBuffer.hpp
index dbccd4e8..87504833 100644
--- a/src/libs/engine/MidiBuffer.hpp
+++ b/src/libs/engine/MidiBuffer.hpp
@@ -18,7 +18,7 @@
#ifndef MIDIBUFFER_H
#define MIDIBUFFER_H
-#include <lv2ext/lv2-midifunctions.h>
+#include <lv2ext/lv2-midiport.h>
#include "Buffer.hpp"
#include "DataType.hpp"
@@ -29,7 +29,7 @@ class MidiBuffer : public Buffer {
public:
MidiBuffer(size_t capacity);
- ~MidiBuffer() { lv2midi_free(_local_state.midi); }
+ ~MidiBuffer();
void prepare_read(SampleCount nframes);
void prepare_write(SampleCount nframes);
@@ -39,38 +39,38 @@ public:
void unjoin();
uint32_t this_nframes() const { return _this_nframes; }
+ uint32_t event_count() const { return _buf->event_count; }
- void copy(const Buffer* src, size_t start_sample, size_t end_sample);
-
+ inline LV2_MIDI* local_data() { return _local_buf; }
+
inline LV2_MIDI* data()
- { return ((_joined_buf != NULL) ? _joined_buf->data() : _state->midi); }
+ { return ((_joined_buf != NULL) ? _joined_buf->data() : _buf); }
inline const LV2_MIDI* data() const
- { return ((_joined_buf != NULL) ? _joined_buf->data() : _state->midi); }
-
- inline void clear()
- { assert(_state); assert(_state->midi); lv2midi_reset_buffer(_state->midi); _state->position = 0; }
+ { return ((_joined_buf != NULL) ? _joined_buf->data() : _buf); }
+
+ void copy(const Buffer* src, size_t start_sample, size_t end_sample);
- inline void reset(SampleCount nframes) const
- { assert(_state); assert(_state->midi); lv2midi_reset_state(_state, _state->midi, nframes); _this_nframes = nframes; }
+ inline void rewind() const { _position = 0; }
+ inline void clear() { if (_joined_buf) reset(_this_nframes); }
+ inline void reset(SampleCount nframes) {
+ _position = 0;
+ _buf->event_count = 0;
+ _buf->size = 0;
+ }
- inline double increment() const
- { assert(_state); assert(_state->midi); return lv2midi_step(_state); }
+ double increment() const;
- inline double get_event(double* timestamp, uint32_t* size, unsigned char** data) const
- { assert(_state); assert(_state->midi); return lv2midi_get_event(_state, timestamp, size, data); }
+ double get_event(double* timestamp, uint32_t* size, unsigned char** data) const;
- inline int put_event(double timestamp, uint32_t size, const unsigned char* data)
- { assert(_state); assert(_state->midi); return lv2midi_put_event(_state, timestamp, size, data); }
+ bool append(double timestamp, uint32_t size, const unsigned char* data);
private:
- LV2_MIDIState _local_state;
- LV2_MIDIState* _state;
- LV2_MIDI* const _buf;
-
- MidiBuffer* _joined_buf; ///< Buffer to mirror, if joined
-
- mutable uint32_t _this_nframes;
+ uint32_t _this_nframes; ///< Current cycle nframes
+ mutable uint32_t _position; ///< Index into _buf
+ MidiBuffer* _joined_buf; ///< Buffer to mirror, if joined
+ LV2_MIDI* _buf; ///< Contents (maybe belong to _joined_buf)
+ LV2_MIDI* _local_buf; ///< Local contents
};
diff --git a/src/libs/engine/OSCBuffer.cpp b/src/libs/engine/OSCBuffer.cpp
index a5f8f3ff..44cf3235 100644
--- a/src/libs/engine/OSCBuffer.cpp
+++ b/src/libs/engine/OSCBuffer.cpp
@@ -69,7 +69,6 @@ OSCBuffer::unjoin()
//_state = &_local_state;
//_state->midi = _buf;
- clear();
reset(_this_nframes);
}
diff --git a/src/libs/engine/OSCBuffer.hpp b/src/libs/engine/OSCBuffer.hpp
index dc529d30..7e1bc451 100644
--- a/src/libs/engine/OSCBuffer.hpp
+++ b/src/libs/engine/OSCBuffer.hpp
@@ -32,7 +32,8 @@ public:
~OSCBuffer() { }
void clear() { lv2_osc_buffer_clear(_buf); }
- void reset(SampleCount nframs) const {}
+ void reset(SampleCount nframes) { clear(); _this_nframes = nframes; }
+ void rewind() const {}
void prepare_read(SampleCount nframes);
void prepare_write(SampleCount nframes);