diff options
-rw-r--r-- | src/jalv.c | 47 | ||||
-rw-r--r-- | src/jalv_internal.h | 13 | ||||
-rw-r--r-- | src/lv2_evbuf.c | 159 | ||||
-rw-r--r-- | src/lv2_evbuf.h | 146 | ||||
-rw-r--r-- | wscript | 2 |
5 files changed, 335 insertions, 32 deletions
@@ -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 */ @@ -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', |