diff options
Diffstat (limited to 'src/libs/engine/MidiBuffer.cpp')
-rw-r--r-- | src/libs/engine/MidiBuffer.cpp | 138 |
1 files changed, 117 insertions, 21 deletions
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 + |