aboutsummaryrefslogtreecommitdiffstats
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
parentf161f400ce62326142f7ea5f613032f230d0d795 (diff)
downloadlv2-5ef77d9bd9b102c76dbef24fbcd006c4534e9fc1.tar.xz
Add worker extension to remove thread stuff from plugins.
-rw-r--r--doc/reference.doxygen.in1
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/forge.h1
-rw-r--r--lv2/lv2plug.in/ns/ext/urid/urid.ttl4
l---------lv2/lv2plug.in/ns/ext/worker/ext.pc.in1
-rw-r--r--lv2/lv2plug.in/ns/ext/worker/manifest.ttl8
l---------lv2/lv2plug.in/ns/ext/worker/waf1
-rw-r--r--lv2/lv2plug.in/ns/ext/worker/worker.h138
-rw-r--r--lv2/lv2plug.in/ns/ext/worker/worker.ttl58
l---------lv2/lv2plug.in/ns/ext/worker/wscript1
-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
17 files changed, 325 insertions, 986 deletions
diff --git a/doc/reference.doxygen.in b/doc/reference.doxygen.in
index f97a93f..9ed3968 100644
--- a/doc/reference.doxygen.in
+++ b/doc/reference.doxygen.in
@@ -587,6 +587,7 @@ INPUT = \
@LV2_SRCDIR@/lv2/lv2plug.in/ns/ext/ui-resize/ui-resize.h \
@LV2_SRCDIR@/lv2/lv2plug.in/ns/ext/uri-map/uri-map.h \
@LV2_SRCDIR@/lv2/lv2plug.in/ns/ext/urid/urid.h \
+ @LV2_SRCDIR@/lv2/lv2plug.in/ns/ext/worker/worker.h \
@LV2_SRCDIR@/lv2/lv2plug.in/ns/extensions/ui/ui.h \
@LV2_SRCDIR@/lv2/lv2plug.in/ns/lv2core/lv2.h
diff --git a/lv2/lv2plug.in/ns/ext/atom/forge.h b/lv2/lv2plug.in/ns/ext/atom/forge.h
index 322e14e..ea5977e 100644
--- a/lv2/lv2plug.in/ns/ext/atom/forge.h
+++ b/lv2/lv2plug.in/ns/ext/atom/forge.h
@@ -120,7 +120,6 @@ static inline void
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
{
lv2_atom_forge_set_buffer(forge, NULL, 0);
- forge->stack = NULL;
forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
forge->Bool = map->map(map->handle, LV2_ATOM__Bool);
forge->Double = map->map(map->handle, LV2_ATOM__Double);
diff --git a/lv2/lv2plug.in/ns/ext/urid/urid.ttl b/lv2/lv2plug.in/ns/ext/urid/urid.ttl
index 121ffaf..d080107 100644
--- a/lv2/lv2plug.in/ns/ext/urid/urid.ttl
+++ b/lv2/lv2plug.in/ns/ext/urid/urid.ttl
@@ -68,7 +68,7 @@ urid:map
lv2:documentation """
<p>A feature which is used to map URIs to integers. To support this feature,
the host must pass an LV2_Feature to LV2_Descriptor::instantiate() with URI
-LV2_URID_MAP_URI and data pointed to an instance of LV2_URID_Map.</p>
+LV2_URID__map and data pointed to an instance of LV2_URID_Map.</p>
""" .
urid:unmap
@@ -76,6 +76,6 @@ urid:unmap
lv2:documentation """
<p>A feature which is used to unmap URIs previously mapped to integers by
urid:map. To support this feature, the host must pass an LV2_Feature to
-LV2_Descriptor::instantiate() with URI LV2_URID_UNMAP_URI and data pointed to
+LV2_Descriptor::instantiate() with URI LV2_URID__unmapl and data pointed to
an instance of LV2_URID_Unmap.</p>
""" .
diff --git a/lv2/lv2plug.in/ns/ext/worker/ext.pc.in b/lv2/lv2plug.in/ns/ext/worker/ext.pc.in
new file mode 120000
index 0000000..03dd044
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/ext.pc.in
@@ -0,0 +1 @@
+../../../../../ext.pc.in \ No newline at end of file
diff --git a/lv2/lv2plug.in/ns/ext/worker/manifest.ttl b/lv2/lv2plug.in/ns/ext/worker/manifest.ttl
new file mode 100644
index 0000000..af46f01
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/manifest.ttl
@@ -0,0 +1,8 @@
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<http://lv2plug.in/ns/ext/worker>
+ a lv2:Specification ;
+ lv2:minorVersion 0 ;
+ lv2:microVersion 1 ;
+ rdfs:seeAlso <worker.ttl> .
diff --git a/lv2/lv2plug.in/ns/ext/worker/waf b/lv2/lv2plug.in/ns/ext/worker/waf
new file mode 120000
index 0000000..5235032
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/waf
@@ -0,0 +1 @@
+../../../../../waf \ No newline at end of file
diff --git a/lv2/lv2plug.in/ns/ext/worker/worker.h b/lv2/lv2plug.in/ns/ext/worker/worker.h
new file mode 100644
index 0000000..612a24c
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/worker.h
@@ -0,0 +1,138 @@
+/*
+ Copyright 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.
+*/
+
+/**
+ @file worker.h C header for the LV2 Worker extension
+ <http://lv2plug.in/ns/ext/worker>.
+*/
+
+#ifndef LV2_WORKER_H
+#define LV2_WORKER_H
+
+#include <stdint.h>
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+
+#define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker"
+#define LV2_WORKER_PREFIX LV2_WORKER_URI "#"
+
+#define LV2_WORKER__Interface LV2_WORKER_PREFIX "Interface"
+#define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule"
+
+/**
+ A status code for worker functions.
+*/
+typedef enum {
+ LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */
+ LV2_WORKER_ERR_UNKNOWN = 1, /**< Unknown error. */
+ LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */
+} LV2_Worker_Status;
+
+typedef void* LV2_Worker_Respond_Handle;
+
+/**
+ A function to respond to run() from the worker method.
+
+ The @p data MUST be safe for the host to copy and later pass to
+ work_response(), and the host MUST guarantee that it will be eventually
+ passed to work_response() if this function returns LV2_WORKER_SUCCESS.
+*/
+typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)(
+ LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data);
+
+/**
+ LV2 Plugin Worker Interface.
+
+ This is the interface provided by the plugin to implement a worker method.
+ The plugin's extension_data() method should return an LV2_Worker_Interface
+ when called with LV2_WORKER__Interface as its argument.
+*/
+typedef struct _LV2_Worker_Interface {
+ /**
+ The worker method. This is called by the host in a non-realtime context
+ as requested, possibly with an arbitrary message to handle.
+
+ A response can be sent to run() using @p respond. The plugin MUST NOT
+ make any assumptions about which thread calls this method, other than
+ the fact that there are no real-time requirements.
+
+ @param instance The LV2 instance this is a method on.
+ @param respond A function for sending a response to run().
+ @param handle Must be passed to @p respond if it is called.
+ @param size The size of @p data.
+ @param data Data from run(), or NULL.
+ */
+ LV2_Worker_Status (*work)(LV2_Handle instance,
+ LV2_Worker_Respond_Function respond,
+ LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data);
+
+ /**
+ Handle a response from the worker. This is called by the host in the
+ run() context when a response from the worker is ready.
+
+ @param instance The LV2 instance this is a method on.
+ @param size The size of @p body.
+ @param body Message body, or NULL.
+ */
+ LV2_Worker_Status (*work_response)(LV2_Handle instance,
+ uint32_t size,
+ const void* body);
+} LV2_Worker_Interface;
+
+typedef void* LV2_Worker_Schedule_Handle;
+
+typedef struct _LV2_Worker_Schedule {
+ /**
+ Opaque host data.
+ */
+ LV2_Worker_Schedule_Handle handle;
+
+ /**
+ Request from run() that the host call the worker.
+
+ This function is in the audio threading class. It should be called from
+ run() to request that the host call the work() method in a non-realtime
+ context with the given arguments.
+
+ This function is always safe to call from run(), but it is not
+ guaranteed that the worker is actually called from a different thread.
+ In particular, when free-wheeling (e.g. for offline rendering), the
+ worker may be executed immediately. This allows single-threaded
+ processing with sample accuracy and avoids timing problems when run() is
+ executing much faster or slower than real-time.
+
+ Plugins SHOULD be written in such a way that if the worker runs
+ immediately, and responses from the worker are delivered immediately,
+ the effect of the work takes place immediately with sample accuracy.
+
+ The @p data MUST be safe for the host to copy and later pass to work(),
+ and the host MUST guarantee that it will be eventually passed to work()
+ if this function returns LV2_WORKER_SUCCESS.
+
+ @param handle The handle field of this struct.
+ @param size The size of @p body.
+ @param data Message to pass to work(), or NULL.
+ */
+ LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle,
+ uint32_t size,
+ const void* data);
+} LV2_Worker_Schedule;
+
+#endif /* LV2_WORKER_H */
diff --git a/lv2/lv2plug.in/ns/ext/worker/worker.ttl b/lv2/lv2plug.in/ns/ext/worker/worker.ttl
new file mode 100644
index 0000000..ea49056
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/worker.ttl
@@ -0,0 +1,58 @@
+# LV2 Worker Extension
+# Copyright 2012 David Robillard <d@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.
+
+@prefix work: <http://lv2plug.in/ns/ext/worker#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+
+<http://lv2plug.in/ns/ext/worker>
+ a lv2:Specification ,
+ lv2:Feature ;
+ doap:name "LV2 Worker" ;
+ doap:shortdesc "Support for a non-realtime plugin worker method." ;
+ lv2:documentation """
+""" .
+
+work:Interface
+ a rdfs:Class ;
+ rdfs:subClassOf lv2:ExtensionData ;
+ lv2:documentation """
+<p>A structure (LV2_Worker_Interface) which contains the worker method to be
+called by the host. In order to support this extension, the plugin must return
+a valid LV2_Worker_Interface from LV2_Descriptor::extension_data() when it is
+called with URI LV2_WORKER__Interface.</p>
+
+<p>The plugin data file should describe this like so:</p>
+<pre class="turtle-code">
+@prefix work: &lt;http://lv2plug.in/ns/ext/worker#&gt; .
+
+&lt;plugin&gt;
+ a lv2:Plugin ;
+ lv2:extensionData work:Interface .
+</pre>
+""" .
+
+work:schedule
+ a lv2:Feature ;
+ lv2:documentation """
+<p>A feature which provides functions for use by the plugin to implement a
+worker method. To support this feature, the host must pass an LV2_Feature to
+LV2_Descriptor::instantiate() with URI LV2_WORKER__schedule and data pointed to
+an instance of LV2_Worker_Schedule.</p>
+""" .
diff --git a/lv2/lv2plug.in/ns/ext/worker/wscript b/lv2/lv2plug.in/ns/ext/worker/wscript
new file mode 120000
index 0000000..7e2c01b
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/worker/wscript
@@ -0,0 +1 @@
+../../../../../ext.wscript \ No newline at end of file
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 */