summaryrefslogtreecommitdiffstats
path: root/src/libs/engine/MidiBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/engine/MidiBuffer.cpp')
-rw-r--r--src/libs/engine/MidiBuffer.cpp138
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
+