aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-03-23 01:26:47 +0000
committerDavid Robillard <d@drobilla.net>2012-03-23 01:26:47 +0000
commit5ef77d9bd9b102c76dbef24fbcd006c4534e9fc1 (patch)
tree37c43c211e7ba050535f2c6e4130685fdbff2bc2 /plugins
parentf161f400ce62326142f7ea5f613032f230d0d795 (diff)
downloadlv2-5ef77d9bd9b102c76dbef24fbcd006c4534e9fc1.tar.xz
Add worker extension to remove thread stuff from plugins.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/eg-sampler.lv2/sampler.c259
-rw-r--r--plugins/eg-sampler.lv2/sampler.ttl12
-rw-r--r--plugins/eg-sampler.lv2/wscript8
-rw-r--r--plugins/eg-sampler.lv2/zix/common.h83
-rw-r--r--plugins/eg-sampler.lv2/zix/ring.c231
-rw-r--r--plugins/eg-sampler.lv2/zix/ring.h136
-rw-r--r--plugins/eg-sampler.lv2/zix/sem.h236
-rw-r--r--plugins/eg-sampler.lv2/zix/thread.h133
8 files changed, 115 insertions, 983 deletions
diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c
index ec59ef3..229762e 100644
--- a/plugins/eg-sampler.lv2/sampler.c
+++ b/plugins/eg-sampler.lv2/sampler.c
@@ -44,16 +44,11 @@
#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
#include "lv2/lv2plug.in/ns/ext/state/state.h"
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-#include "zix/sem.h"
-#include "zix/thread.h"
-#include "zix/ring.h"
-
#include "./uris.h"
-#define RING_SIZE 4096
-
enum {
SAMPLER_CONTROL = 0,
SAMPLER_RESPONSE = 1,
@@ -71,39 +66,38 @@ typedef struct {
typedef struct {
/* Features */
- LV2_URID_Map* map;
+ LV2_URID_Map* map;
+ LV2_Worker_Schedule* schedule;
/* Forge for creating atoms */
LV2_Atom_Forge forge;
- /* Worker thread, communication, and sync */
- ZixThread worker_thread;
- ZixSem signal;
- ZixRing* to_worker;
- ZixRing* from_worker;
- bool exit;
-
/* Sample */
Sample* sample;
/* Ports */
- float* output_port;
- LV2_Atom_Sequence* control_port;
- LV2_Atom_Sequence* notify_port;
+ float* output_port;
+ LV2_Atom_Sequence* control_port;
+ LV2_Atom_Sequence* notify_port;
+ LV2_Atom_Forge_Frame notify_frame;
/* URIs */
SamplerURIs uris;
+ /* Current position in run() */
+ uint32_t frame_offset;
+
/* Playback state */
sf_count_t frame;
bool play;
} Sampler;
-/** An atom-like message used internally to apply/free samples.
- *
- * This is only used internally via ringbuffers, since it is not POD and
- * therefore not strictly an Atom.
- */
+/**
+ An atom-like message used internally to apply/free samples.
+
+ This is only used internally to communicate with the worker, it is not an
+ Atom because it is not POD.
+*/
typedef struct {
LV2_Atom atom;
Sample* sample;
@@ -120,7 +114,7 @@ load_sample(Sampler* plugin, const char* path)
SNDFILE* const sndfile = sf_open(path, SFM_READ, info);
if (!sndfile || !info->frames || (info->channels != 1)) {
- fprintf(stderr, "failed to open sample '%s'.\n", path);
+ fprintf(stderr, "Failed to open sample '%s'.\n", path);
free(sample);
return NULL;
}
@@ -128,7 +122,7 @@ load_sample(Sampler* plugin, const char* path)
/* Read data */
float* const data = malloc(sizeof(float) * info->frames);
if (!data) {
- fprintf(stderr, "failed to allocate memory for sample.\n");
+ fprintf(stderr, "Failed to allocate memory for sample.\n");
return NULL;
}
sf_seek(sndfile, 0ul, SEEK_SET);
@@ -144,32 +138,7 @@ load_sample(Sampler* plugin, const char* path)
return sample;
}
-static bool
-handle_set_message(Sampler* plugin,
- const LV2_Atom_Object* obj)
-{
- /* Get file path from message */
- const LV2_Atom* file_path = read_set_file(&plugin->uris, obj);
- if (!file_path) {
- return false;
- }
-
- /* Load sample. */
- Sample* sample = load_sample(plugin, LV2_ATOM_BODY(file_path));
- if (sample) {
- /* Loaded sample, send it to run() to be applied. */
- const SampleMessage msg = {
- { sizeof(sample), plugin->uris.eg_applySample },
- sample
- };
- zix_ring_write(
- plugin->from_worker, &msg, lv2_atom_pad_size(sizeof(msg)));
- }
-
- return true;
-}
-
-void
+static void
free_sample(Sample* sample)
{
if (sample) {
@@ -180,33 +149,65 @@ free_sample(Sample* sample)
}
}
-void*
-worker_thread_main(void* arg)
+/** Handle work (load or free a sample) in a non-realtime thread. */
+static LV2_Worker_Status
+work(LV2_Handle instance,
+ LV2_Worker_Respond_Function respond,
+ LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data)
{
- Sampler* plugin = (Sampler*)arg;
-
- while (!zix_sem_wait(&plugin->signal) && !plugin->exit) {
- /* Peek message header to see how much we need to read. */
- LV2_Atom head;
- zix_ring_peek(plugin->to_worker, &head, sizeof(head));
-
- /* Read message. */
- const uint32_t size = lv2_atom_pad_size(sizeof(LV2_Atom) + head.size);
- uint8_t buf[size];
- LV2_Atom* obj = (LV2_Atom*)buf;
- zix_ring_read(plugin->to_worker, buf, size);
-
- if (obj->type == plugin->uris.eg_freeSample) {
- /* Free old sample */
- SampleMessage* msg = (SampleMessage*)obj;
- free_sample(msg->sample);
- } else {
- /* Handle set message (load sample). */
- handle_set_message(plugin, (LV2_Atom_Object*)obj);
+ Sampler* self = (Sampler*)instance;
+ LV2_Atom* atom = (LV2_Atom*)data;
+ if (atom->type == self->uris.eg_freeSample) {
+ /* Free old sample */
+ SampleMessage* msg = (SampleMessage*)data;
+ free_sample(msg->sample);
+ } else {
+ /* Handle set message (load sample). */
+ LV2_Atom_Object* obj = (LV2_Atom_Object*)data;
+
+ /* Get file path from message */
+ const LV2_Atom* file_path = read_set_file(&self->uris, obj);
+ if (!file_path) {
+ return LV2_WORKER_ERR_UNKNOWN;
+ }
+
+ /* Load sample. */
+ Sample* sample = load_sample(self, LV2_ATOM_BODY(file_path));
+ if (sample) {
+ /* Loaded sample, send it to run() to be applied. */
+ respond(handle, sizeof(sample), &sample);
}
}
- return 0;
+ return LV2_WORKER_SUCCESS;
+}
+
+/** Handle a response from work() in the audio thread. */
+static LV2_Worker_Status
+work_response(LV2_Handle instance,
+ uint32_t size,
+ const void* data)
+{
+ Sampler* self = (Sampler*)instance;
+
+ SampleMessage msg = { { sizeof(Sample*), self->uris.eg_freeSample },
+ self->sample };
+
+ /* Send a message to the worker to free the current sample */
+ self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg);
+
+ /* Install the new sample */
+ self->sample = *(Sample**)data;
+
+ /* Send a notification that we're using a new sample. */
+ lv2_atom_forge_frame_time(&self->forge, self->frame_offset);
+ write_set_file(&self->forge, &self->uris,
+ self->sample->path,
+ self->sample->path_len);
+
+ return LV2_WORKER_SUCCESS;
}
static void
@@ -242,52 +243,34 @@ instantiate(const LV2_Descriptor* descriptor,
return NULL;
}
+ memset(plugin, 0, sizeof(Sampler));
plugin->sample = (Sample*)malloc(sizeof(Sample));
if (!plugin->sample) {
return NULL;
}
memset(plugin->sample, 0, sizeof(Sample));
- memset(&plugin->uris, 0, sizeof(plugin->uris));
- /* Scan host features for URID map */
- LV2_URID_Map* map = NULL;
+ /* Scan and store host features */
for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
- map = (LV2_URID_Map*)features[i]->data;
+ if (!strcmp(features[i]->URI, LV2_URID__map)) {
+ plugin->map = (LV2_URID_Map*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_WORKER__schedule)) {
+ plugin->schedule = (LV2_Worker_Schedule*)features[i]->data;
}
}
- if (!map) {
+ if (!plugin->map) {
fprintf(stderr, "Host does not support urid:map.\n");
goto fail;
+ } else if (!plugin->schedule) {
+ fprintf(stderr, "Host does not support work:schedule.\n");
+ goto fail;
}
/* Map URIS and initialise forge */
- plugin->map = map;
map_sampler_uris(plugin->map, &plugin->uris);
lv2_atom_forge_init(&plugin->forge, plugin->map);
- /* Create signal for waking up worker thread */
- if (zix_sem_init(&plugin->signal, 0)) {
- fprintf(stderr, "Could not initialize semaphore.\n");
- goto fail;
- }
-
- /* Create worker thread */
- plugin->exit = false;
- if (zix_thread_create(
- &plugin->worker_thread, 1024, worker_thread_main, plugin)) {
- fprintf(stderr, "Could not initialize worker thread.\n");
- goto fail;
- }
-
- /* Create ringbuffers for communicating with worker thread */
- plugin->to_worker = zix_ring_new(RING_SIZE);
- plugin->from_worker = zix_ring_new(RING_SIZE);
-
- zix_ring_mlock(plugin->to_worker);
- zix_ring_mlock(plugin->from_worker);
-
/* Load the default sample file */
const size_t path_len = strlen(path);
const size_t file_len = strlen(default_sample_file);
@@ -308,12 +291,6 @@ cleanup(LV2_Handle instance)
{
Sampler* plugin = (Sampler*)instance;
- plugin->exit = true;
- zix_sem_post(&plugin->signal);
- zix_thread_join(plugin->worker_thread, 0);
- zix_sem_destroy(&plugin->signal);
- zix_ring_free(plugin->to_worker);
- zix_ring_free(plugin->from_worker);
free_sample(plugin->sample);
free(plugin);
}
@@ -328,9 +305,19 @@ run(LV2_Handle instance,
sf_count_t pos = 0;
float* output = plugin->output_port;
+ /* Set up forge to write directly to notify output port. */
+ const uint32_t notify_capacity = plugin->notify_port->atom.size;
+ lv2_atom_forge_set_buffer(&plugin->forge,
+ (uint8_t*)plugin->notify_port,
+ notify_capacity);
+
+ /* Start a sequence in the notify output port. */
+ lv2_atom_forge_sequence_head(&plugin->forge, &plugin->notify_frame, 0);
+
/* Read incoming events */
LV2_SEQUENCE_FOREACH(plugin->control_port, i) {
LV2_Atom_Event* const ev = lv2_sequence_iter_get(i);
+ plugin->frame_offset = ev->time.frames;
if (ev->body.type == uris->midi_Event) {
uint8_t* const data = (uint8_t* const)(ev + 1);
if ((data[0] & 0xF0) == 0x90) {
@@ -341,13 +328,11 @@ run(LV2_Handle instance,
} else if (is_object_type(uris, ev->body.type)) {
const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
if (obj->body.otype == uris->patch_Set) {
- /* Received a set message, send it to the worker thread. */
+ /* Received a set message, send it to the worker. */
fprintf(stderr, "Queueing set message\n");
- zix_ring_write(plugin->to_worker,
- obj,
- lv2_atom_pad_size(
- lv2_atom_total_size(&obj->atom)));
- zix_sem_post(&plugin->signal);
+ plugin->schedule->schedule_work(plugin->schedule->handle,
+ lv2_atom_total_size(&ev->body),
+ &ev->body);
} else {
fprintf(stderr, "Unknown object type %d\n", obj->body.otype);
}
@@ -380,47 +365,6 @@ run(LV2_Handle instance,
for (; pos < sample_count; ++pos) {
output[pos] = 0.0f;
}
-
- /* Set up forge to write directly to notify output port buffer */
- const uint32_t notify_capacity = plugin->notify_port->atom.size;
-
- lv2_atom_forge_set_buffer(&plugin->forge,
- (uint8_t*)plugin->notify_port,
- notify_capacity);
-
- LV2_Atom_Forge_Frame seq_frame;
- lv2_atom_forge_sequence_head(&plugin->forge, &seq_frame, 0);
-
- /* Read messages from worker thread */
- SampleMessage m;
- const uint32_t msize = lv2_atom_pad_size(sizeof(m));
- while (zix_ring_read(plugin->from_worker, &m, msize) == msize) {
- if (m.atom.type == uris->eg_applySample) {
- /* Send a message to the worker to free the current sample */
- SampleMessage free_msg = {
- { sizeof(plugin->sample), uris->eg_freeSample },
- plugin->sample
- };
- zix_ring_write(plugin->to_worker,
- &free_msg,
- lv2_atom_pad_size(sizeof(free_msg)));
- zix_sem_post(&plugin->signal);
-
- /* Install the new sample */
- plugin->sample = m.sample;
-
- /* Send a notification that we're using a new sample. */
- lv2_atom_forge_frame_time(&plugin->forge, 0);
- write_set_file(&plugin->forge, uris,
- plugin->sample->path,
- plugin->sample->path_len);
-
- } else {
- fprintf(stderr, "Unknown message from worker\n");
- }
- }
-
- lv2_atom_forge_pop(&plugin->forge, &seq_frame);
}
static void
@@ -477,12 +421,15 @@ restore(LV2_Handle instance,
}
}
-const void*
+static const void*
extension_data(const char* uri)
{
- static const LV2_State_Interface state = { save, restore };
+ static const LV2_State_Interface state = { save, restore };
+ static const LV2_Worker_Interface worker = { work, work_response };
if (!strcmp(uri, LV2_STATE__Interface)) {
return &state;
+ } else if (!strcmp(uri, LV2_WORKER__Interface)) {
+ return &worker;
}
return NULL;
}
diff --git a/plugins/eg-sampler.lv2/sampler.ttl b/plugins/eg-sampler.lv2/sampler.ttl
index fa93ba4..a70be7b 100644
--- a/plugins/eg-sampler.lv2/sampler.ttl
+++ b/plugins/eg-sampler.lv2/sampler.ttl
@@ -21,12 +21,14 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
+@prefix work: <http://lv2plug.in/ns/ext/worker#> .
<http://lv2plug.in/plugins/eg-sampler>
a lv2:Plugin ;
doap:name "Example Sampler" ;
doap:license <http://opensource.org/licenses/isc> ;
- lv2:requiredFeature urid:map ;
+ lv2:requiredFeature urid:map ,
+ work:schedule ;
lv2:optionalFeature lv2:hardRTCapable ;
lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ;
ui:ui <http://lv2plug.in/plugins/eg-sampler#ui> ;
@@ -38,7 +40,7 @@
<http://lv2plug.in/ns/ext/patch#Message> ;
lv2:index 0 ;
lv2:symbol "control" ;
- lv2:name "Control"
+ lv2:name "Control" ;
] , [
a lv2:OutputPort ,
atom:MessagePort ;
@@ -46,13 +48,13 @@
atom:supports <http://lv2plug.in/ns/ext/patch#Message> ;
lv2:index 1 ;
lv2:symbol "notify" ;
- lv2:name "Notify"
+ lv2:name "Notify" ;
] , [
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 2 ;
lv2:symbol "out" ;
- lv2:name "Out"
+ lv2:name "Out" ;
] .
<http://lv2plug.in/plugins/eg-sampler#ui>
@@ -61,5 +63,5 @@
ui:portNotification [
ui:plugin <http://lv2plug.in/plugins/eg-sampler> ;
lv2:symbol "notify" ;
- ui:notifyType atom:Blank ;
+ ui:notifyType atom:Blank ;
] .
diff --git a/plugins/eg-sampler.lv2/wscript b/plugins/eg-sampler.lv2/wscript
index c25b28d..1f3ec04 100644
--- a/plugins/eg-sampler.lv2/wscript
+++ b/plugins/eg-sampler.lv2/wscript
@@ -31,6 +31,8 @@ def configure(conf):
uselib_store='LV2_PATCH')
autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-state',
uselib_store='LV2_STATE')
+ autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-worker',
+ uselib_store='LV2_WORKER')
conf.check(function_name='mlock',
header_name='sys/mman.h',
@@ -85,11 +87,11 @@ def build(bld):
# Build plugin library
obj = bld(features = 'c cshlib',
env = penv,
- source = ['sampler.c', 'zix/ring.c'],
+ source = ['sampler.c'],
name = 'sampler',
target = '%s/sampler' % bundle,
install_path = '${LV2DIR}/%s' % bundle,
- use = 'SNDFILE LV2CORE LV2_URID LV2_ATOM LV2_STATE LV2_MESSAGE',
+ use = 'SNDFILE LV2CORE LV2_URID LV2_ATOM LV2_STATE LV2_PATCH LV2_WORKER',
includes = includes)
# Build UI library
@@ -100,6 +102,6 @@ def build(bld):
name = 'sampler_ui',
target = '%s/sampler_ui' % bundle,
install_path = '${LV2DIR}/%s' % bundle,
- use = 'GTK2 LV2CORE LV2_URID LV2_ATOM LV2_STATE LV2_MESSAGE',
+ use = 'GTK2 LV2CORE LV2_URID LV2_ATOM LV2_PATCH',
includes = includes)
diff --git a/plugins/eg-sampler.lv2/zix/common.h b/plugins/eg-sampler.lv2/zix/common.h
deleted file mode 100644
index f113cfe..0000000
--- a/plugins/eg-sampler.lv2/zix/common.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- Copyright 2011-2012 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 ZIX_COMMON_H
-#define ZIX_COMMON_H
-
-/**
- @addtogroup zix
- @{
-*/
-
-/** @cond */
-#ifdef ZIX_SHARED
-# ifdef _WIN32
-# define ZIX_LIB_IMPORT __declspec(dllimport)
-# define ZIX_LIB_EXPORT __declspec(dllexport)
-# else
-# define ZIX_LIB_IMPORT __attribute__((visibility("default")))
-# define ZIX_LIB_EXPORT __attribute__((visibility("default")))
-# endif
-# ifdef ZIX_INTERNAL
-# define ZIX_API ZIX_LIB_EXPORT
-# else
-# define ZIX_API ZIX_LIB_IMPORT
-# endif
-#else
-# define ZIX_API
-#endif
-/** @endcond */
-
-#ifdef __cplusplus
-extern "C" {
-#else
-# include <stdbool.h>
-#endif
-
-typedef enum {
- ZIX_STATUS_SUCCESS,
- ZIX_STATUS_ERROR,
- ZIX_STATUS_NO_MEM,
- ZIX_STATUS_NOT_FOUND,
- ZIX_STATUS_EXISTS,
- ZIX_STATUS_BAD_ARG,
- ZIX_STATUS_BAD_PERMS,
-} ZixStatus;
-
-/**
- Function for comparing two elements.
-*/
-typedef int (*ZixComparator)(const void* a, const void* b, void* user_data);
-
-/**
- Function for testing equality of two elements.
-*/
-typedef bool (*ZixEqualFunc)(const void* a, const void* b);
-
-/**
- Function to destroy an element.
-*/
-typedef void (*ZixDestroyFunc)(void* ptr);
-
-/**
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_COMMON_H */
diff --git a/plugins/eg-sampler.lv2/zix/ring.c b/plugins/eg-sampler.lv2/zix/ring.c
deleted file mode 100644
index 29d415c..0000000
--- a/plugins/eg-sampler.lv2/zix/ring.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- Copyright 2011-2012 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 <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_MLOCK
-# include <sys/mman.h>
-# define ZIX_MLOCK(ptr, size) mlock((ptr), (size))
-#elif defined(_WIN32)
-# include <windows.h>
-# define ZIX_MLOCK(ptr, size) VirtualLock((ptr), (size))
-#else
-# pragma message("warning: No memory locking, possible RT violations")
-# define ZIX_MLOCK(ptr, size)
-#endif
-
-#if defined(__APPLE__)
-# include <libkern/OSAtomic.h>
-# define ZIX_FULL_BARRIER() OSMemoryBarrier()
-#elif defined(_WIN32)
-# include <windows.h>
-# define ZIX_FULL_BARRIER() MemoryBarrier()
-#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
-# define ZIX_FULL_BARRIER() __sync_synchronize()
-#else
-# pragma message("warning: No memory barriers, possible SMP bugs")
-# define ZIX_FULL_BARRIER()
-#endif
-
-/* No support for any systems with separate read and write barriers */
-#define ZIX_READ_BARRIER() ZIX_FULL_BARRIER()
-#define ZIX_WRITE_BARRIER() ZIX_FULL_BARRIER()
-
-#include "zix/ring.h"
-
-struct ZixRingImpl {
- uint32_t write_head; ///< Read index into buf
- uint32_t read_head; ///< Write index into buf
- uint32_t size; ///< Size (capacity) in bytes
- uint32_t size_mask; ///< Mask for fast modulo
- char* buf; ///< Contents
-};
-
-static inline uint32_t
-next_power_of_two(uint32_t size)
-{
- // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
- size--;
- size |= size >> 1;
- size |= size >> 2;
- size |= size >> 4;
- size |= size >> 8;
- size |= size >> 16;
- size++;
- return size;
-}
-
-ZixRing*
-zix_ring_new(uint32_t size)
-{
- ZixRing* ring = (ZixRing*)malloc(sizeof(ZixRing));
- ring->write_head = 0;
- ring->read_head = 0;
- ring->size = next_power_of_two(size);
- ring->size_mask = ring->size - 1;
- ring->buf = (char*)malloc(ring->size);
- return ring;
-}
-
-void
-zix_ring_free(ZixRing* ring)
-{
- free(ring->buf);
- free(ring);
-}
-
-void
-zix_ring_mlock(ZixRing* ring)
-{
- ZIX_MLOCK(ring, sizeof(ZixRing));
- ZIX_MLOCK(ring->buf, ring->size);
-}
-
-void
-zix_ring_reset(ZixRing* ring)
-{
- ring->write_head = 0;
- ring->read_head = 0;
-}
-
-static inline uint32_t
-read_space_internal(const ZixRing* ring, uint32_t r, uint32_t w)
-{
- if (r < w) {
- return w - r;
- } else {
- return (w - r + ring->size) & ring->size_mask;
- }
-}
-
-uint32_t
-zix_ring_read_space(const ZixRing* ring)
-{
- return read_space_internal(ring, ring->read_head, ring->write_head);
-}
-
-static inline uint32_t
-write_space_internal(const ZixRing* ring, uint32_t r, uint32_t w)
-{
- if (r == w) {
- return ring->size - 1;
- } else if (r < w) {
- return ((r - w + ring->size) & ring->size_mask) - 1;
- } else {
- return (r - w) - 1;
- }
-}
-
-uint32_t
-zix_ring_write_space(const ZixRing* ring)
-{
- return write_space_internal(ring, ring->read_head, ring->write_head);
-}
-
-uint32_t
-zix_ring_capacity(const ZixRing* ring)
-{
- return ring->size - 1;
-}
-
-static inline uint32_t
-peek_internal(const ZixRing* ring, uint32_t r, uint32_t w,
- uint32_t size, void* dst)
-{
- if (read_space_internal(ring, r, w) < size) {
- return 0;
- }
-
- if (r + size < ring->size) {
- memcpy(dst, &ring->buf[r], size);
- } else {
- const uint32_t first_size = ring->size - r;
- memcpy(dst, &ring->buf[r], first_size);
- memcpy((char*)dst + first_size, &ring->buf[0], size - first_size);
- }
-
- return size;
-}
-
-uint32_t
-zix_ring_peek(ZixRing* ring, void* dst, uint32_t size)
-{
- const uint32_t r = ring->read_head;
- const uint32_t w = ring->write_head;
-
- return peek_internal(ring, r, w, size, dst);
-}
-
-uint32_t
-zix_ring_read(ZixRing* ring, void* dst, uint32_t size)
-{
- const uint32_t r = ring->read_head;
- const uint32_t w = ring->write_head;
-
- if (peek_internal(ring, r, w, size, dst)) {
- ZIX_READ_BARRIER();
- ring->read_head = (r + size) & ring->size_mask;
- return size;
- } else {
- return 0;
- }
-}
-
-uint32_t
-zix_ring_skip(ZixRing* ring, uint32_t size)
-{
- const uint32_t r = ring->read_head;
- const uint32_t w = ring->write_head;
- if (read_space_internal(ring, r, w) < size) {
- return 0;
- }
-
- ZIX_READ_BARRIER();
- ring->read_head = (r + size) & ring->size_mask;
- return size;
-}
-
-uint32_t
-zix_ring_write(ZixRing* ring, const void* src, uint32_t size)
-{
- const uint32_t r = ring->read_head;
- const uint32_t w = ring->write_head;
- if (write_space_internal(ring, r, w) < size) {
- return 0;
- }
-
- if (w + size <= ring->size) {
- memcpy(&ring->buf[w], src, size);
- ZIX_WRITE_BARRIER();
- ring->write_head = (w + size) & ring->size_mask;
- } else {
- const uint32_t this_size = ring->size - w;
- memcpy(&ring->buf[w], src, this_size);
- memcpy(&ring->buf[0], (char*)src + this_size, size - this_size);
- ZIX_WRITE_BARRIER();
- ring->write_head = size - this_size;
- }
-
- return size;
-}
-
-void*
-zix_ring_write_head(ZixRing* ring)
-{
- return &ring->buf[ring->write_head];
-}
diff --git a/plugins/eg-sampler.lv2/zix/ring.h b/plugins/eg-sampler.lv2/zix/ring.h
deleted file mode 100644
index dd45769..0000000
--- a/plugins/eg-sampler.lv2/zix/ring.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- Copyright 2011-2012 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 ZIX_RING_H
-#define ZIX_RING_H
-
-#include <stdint.h>
-
-#include "zix/common.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- @addtogroup zix
- @{
- @name Ring
- @{
-*/
-
-/**
- A lock-free ring buffer.
-
- Thread-safe with a single reader and single writer, and realtime safe
- on both ends.
-*/
-typedef struct ZixRingImpl ZixRing;
-
-/**
- Create a new ring.
- @param size Size in bytes (note this may be rounded up).
-
- At most @c size - 1 bytes may be stored in the ring at once.
-*/
-ZixRing*
-zix_ring_new(uint32_t size);
-
-/**
- Destroy a ring.
-*/
-void
-zix_ring_free(ZixRing* ring);
-
-/**
- Lock the ring data into physical memory.
-
- This function is NOT thread safe or real-time safe, but it should be called
- after zix_ring_new() to lock all ring memory to avoid page faults while
- using the ring (i.e. this function MUST be called first in order for the
- ring to be truly real-time safe).
-
-*/
-void
-zix_ring_mlock(ZixRing* ring);
-
-/**
- Reset (empty) a ring.
-
- This function is NOT thread-safe, it may only be called when there are no
- readers or writers.
-*/
-void
-zix_ring_reset(ZixRing* ring);
-
-/**
- Return the number of bytes of space available for reading.
-*/
-uint32_t
-zix_ring_read_space(const ZixRing* ring);
-
-/**
- Return the number of bytes of space available for writing.
-*/
-uint32_t
-zix_ring_write_space(const ZixRing* ring);
-
-/**
- Return the capacity (i.e. total write space when empty).
-*/
-uint32_t
-zix_ring_capacity(const ZixRing* ring);
-
-/**
- Read from the ring without advancing the read head.
-*/
-uint32_t
-zix_ring_peek(ZixRing* ring, void* dst, uint32_t size);
-
-/**
- Read from the ring and advance the read head.
-*/
-uint32_t
-zix_ring_read(ZixRing* ring, void* dst, uint32_t size);
-
-/**
- Skip data in the ring (advance read head without reading).
-*/
-uint32_t
-zix_ring_skip(ZixRing* ring, uint32_t size);
-
-/**
- Write data to the ring.
-*/
-uint32_t
-zix_ring_write(ZixRing* ring, const void* src, uint32_t size);
-
-/**
- Return a pointer to the current position of the write head.
-*/
-void*
-zix_ring_write_head(ZixRing* ring);
-
-/**
- @}
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_RING_H */
diff --git a/plugins/eg-sampler.lv2/zix/sem.h b/plugins/eg-sampler.lv2/zix/sem.h
deleted file mode 100644
index d536c99..0000000
--- a/plugins/eg-sampler.lv2/zix/sem.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- Copyright 2012-2012 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 ZIX_SEM_H
-#define ZIX_SEM_H
-
-#ifdef __APPLE__
-# include <mach/mach.h>
-#elif defined(_WIN32)
-# include <windows.h>
-#else
-# include <semaphore.h>
-# include <errno.h>
-#endif
-
-#include "zix/common.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- @addtogroup zix
- @{
- @name Semaphore
- @{
-*/
-
-/**
- A counting semaphore.
-
- This is an integer that is always positive, and has two main operations:
- increment (post) and decrement (wait). If a decrement can not be performed
- (i.e. the value is 0) the caller will be blocked until another thread posts
- and the operation can succeed.
-
- Semaphores can be created with any starting value, but typically this will
- be 0 so the semaphore can be used as a simple signal where each post
- corresponds to one wait.
-
- Semaphores are very efficient (much moreso than a mutex/cond pair). In
- particular, at least on Linux, post is async-signal-safe, which means it
- does not block and will not be interrupted. If you need to signal from
- a realtime thread, this is the most appropriate primitive to use.
-*/
-typedef struct ZixSemImpl ZixSem;
-
-/**
- Create and initialize @c sem to @c initial.
-*/
-static inline ZixStatus
-zix_sem_init(ZixSem* sem, unsigned initial);
-
-/**
- Destroy @c sem.
-*/
-static inline void
-zix_sem_destroy(ZixSem* sem);
-
-/**
- Increment (and signal any waiters).
- Realtime safe.
-*/
-static inline void
-zix_sem_post(ZixSem* sem);
-
-/**
- Wait until count is > 0, then decrement.
- Obviously not realtime safe.
-*/
-static inline ZixStatus
-zix_sem_wait(ZixSem* sem);
-
-/**
- Non-blocking version of wait().
-
- @return true if decrement was successful (lock was acquired).
-*/
-static inline bool
-zix_sem_try_wait(ZixSem* sem);
-
-/**
- @cond
-*/
-
-#ifdef __APPLE__
-
-struct ZixSemImpl {
- semaphore_t sem;
-};
-
-static inline ZixStatus
-zix_sem_init(ZixSem* sem, unsigned initial)
-{
- return semaphore_create(mach_task_self(), &sem->sem, SYNC_POLICY_FIFO, 0)
- ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
-}
-
-static inline void
-zix_sem_destroy(ZixSem* sem)
-{
- semaphore_destroy(mach_task_self(), sem->sem);
-}
-
-static inline void
-zix_sem_post(ZixSem* sem)
-{
- semaphore_signal(sem->sem);
-}
-
-static inline ZixStatus
-zix_sem_wait(ZixSem* sem)
-{
- if (semaphore_wait(sem->sem) != KERN_SUCCESS) {
- return ZIX_STATUS_ERROR;
- }
- return ZIX_STATUS_SUCCESS;
-}
-
-static inline bool
-zix_sem_try_wait(ZixSem* sem)
-{
- const mach_timespec_t zero = { 0, 0 };
- return semaphore_timedwait(sem->sem, zero) == KERN_SUCCESS;
-}
-
-#elif defined(_WIN32)
-
-struct ZixSemImpl {
- HANDLE sem;
-};
-
-static inline ZixStatus
-zix_sem_init(ZixSem* sem, unsigned initial)
-{
- sem->sem = CreateSemaphore(NULL, initial, LONG_MAX, NULL);
- return (sem->sem) ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
-}
-
-static inline void
-zix_sem_destroy(ZixSem* sem)
-{
- CloseHandle(sem->sem);
-}
-
-static inline void
-zix_sem_post(ZixSem* sem)
-{
- ReleaseSemaphore(sem->sem, 1, NULL);
-}
-
-static inline ZixStatus
-zix_sem_wait(ZixSem* sem)
-{
- if (WaitForSingleObject(sem->sem, INFINITE) != WAIT_OBJECT_0) {
- return ZIX_STATUS_ERROR;
- }
- return ZIX_STATUS_SUCCESS;
-}
-
-static inline bool
-zix_sem_try_wait(ZixSem* sem)
-{
- WaitForSingleObject(sem->sem, 0);
-}
-
-#else /* !defined(__APPLE__) && !defined(_WIN32) */
-
-struct ZixSemImpl {
- sem_t sem;
-};
-
-static inline ZixStatus
-zix_sem_init(ZixSem* sem, unsigned initial)
-{
- return sem_init(&sem->sem, 0, initial)
- ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
-}
-
-static inline void
-zix_sem_destroy(ZixSem* sem)
-{
- sem_destroy(&sem->sem);
-}
-
-static inline void
-zix_sem_post(ZixSem* sem)
-{
- sem_post(&sem->sem);
-}
-
-static inline ZixStatus
-zix_sem_wait(ZixSem* sem)
-{
- while (sem_wait(&sem->sem)) {
- if (errno != EINTR) {
- return ZIX_STATUS_ERROR;
- }
- /* Otherwise, interrupted, so try again. */
- }
-
- return ZIX_STATUS_SUCCESS;
-}
-
-static inline bool
-zix_sem_try_wait(ZixSem* sem)
-{
- return (sem_trywait(&sem->sem) == 0);
-}
-
-#endif
-
-/**
- @endcond
- @}
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_SEM_H */
diff --git a/plugins/eg-sampler.lv2/zix/thread.h b/plugins/eg-sampler.lv2/zix/thread.h
deleted file mode 100644
index 602b701..0000000
--- a/plugins/eg-sampler.lv2/zix/thread.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- Copyright 2012-2012 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 ZIX_THREAD_H
-#define ZIX_THREAD_H
-
-#ifdef _WIN32
-# include <windows.h>
-#else
-# include <errno.h>
-# include <pthread.h>
-#endif
-
-#include "zix/common.h"
-
-#ifdef __cplusplus
-extern "C" {
-#else
-# include <stdbool.h>
-#endif
-
-/**
- @addtogroup zix
- @{
- @name Thread
- @{
-*/
-
-#ifdef _WIN32
-typedef HANDLE ZixThread;
-#else
-typedef pthread_t ZixThread;
-#endif
-
-/**
- Initialize @c thread to a new thread.
-
- The thread will immediately be launched, calling @c function with @c arg
- as the only parameter.
-*/
-static inline ZixStatus
-zix_thread_create(ZixThread* thread,
- size_t stack_size,
- void* (*function)(void*),
- void* arg);
-
-/**
- Join @c thread (block until @c thread exits).
-*/
-static inline ZixStatus
-zix_thread_join(ZixThread thread, void** retval);
-
-#ifdef _WIN32
-
-static inline ZixStatus
-zix_thread_create(ZixThread* thread,
- size_t stack_size,
- void* (*function)(void*),
- void* arg)
-{
- *thread = CreateThread(NULL, stack_size,
- (LPTHREAD_START_ROUTINE)function, arg,
- 0, NULL);
- return *thread ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR;
-}
-
-static inline ZixStatus
-zix_thread_join(ZixThread thread, void** retval)
-{
- return WaitForSingleObject(thread, INFINITE)
- ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR;
-}
-
-#else /* !defined(_WIN32) */
-
-static inline ZixStatus
-zix_thread_create(ZixThread* thread,
- size_t stack_size,
- void* (*function)(void*),
- void* arg)
-{
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, stack_size);
-
- const int ret = pthread_create(thread, NULL, function, arg);
- pthread_attr_destroy(&attr);
-
- if (ret == EAGAIN) {
- return ZIX_STATUS_NO_MEM;
- } else if (ret == EINVAL) {
- return ZIX_STATUS_BAD_ARG;
- } else if (ret == EPERM) {
- return ZIX_STATUS_BAD_PERMS;
- } else if (ret) {
- return ZIX_STATUS_ERROR;
- }
-
- return ZIX_STATUS_SUCCESS;
-}
-
-static inline ZixStatus
-zix_thread_join(ZixThread thread, void** retval)
-{
- return pthread_join(thread, retval)
- ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS;
-}
-
-#endif
-
-/**
- @}
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_THREAD_H */