From e671a1e03df0d327691b9d13fb3bd753fb58a85c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 2 Aug 2007 18:33:34 +0000 Subject: 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 --- src/libs/engine/AudioBuffer.hpp | 2 +- src/libs/engine/Buffer.hpp | 4 +- src/libs/engine/InputPort.cpp | 3 + src/libs/engine/JackMidiDriver.cpp | 7 +- src/libs/engine/MidiBuffer.cpp | 138 +++++++++++++++++++++++++++++++------ src/libs/engine/MidiBuffer.hpp | 48 ++++++------- src/libs/engine/OSCBuffer.cpp | 1 - src/libs/engine/OSCBuffer.hpp | 3 +- 8 files changed, 154 insertions(+), 52 deletions(-) (limited to 'src/libs/engine') 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 #include #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(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 +#include #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); -- cgit v1.2.1