aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-11-05 02:45:02 +0000
committerDavid Robillard <d@drobilla.net>2011-11-05 02:45:02 +0000
commitc4238232efbf531ae77cd286746d27d0dcbdf060 (patch)
tree4d3e9ce07713aa2aaacfbf8144f90c2fe022d0d9
parente0bce972cfe18a2e2538baf07190eef1526ed9e3 (diff)
downloadjalv-c4238232efbf531ae77cd286746d27d0dcbdf060.tar.gz
jalv-c4238232efbf531ae77cd286746d27d0dcbdf060.tar.bz2
jalv-c4238232efbf531ae77cd286746d27d0dcbdf060.zip
Add abstract interface for event buffers (towards event/atom compatibility).
git-svn-id: http://svn.drobilla.net/lad/trunk/jalv@3598 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/jalv.c47
-rw-r--r--src/jalv_internal.h13
-rw-r--r--src/lv2_evbuf.c159
-rw-r--r--src/lv2_evbuf.h146
-rw-r--r--wscript2
5 files changed, 335 insertions, 32 deletions
diff --git a/src/jalv.c b/src/jalv.c
index 7621e07..5eef658 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -32,7 +32,6 @@
# include <jack/session.h>
#endif
-#include "lv2/lv2plug.in/ns/ext/event/event-helpers.h"
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
#ifdef HAVE_LV2_UI_RESIZE
# include "lv2/lv2plug.in/ns/ext/ui-resize/ui-resize.h"
@@ -42,6 +41,8 @@
#include "suil/suil.h"
+#include "lv2_evbuf.h"
+
sem_t exit_sem; /**< Exit semaphore */
/**
@@ -115,7 +116,7 @@ create_port(Jalv* host,
port->lilv_port = lilv_plugin_get_port_by_index(host->plugin, port_index);
port->jack_port = NULL;
port->control = 0.0f;
- port->ev_buffer = NULL;
+ port->evbuf = NULL;
port->flow = FLOW_UNKNOWN;
/* Get the port symbol for console printing */
@@ -180,16 +181,15 @@ jalv_allocate_port_buffers(Jalv* jalv)
struct Port* const port = &jalv->ports[i];
switch (port->type) {
case TYPE_EVENT:
- free(port->ev_buffer);
- port->ev_buffer = lv2_event_buffer_new(
- jalv->midi_buf_size, LV2_EVENT_AUDIO_STAMP);
+ lv2_evbuf_free(port->evbuf);
+ port->evbuf = lv2_evbuf_new(jalv->midi_buf_size);
lilv_instance_connect_port(
- jalv->instance, i, port->ev_buffer);
+ jalv->instance, i, lv2_evbuf_get_buffer(port->evbuf));
default: break;
}
}
}
-
+
/**
Get a port structure by symbol.
@@ -288,21 +288,19 @@ jack_process_cb(jack_nframes_t nframes, void* data)
} else if (host->ports[p].type == TYPE_EVENT) {
/* Clear Jack event port buffer. */
- lv2_event_buffer_reset(host->ports[p].ev_buffer,
- LV2_EVENT_AUDIO_STAMP,
- (uint8_t*)(host->ports[p].ev_buffer + 1));
+ lv2_evbuf_reset(host->ports[p].evbuf);
if (host->ports[p].flow == FLOW_INPUT) {
void* buf = jack_port_get_buffer(host->ports[p].jack_port,
nframes);
- LV2_Event_Iterator iter;
- lv2_event_begin(&iter, host->ports[p].ev_buffer);
+ LV2_Evbuf_Iterator iter;
+ lv2_evbuf_begin(&iter, host->ports[p].evbuf);
for (uint32_t i = 0; i < jack_midi_get_event_count(buf); ++i) {
jack_midi_event_t ev;
jack_midi_event_get(&ev, buf, i);
- lv2_event_write(&iter,
+ lv2_evbuf_write(&iter,
ev.time, 0,
host->midi_event_id,
ev.size, ev.buffer);
@@ -343,14 +341,17 @@ jack_process_cb(jack_nframes_t nframes, void* data)
jack_midi_clear_buffer(buf);
- LV2_Event_Iterator iter;
- lv2_event_begin(&iter, host->ports[p].ev_buffer);
-
- for (uint32_t i = 0; i < iter.buf->event_count; ++i) {
- uint8_t* data;
- LV2_Event* ev = lv2_event_get(&iter, &data);
- jack_midi_event_write(buf, ev->frames, data, ev->size);
- lv2_event_increment(&iter);
+ LV2_Evbuf_Iterator iter;
+ lv2_evbuf_begin(&iter, host->ports[p].evbuf);
+
+ const uint32_t event_count = lv2_evbuf_get_event_count(iter.evbuf);
+ for (uint32_t i = 0; i < event_count; ++i) {
+ uint32_t frames, subframes, type, size;
+ uint8_t* data;
+ lv2_evbuf_get(&iter, &frames, &subframes,
+ &type, &size, &data);
+ jack_midi_event_write(buf, frames, data, size);
+ lv2_evbuf_increment(&iter);
}
} else if (send_ui_updates
&& !host->ports[p].flow == FLOW_INPUT
@@ -647,8 +648,8 @@ main(int argc, char** argv)
/* Deactivate JACK */
jack_deactivate(host.jack_client);
for (uint32_t i = 0; i < host.num_ports; ++i) {
- if (host.ports[i].ev_buffer) {
- free(host.ports[i].ev_buffer);
+ if (host.ports[i].evbuf) {
+ lv2_evbuf_free(host.ports[i].evbuf);
}
}
jack_client_close(host.jack_client);
diff --git a/src/jalv_internal.h b/src/jalv_internal.h
index 906ca7b..3eb1a3d 100644
--- a/src/jalv_internal.h
+++ b/src/jalv_internal.h
@@ -22,14 +22,11 @@
#include <jack/jack.h>
#include <jack/ringbuffer.h>
-#include "lv2/lv2plug.in/ns/ext/event/event.h"
-
-#include "serd/serd.h"
-
#include "lilv/lilv.h"
-
+#include "serd/serd.h"
#include "suil/suil.h"
+#include "lv2_evbuf.h"
#include "symap.h"
#ifdef __cplusplus
@@ -55,9 +52,9 @@ struct Port {
const LilvPort* lilv_port;
enum PortType type;
enum PortFlow flow;
- jack_port_t* jack_port; /**< For audio/MIDI ports, otherwise NULL */
- float control; /**< For control ports, otherwise 0.0f */
- LV2_Event_Buffer* ev_buffer; /**< For MIDI ports, otherwise NULL */
+ jack_port_t* jack_port; /**< For audio/MIDI ports, otherwise NULL */
+ float control; /**< For control ports, otherwise 0.0f */
+ LV2_Evbuf* evbuf; /**< For MIDI ports, otherwise NULL */
};
struct Property {
diff --git a/src/lv2_evbuf.c b/src/lv2_evbuf.c
new file mode 100644
index 0000000..7849124
--- /dev/null
+++ b/src/lv2_evbuf.c
@@ -0,0 +1,159 @@
+/*
+ Copyright 2008-2011 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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/event/event.h"
+
+#include "lv2_evbuf.h"
+
+struct LV2_Evbuf_Impl {
+ union {
+ LV2_Event_Buffer event;
+ LV2_Atom_Event_Buffer atom_event;
+ } buf;
+ LV2_Evbuf_Type type;
+};
+
+static inline uint32_t
+lv2_evbuf_pad_size(uint32_t size)
+{
+ return (size + 7) & (~7);
+}
+
+LV2_Evbuf*
+lv2_evbuf_new(uint32_t capacity)
+{
+ LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(sizeof(LV2_Evbuf));
+ evbuf->type = LV2_EVBUF_EVENT_BUFFER;
+ evbuf->buf.event.capacity = capacity;
+ lv2_evbuf_reset(evbuf);
+ return evbuf;
+}
+
+void
+lv2_evbuf_free(LV2_Evbuf* evbuf)
+{
+ free(evbuf);
+}
+
+void
+lv2_evbuf_reset(LV2_Evbuf* evbuf)
+{
+ LV2_Event_Buffer* buf = &evbuf->buf.event;
+ buf->header_size = sizeof(LV2_Event_Buffer);
+ buf->stamp_type = LV2_EVENT_AUDIO_STAMP;
+ buf->event_count = 0;
+ buf->size = 0;
+}
+
+uint32_t
+lv2_evbuf_get_event_count(LV2_Evbuf* evbuf)
+{
+ return evbuf->buf.event.event_count;
+}
+
+void*
+lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
+{
+ return &evbuf->buf.event;
+}
+
+bool
+lv2_evbuf_begin(LV2_Evbuf_Iterator* iter,
+ LV2_Evbuf* evbuf)
+{
+ LV2_Event_Buffer* buf = &evbuf->buf.event;
+ iter->offset = 0;
+ return buf->size > 0;
+}
+
+bool
+lv2_evbuf_is_valid(LV2_Evbuf_Iterator* iter)
+{
+ return iter->offset < iter->evbuf->buf.event.size;
+}
+
+bool
+lv2_evbuf_increment(LV2_Evbuf_Iterator* iter)
+{
+ assert(lv2_evbuf_is_valid(iter));
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->evbuf->buf.event.data + iter->offset);
+
+ iter->offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + ev->size);
+
+ return true;
+}
+
+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;
+ assert(lv2_evbuf_is_valid(iter));
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->evbuf->buf.event.data + iter->offset);
+
+ *frames = ev->frames;
+ *subframes = ev->subframes;
+ *type = ev->type;
+ *size = ev->size;
+ *data = (uint8_t*)ev + sizeof(LV2_Event);
+
+ 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_Event_Buffer* buf = &iter->evbuf->buf.event;
+ if (buf->capacity - buf->size < sizeof(LV2_Event) + size) {
+ return false;
+ }
+
+ LV2_Event* const ev = (LV2_Event*)((uint8_t*)buf->data + iter->offset);
+
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
+ ++buf->event_count;
+
+ size = lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
+ buf->size += size;
+ iter->offset += size;
+
+ return true;
+}
diff --git a/src/lv2_evbuf.h b/src/lv2_evbuf.h
new file mode 100644
index 0000000..94aa1e0
--- /dev/null
+++ b/src/lv2_evbuf.h
@@ -0,0 +1,146 @@
+/*
+ Copyright 2008-2011 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.
+*/
+
+#ifndef LV2_EVBUF_H
+#define LV2_EVBUF_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Format of actual buffer.
+*/
+typedef enum {
+ /**
+ An old ev:EventBuffer (LV2_Event_Buffer).
+ */
+ LV2_EVBUF_EVENT_BUFFER,
+
+ /**
+ A new atom:EventBuffer (LV2_Atom_Event_Buffer).
+ */
+ LV2_EVBUF_ATOM_EVENT_BUFFER
+} LV2_Evbuf_Type;
+
+/**
+ An abstract/opaque LV2 event buffer.
+*/
+typedef struct LV2_Evbuf_Impl LV2_Evbuf;
+
+/**
+ An iterator over an LV2_Evbuf.
+*/
+typedef struct {
+ LV2_Evbuf* evbuf;
+ uint32_t offset;
+} LV2_Evbuf_Iterator;
+
+/**
+ Allocate a new, empty event buffer.
+*/
+LV2_Evbuf*
+lv2_evbuf_new(uint32_t capacity);
+
+/**
+ Free an event buffer allocated with lv2_evbuf_new.
+*/
+void
+lv2_evbuf_free(LV2_Evbuf* evbuf);
+
+/**
+ Clear and initialize an existing event buffer.
+ The contents of buf are ignored entirely and overwritten, except capacity
+ which is unmodified.
+*/
+void
+lv2_evbuf_reset(LV2_Evbuf* evbuf);
+
+/**
+ Return the number of events stored in the buffer.
+*/
+uint32_t
+lv2_evbuf_get_event_count(LV2_Evbuf* evbuf);
+
+/**
+ Return the actual buffer implementation.
+ The format of the buffer returned depends on the buffer type.
+*/
+void*
+lv2_evbuf_get_buffer(LV2_Evbuf* evbuf);
+
+/**
+ Reset an iterator to point to the start of @a buf.
+ @return True if @a iter is valid, otherwise false (buffer is empty)
+*/
+bool
+lv2_evbuf_begin(LV2_Evbuf_Iterator* iter,
+ LV2_Evbuf* evbuf);
+
+/**
+ Check if @a iter is valid.
+ @return True if @a iter is valid, otherwise false (past end of buffer)
+*/
+bool
+lv2_evbuf_is_valid(LV2_Evbuf_Iterator* iter);
+
+/**
+ Advance @a iter forward one event.
+ @a iter must be valid.
+ @return True if @a iter is valid, otherwise false (reached end of buffer)
+*/
+bool
+lv2_evbuf_increment(LV2_Evbuf_Iterator* iter);
+
+/**
+ Dereference an event iterator (i.e. get the event currently pointed to).
+ @a iter must be valid.
+ @a type Set to the type of the event.
+ @a size Set to the size of the event.
+ @a data Set to the contents of the event.
+ @return True on success.
+*/
+bool
+lv2_evbuf_get(LV2_Evbuf_Iterator* iter,
+ uint32_t* frames,
+ uint32_t* subframes,
+ uint32_t* type,
+ uint32_t* size,
+ uint8_t** data);
+
+/**
+ Write an event at @a iter.
+ The event (if any) pointed to by @a iter will be overwritten, and @a iter
+ incremented to point to the following event (i.e. several calls to this
+ function can be done in sequence without twiddling iter in-between).
+ @return True if event was written, otherwise false (buffer is full).
+*/
+bool
+lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint32_t type,
+ uint32_t size,
+ const uint8_t* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LV2_EVBUF_H */
diff --git a/wscript b/wscript
index b75fc80..7d94bc5 100644
--- a/wscript
+++ b/wscript
@@ -77,7 +77,7 @@ def configure(conf):
def build(bld):
libs = 'LILV SUIL JACK SERD LV2CORE LV2_EVENT LV2_URI_MAP LV2_PERSIST'
- source = 'src/jalv.c src/symap.c src/persist.c'
+ source = 'src/jalv.c src/symap.c src/persist.c src/lv2_evbuf.c'
# Non-GUI version
obj = bld(features = 'c cprogram',