summaryrefslogtreecommitdiffstats
path: root/src/engine/EventBuffer.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-09-30 16:50:21 +0000
committerDavid Robillard <d@drobilla.net>2008-09-30 16:50:21 +0000
commit93850c202de8b073a1ce1dd8bd246d407bce4e2f (patch)
tree6910b135bf4eff12de1af116cef73f6e9c107cd0 /src/engine/EventBuffer.cpp
parenta8bf5272d096de73507d2eab47f282c345f4ca8a (diff)
downloadingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.tar.gz
ingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.tar.bz2
ingen-93850c202de8b073a1ce1dd8bd246d407bce4e2f.zip
Flatten ingen source directory heirarchy a bit.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@1551 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/EventBuffer.cpp')
-rw-r--r--src/engine/EventBuffer.cpp318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/engine/EventBuffer.cpp b/src/engine/EventBuffer.cpp
new file mode 100644
index 00000000..e8584597
--- /dev/null
+++ b/src/engine/EventBuffer.cpp
@@ -0,0 +1,318 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen 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 General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define __STDC_LIMIT_MACROS 1
+#include <stdint.h>
+#include <iostream>
+#include "EventBuffer.hpp"
+#include "lv2ext/lv2_event.h"
+#include "lv2ext/lv2_event_helpers.h"
+
+using namespace std;
+
+namespace Ingen {
+
+
+/** Allocate a new event buffer.
+ * \a capacity is in bytes (not number of events).
+ */
+EventBuffer::EventBuffer(size_t capacity)
+ : Buffer(DataType(DataType::EVENT), capacity)
+ , _latest_frames(0)
+ , _latest_subframes(0)
+{
+ if (capacity > UINT32_MAX) {
+ cerr << "Event buffer size " << capacity << " too large, aborting." << endl;
+ throw std::bad_alloc();
+ }
+
+ int ret = posix_memalign((void**)&_local_buf, 16, sizeof(LV2_Event_Buffer) + capacity);
+ if (ret) {
+ cerr << "Failed to allocate event buffer. Aborting." << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ _local_buf->event_count = 0;
+ _local_buf->capacity = (uint32_t)capacity;
+ _local_buf->size = 0;
+ _local_buf->data = reinterpret_cast<uint8_t*>(_local_buf + 1);
+ _buf = _local_buf;
+
+ reset(0);
+
+ //cerr << "Creating MIDI Buffer " << _buf << ", capacity = " << _buf->capacity << endl;
+}
+
+
+EventBuffer::~EventBuffer()
+{
+ free(_local_buf);
+}
+
+
+/** Use another buffer's data instead of the local one.
+ *
+ * This buffer will essentially be identical to @a buf after this call.
+ */
+bool
+EventBuffer::join(Buffer* buf)
+{
+ EventBuffer* mbuf = dynamic_cast<EventBuffer*>(buf);
+ if (mbuf) {
+ _buf = mbuf->local_data();
+ _joined_buf = mbuf;
+ _iter = mbuf->_iter;
+ _iter.buf = _buf;
+ return false;
+ } else {
+ return false;
+ }
+
+ //assert(mbuf->size() == _size);
+
+ _joined_buf = mbuf;
+
+ return true;
+}
+
+
+void
+EventBuffer::unjoin()
+{
+ _joined_buf = NULL;
+ _buf = _local_buf;
+ reset(_this_nframes);
+}
+
+
+void
+EventBuffer::prepare_read(FrameTime start, SampleCount nframes)
+{
+ //cerr << "\t" << this << " prepare_read: " << event_count() << endl;
+ rewind();
+ _this_nframes = nframes;
+}
+
+
+void
+EventBuffer::prepare_write(FrameTime start, SampleCount nframes)
+{
+ //cerr << "\t" << this << " prepare_write: " << event_count() << endl;
+ reset(nframes);
+}
+
+/** FIXME: parameters ignored */
+void
+EventBuffer::copy(const Buffer* src_buf, size_t start_sample, size_t end_sample)
+{
+ const EventBuffer* src = dynamic_cast<const EventBuffer*>(src_buf);
+ assert(src);
+ assert(_buf->capacity >= src->_buf->capacity);
+
+ clear();
+ src->rewind();
+
+ memcpy(_buf, src->_buf, src->_buf->size);
+}
+
+
+/** Increment the read position by one event.
+ *
+ * \return true if increment was successful, or false if end of buffer reached.
+ */
+bool
+EventBuffer::increment() const
+{
+ if (lv2_event_is_valid(&_iter)) {
+ lv2_event_increment(&_iter);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/**
+ * \return true iff the cursor is valid (ie get_event is safe)
+ */
+bool
+EventBuffer::is_valid() const
+{
+ return lv2_event_is_valid(&_iter);
+}
+
+
+/** Append an event to the buffer.
+ *
+ * \a timestamp must be >= the latest event in the buffer,
+ * and < this_nframes()
+ *
+ * \return true on success
+ */
+bool
+EventBuffer::append(uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size,
+ const uint8_t* data)
+{
+#ifndef NDEBUG
+ if (lv2_event_is_valid(&_iter)) {
+ LV2_Event* last_event = lv2_event_get(&_iter, NULL);
+ assert(last_event->frames < frames
+ || (last_event->frames == frames && last_event->subframes <= subframes));
+ }
+#endif
+
+ /*cout << "Appending event type " << type << ", size " << size
+ << " @ " << frames << "." << subframes << endl;*/
+
+ const bool ret = lv2_event_write(&_iter, frames, subframes, type, size, data);
+
+ if (!ret)
+ cerr << "ERROR: Failed to write event." << endl;
+
+ _latest_frames = frames;
+ _latest_subframes = subframes;
+
+ return ret;
+}
+
+
+/** Append a buffer of events to the buffer.
+ *
+ * \a timestamp must be >= the latest event in the buffer,
+ * and < this_nframes()
+ *
+ * \return true on success
+ */
+bool
+EventBuffer::append(const LV2_Event_Buffer* buf)
+{
+ uint8_t** data;
+ bool ret = true;
+
+ LV2_Event_Iterator iter;
+ for (lv2_event_begin(&iter, _buf); lv2_event_is_valid(&iter); lv2_event_increment(&iter)) {
+ LV2_Event* ev = lv2_event_get(&iter, data);
+
+#ifndef NDEBUG
+ assert((ev->frames > _latest_frames)
+ || (ev->frames == _latest_frames
+ && ev->subframes >= _latest_subframes));
+#endif
+
+ if (!(ret = append(ev->frames, ev->subframes, ev->type, ev->size, *data))) {
+ cerr << "ERROR: Failed to write event." << endl;
+ break;
+ }
+
+ _latest_frames = ev->frames;
+ _latest_subframes = ev->subframes;
+ }
+
+ return ret;
+}
+
+
+/** Read an event from the current position in the buffer
+ *
+ * \return true if read was successful, or false if end of buffer reached
+ */
+bool
+EventBuffer::get_event(uint32_t* frames,
+ uint32_t* subframes,
+ uint16_t* type,
+ uint16_t* size,
+ uint8_t** data) const
+{
+ if (lv2_event_is_valid(&_iter)) {
+ LV2_Event* ev = lv2_event_get(&_iter, data);
+ *frames = ev->frames;
+ *subframes = ev->subframes;
+ *type = ev->type;
+ *size = ev->size;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/** Clear, and merge \a a and \a b into this buffer.
+ *
+ * FIXME: This is slow.
+ *
+ * \return true if complete merge was successful
+ */
+bool
+EventBuffer::merge(const EventBuffer& a, const EventBuffer& b)
+{
+ // Die if a merge isn't necessary as it's expensive
+ assert(a.size() > 0 && b.size() > 0);
+
+ reset(_this_nframes);
+
+ a.rewind();
+ b.rewind();
+
+#if 0
+ uint32_t a_frames;
+ uint32_t a_subframes;
+ uint16_t a_type;
+ uint16_t a_size;
+ uint8_t* a_data;
+
+ uint32_t b_frames;
+ uint32_t b_subframes;
+ uint16_t b_type;
+ uint16_t b_size;
+ uint8_t* b_data;
+#endif
+
+ cout << "FIXME: merge" << endl;
+#if 0
+ a.get_event(&a_frames, &a_subframes, &a_type, &a_size, &a_data);
+ b.get_event(&b_frames, &b_subframes, &b_type, &b_size, &b_data);
+
+ while (true) {
+ if (a_data && (!b_data || (a_time < b_time))) {
+ append(a_time, a_size, a_data);
+ if (a.increment())
+ a.get_event(&a_time, &a_size, &a_data);
+ else
+ a_data = NULL;
+ } else if (b_data) {
+ append(b_time, b_size, b_data);
+ if (b.increment())
+ b.get_event(&b_time, &b_size, &b_data);
+ else
+ b_data = NULL;
+ } else {
+ break;
+ }
+ }
+
+ _latest_stamp = max(a_time, b_time);
+#endif
+
+ return true;
+}
+
+
+} // namespace Ingen
+