aboutsummaryrefslogtreecommitdiffstats
path: root/src/lv2_evbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lv2_evbuf.c')
-rw-r--r--src/lv2_evbuf.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/lv2_evbuf.c b/src/lv2_evbuf.c
new file mode 100644
index 0000000..d7012c7
--- /dev/null
+++ b/src/lv2_evbuf.c
@@ -0,0 +1,180 @@
+/*
+ Copyright 2008-2018 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+
+#include "lv2_evbuf.h"
+
+struct LV2_Evbuf_Impl {
+ uint32_t capacity;
+ uint32_t atom_Chunk;
+ uint32_t atom_Sequence;
+ LV2_Atom_Sequence buf;
+};
+
+static inline uint32_t
+lv2_evbuf_pad_size(uint32_t size)
+{
+ return (size + 7) & (~7);
+}
+
+LV2_Evbuf*
+lv2_evbuf_new(uint32_t capacity, uint32_t atom_Chunk, uint32_t atom_Sequence)
+{
+ // FIXME: memory must be 64-bit aligned
+ LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
+ sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
+ evbuf->capacity = capacity;
+ evbuf->atom_Chunk = atom_Chunk;
+ evbuf->atom_Sequence = atom_Sequence;
+ lv2_evbuf_reset(evbuf, true);
+ return evbuf;
+}
+
+void
+lv2_evbuf_free(LV2_Evbuf* evbuf)
+{
+ free(evbuf);
+}
+
+void
+lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input)
+{
+ if (input) {
+ evbuf->buf.atom.size = sizeof(LV2_Atom_Sequence_Body);
+ evbuf->buf.atom.type = evbuf->atom_Sequence;
+ } else {
+ evbuf->buf.atom.size = evbuf->capacity;
+ evbuf->buf.atom.type = evbuf->atom_Chunk;
+ }
+}
+
+uint32_t
+lv2_evbuf_get_size(LV2_Evbuf* evbuf)
+{
+ assert(evbuf->buf.atom.type != evbuf->atom_Sequence
+ || evbuf->buf.atom.size >= sizeof(LV2_Atom_Sequence_Body));
+ return evbuf->buf.atom.type == evbuf->atom_Sequence
+ ? evbuf->buf.atom.size - sizeof(LV2_Atom_Sequence_Body)
+ : 0;
+}
+
+void*
+lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
+{
+ return &evbuf->buf;
+}
+
+LV2_Evbuf_Iterator
+lv2_evbuf_begin(LV2_Evbuf* evbuf)
+{
+ LV2_Evbuf_Iterator iter = { evbuf, 0 };
+ return iter;
+}
+
+LV2_Evbuf_Iterator
+lv2_evbuf_end(LV2_Evbuf* evbuf)
+{
+ const uint32_t size = lv2_evbuf_get_size(evbuf);
+ const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
+ return iter;
+}
+
+bool
+lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter)
+{
+ return iter.offset < lv2_evbuf_get_size(iter.evbuf);
+}
+
+LV2_Evbuf_Iterator
+lv2_evbuf_next(LV2_Evbuf_Iterator iter)
+{
+ if (!lv2_evbuf_is_valid(iter)) {
+ return iter;
+ }
+
+ LV2_Evbuf* evbuf = iter.evbuf;
+ uint32_t offset = iter.offset;
+ uint32_t size;
+ size = ((LV2_Atom_Event*)
+ ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom)
+ + offset))->body.size;
+ offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
+
+ LV2_Evbuf_Iterator next = { evbuf, offset };
+ return next;
+}
+
+bool
+lv2_evbuf_get(LV2_Evbuf_Iterator iter,
+ uint32_t* frames,
+ uint32_t* subframes,
+ uint32_t* type,
+ uint32_t* size,
+ uint8_t** data)
+{
+ *frames = *subframes = *type = *size = 0;
+ *data = NULL;
+
+ if (!lv2_evbuf_is_valid(iter)) {
+ return false;
+ }
+
+ LV2_Atom_Sequence* aseq = &iter.evbuf->buf;
+ LV2_Atom_Event* aev = (LV2_Atom_Event*)(
+ (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq) + iter.offset);
+
+ *frames = aev->time.frames;
+ *subframes = 0;
+ *type = aev->body.type;
+ *size = aev->body.size;
+ *data = (uint8_t*)LV2_ATOM_BODY(&aev->body);
+
+ return true;
+}
+
+bool
+lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint32_t type,
+ uint32_t size,
+ const uint8_t* data)
+{
+ LV2_Atom_Sequence* aseq = &iter->evbuf->buf;
+ if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size <
+ sizeof(LV2_Atom_Event) + size) {
+ return false;
+ }
+
+ LV2_Atom_Event* aev = (LV2_Atom_Event*)(
+ (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq) + iter->offset);
+
+ aev->time.frames = frames;
+ aev->body.type = type;
+ aev->body.size = size;
+ memcpy(LV2_ATOM_BODY(&aev->body), data, size);
+
+ size = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
+ aseq->atom.size += size;
+ iter->offset += size;
+
+ return true;
+}