aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/eg-sampler.lv2
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-02-08 01:38:38 +0000
committerDavid Robillard <d@drobilla.net>2012-02-08 01:38:38 +0000
commit046c0a8bbffb572df1c6376d3bf525aac9b3a9fa (patch)
tree1299f3ed06b43031060673fefc32bc2f29587638 /plugins/eg-sampler.lv2
parent0ad020578277f8aade6b2df90385b911775ead18 (diff)
downloadlv2-046c0a8bbffb572df1c6376d3bf525aac9b3a9fa.tar.xz
Heavily revise atom extension into a release candidate.
Diffstat (limited to 'plugins/eg-sampler.lv2')
-rw-r--r--plugins/eg-sampler.lv2/sampler.c112
-rw-r--r--plugins/eg-sampler.lv2/sampler.ttl9
-rw-r--r--plugins/eg-sampler.lv2/sampler_ui.c32
-rw-r--r--plugins/eg-sampler.lv2/uris.h10
4 files changed, 78 insertions, 85 deletions
diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c
index 5584143..ae5434a 100644
--- a/plugins/eg-sampler.lv2/sampler.c
+++ b/plugins/eg-sampler.lv2/sampler.c
@@ -1,8 +1,8 @@
/*
LV2 Sampler Example Plugin
+ Copyright 2011-2012 David Robillard <d@drobilla.net>
Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
Copyright 2011 James Morris <jwm.art.net@gmail.com>
- Copyright 2011 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
@@ -24,11 +24,11 @@
incoming events) and also triggers their playback (based on incoming MIDI
note events). The sample must be monophonic.
- So that the runSampler() method stays real-time safe, the plugin creates a
- worker thread (worker_thread_main) that listens for file loading events. It
- loads everything in plugin->pending_samp and then signals the runSampler()
- that it's time to install it. runSampler() just has to swap pointers... so
- the change happens very fast and atomically.
+ So that the run() method stays real-time safe, the plugin creates a worker
+ thread (worker_thread_main) that listens for file loading events. It loads
+ everything in plugin->pending_samp and then signals the run() that it's time
+ to install it. run() just has to swap pointers... so the change happens
+ very fast and atomically.
*/
#include <assert.h>
@@ -41,7 +41,8 @@
#include <sndfile.h>
-#include "lv2/lv2plug.in/ns/ext/atom/atom-buffer.h"
+#include <semaphore.h>
+
#include "lv2/lv2plug.in/ns/ext/atom/atom-helpers.h"
#include "lv2/lv2plug.in/ns/ext/state/state.h"
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
@@ -69,22 +70,21 @@ typedef struct {
LV2_URID_Map* map;
/* Sample */
- SampleFile* samp;
- SampleFile* pending_samp;
- pthread_mutex_t pending_samp_mutex; /**< Protects pending_samp */
- pthread_cond_t pending_samp_cond; /**< Signaling mechanism */
- int pending_sample_ready;
+ SampleFile* samp;
+ SampleFile* pending_samp;
+ sem_t signal;
+ int pending_sample_ready;
/* Ports */
- float* output_port;
- LV2_Atom_Buffer* event_port;
+ float* output_port;
+ LV2_Atom_Sequence* event_port;
/* URIs */
struct {
- LV2_URID midi_event;
- LV2_URID atom_message;
+ LV2_URID midi_Event;
+ LV2_URID atom_Object;
LV2_URID set_message;
- LV2_URID state_path;
+ LV2_URID state_Path;
LV2_URID filename_key;
} uris;
@@ -139,16 +139,16 @@ worker_thread_main(void* arg)
{
Sampler* plugin = (Sampler*)arg;
- pthread_mutex_lock(&plugin->pending_samp_mutex);
while (true) {
/* Wait for run() to signal that we need to load a sample */
- pthread_cond_wait(&plugin->pending_samp_cond,
- &plugin->pending_samp_mutex);
+ if (sem_wait(&plugin->signal)) {
+ fprintf(stderr, "Odd, sem_wait failed...\n");
+ continue;
+ }
/* Then load it */
handle_load_sample(plugin);
}
- pthread_mutex_unlock(&plugin->pending_samp_mutex);
return 0;
}
@@ -159,6 +159,7 @@ cleanup(LV2_Handle instance)
Sampler* plugin = (Sampler*)instance;
pthread_cancel(plugin->worker_thread);
pthread_join(plugin->worker_thread, 0);
+ sem_destroy(&plugin->signal);
free(plugin->samp->data);
free(plugin->pending_samp->data);
@@ -176,7 +177,7 @@ connect_port(LV2_Handle instance,
switch (port) {
case SAMPLER_CONTROL:
- plugin->event_port = (LV2_Atom_Buffer*)data;
+ plugin->event_port = (LV2_Atom_Sequence*)data;
break;
case SAMPLER_OUT:
plugin->output_port = (float*)data;
@@ -196,7 +197,7 @@ instantiate(const LV2_Descriptor* descriptor,
if (!plugin) {
return NULL;
}
-
+
plugin->samp = (SampleFile*)malloc(sizeof(SampleFile));
plugin->pending_samp = (SampleFile*)malloc(sizeof(SampleFile));
if (!plugin->samp || !plugin->pending_samp) {
@@ -207,15 +208,13 @@ instantiate(const LV2_Descriptor* descriptor,
memset(plugin->pending_samp, 0, sizeof(SampleFile));
memset(&plugin->uris, 0, sizeof(plugin->uris));
- /* Initialise mutexes and conditions for the worker thread */
- if (pthread_mutex_init(&plugin->pending_samp_mutex, 0)) {
- fprintf(stderr, "Could not initialize next_sample_mutex.\n");
- goto fail;
- }
- if (pthread_cond_init(&plugin->pending_samp_cond, 0)) {
- fprintf(stderr, "Could not initialize next_sample_waitcond.\n");
+ /* Create signal for waking up worker thread */
+ if (sem_init(&plugin->signal, 0, 0)) {
+ fprintf(stderr, "Could not initialize semaphore.\n");
goto fail;
}
+
+ /* Create worker thread */
if (pthread_create(&plugin->worker_thread, 0, worker_thread_main, plugin)) {
fprintf(stderr, "Could not initialize worker thread.\n");
goto fail;
@@ -225,13 +224,13 @@ instantiate(const LV2_Descriptor* descriptor,
for (int i = 0; features[i]; ++i) {
if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
plugin->map = (LV2_URID_Map*)features[i]->data;
- plugin->uris.midi_event = plugin->map->map(
+ plugin->uris.midi_Event = plugin->map->map(
plugin->map->handle, MIDI_EVENT_URI);
- plugin->uris.atom_message = plugin->map->map(
- plugin->map->handle, ATOM_MESSAGE_URI);
+ plugin->uris.atom_Object = plugin->map->map(
+ plugin->map->handle, ATOM_OBJECT_URI);
plugin->uris.set_message = plugin->map->map(
plugin->map->handle, SET_MESSAGE_URI);
- plugin->uris.state_path = plugin->map->map(
+ plugin->uris.state_Path = plugin->map->map(
plugin->map->handle, LV2_STATE_PATH_URI);
plugin->uris.filename_key = plugin->map->map(
plugin->map->handle, FILENAME_URI);
@@ -267,39 +266,35 @@ run(LV2_Handle instance,
float* output = plugin->output_port;
/* Read incoming events */
- for (LV2_Atom_Buffer_Iterator i = lv2_atom_buffer_begin(plugin->event_port);
- lv2_atom_buffer_is_valid(i);
- i = lv2_atom_buffer_next(i)) {
-
- LV2_Atom_Event* const ev = lv2_atom_buffer_get(i);
- if (ev->body.type == plugin->uris.midi_event) {
+ LV2_SEQUENCE_FOREACH(plugin->event_port, i) {
+ LV2_Atom_Event* const ev = lv2_sequence_iter_get(i);
+ if (ev->body.type == plugin->uris.midi_Event) {
uint8_t* const data = (uint8_t* const)(ev + 1);
if ((data[0] & 0xF0) == 0x90) {
- start_frame = ev->frames;
+ start_frame = ev->time.audio.frames;
plugin->frame = 0;
plugin->play = true;
}
- } else if (ev->body.type == plugin->uris.atom_message) {
- const LV2_Thing* msg = (LV2_Thing*)&ev->body;
- if (msg->id == plugin->uris.set_message) {
+ } else if (ev->body.type == plugin->uris.atom_Object) {
+ const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
+ if (obj->type == plugin->uris.set_message) {
const LV2_Atom* filename = NULL;
- LV2_Thing_Query q[] = {
+ LV2_Atom_Object_Query q[] = {
{ plugin->uris.filename_key, &filename },
- LV2_THING_QUERY_END
+ LV2_OBJECT_QUERY_END
};
- lv2_thing_query(msg, q);
+ lv2_object_get(obj, q);
if (filename) {
- memcpy(plugin->pending_samp->filepath,
- filename->body,
- filename->size);
- pthread_cond_signal(&plugin->pending_samp_cond);
-
+ char* str = (char*)LV2_ATOM_BODY(filename);
+ fprintf(stderr, "Request to load %s\n", str);
+ memcpy(plugin->pending_samp->filepath, str, filename->size);
+ sem_post(&plugin->signal);
} else {
fprintf(stderr, "Ignored set message with no filename\n");
}
} else {
- fprintf(stderr, "Unknown message type %d\n", msg->id);
+ fprintf(stderr, "Unknown message type %d\n", obj->id);
}
} else {
@@ -328,18 +323,13 @@ run(LV2_Handle instance,
}
/* Check if we have a sample pending */
- if (!plugin->play
- && plugin->pending_sample_ready
- && pthread_mutex_trylock(&plugin->pending_samp_mutex)) {
+ if (!plugin->play && plugin->pending_sample_ready) {
/* Install the new sample */
- SampleFile* tmp;
- tmp = plugin->samp;
+ SampleFile* tmp = plugin->samp;
plugin->samp = plugin->pending_samp;
plugin->pending_samp = tmp;
plugin->pending_sample_ready = 0;
free(plugin->pending_samp->data); // FIXME: non-realtime!
-
- pthread_mutex_unlock(&plugin->pending_samp_mutex);
}
/* Add zeros to end if sample not long enough (or not playing) */
@@ -376,7 +366,7 @@ save(LV2_Handle instance,
map_uri(plugin, FILENAME_URI),
apath,
strlen(plugin->samp->filepath) + 1,
- plugin->uris.state_path,
+ plugin->uris.state_Path,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
free(apath);
diff --git a/plugins/eg-sampler.lv2/sampler.ttl b/plugins/eg-sampler.lv2/sampler.ttl
index 54eb36b..7548396 100644
--- a/plugins/eg-sampler.lv2/sampler.ttl
+++ b/plugins/eg-sampler.lv2/sampler.ttl
@@ -25,13 +25,14 @@
a lv2:Plugin ;
doap:name "Example Sampler" ;
doap:license <http://opensource.org/licenses/isc> ;
- lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#Mapper> ;
- lv2:optionalFeature lv2:hardRtCapable ;
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#map> ;
+ lv2:optionalFeature lv2:hardRTCapable ;
lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ;
ui:ui <http://lv2plug.in/plugins/eg-sampler#ui> ;
lv2:port [
a lv2:InputPort ,
- atom:EventPort ;
+ atom:MessagePort ;
+ atom:bufferType atom:Sequence ;
atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;
lv2:index 0 ;
lv2:symbol "control" ;
@@ -46,5 +47,5 @@
<http://lv2plug.in/plugins/eg-sampler#ui>
a ui:GtkUI ;
- lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#Mapper> ;
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#map> ;
ui:binary <sampler_ui.so> .
diff --git a/plugins/eg-sampler.lv2/sampler_ui.c b/plugins/eg-sampler.lv2/sampler_ui.c
index dcc808f..ea57cc1 100644
--- a/plugins/eg-sampler.lv2/sampler_ui.c
+++ b/plugins/eg-sampler.lv2/sampler_ui.c
@@ -34,8 +34,9 @@
#define SAMPLER_UI_URI "http://lv2plug.in/plugins/eg-sampler#ui"
typedef struct {
+ LV2_Atom_Forge forge;
+
LV2_URID_Map* map;
- LV2_Atom_Forge* forge;
LV2UI_Write_Function write;
LV2UI_Controller controller;
@@ -71,19 +72,20 @@ on_load_clicked(GtkWidget* widget,
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
const size_t filename_len = strlen(filename);
gtk_widget_destroy(dialog);
-
- uint8_t msg_buf[4096];
- LV2_Thing* msg = (LV2_Thing*)msg_buf;
- lv2_atom_forge_set_message(ui->forge, msg, uri_to_id(ui, SET_MESSAGE_URI));
- lv2_thing_append(msg,
- uri_to_id(ui, FILENAME_URI),
- uri_to_id(ui, NS_ATOM "String"),
- filename_len,
- filename);
-
- ui->write(ui->controller, 0, sizeof(LV2_Atom) + msg->size,
+
+#define OBJ_BUF_SIZE 1024
+ uint8_t obj_buf[OBJ_BUF_SIZE];
+ lv2_atom_forge_set_buffer(&ui->forge, obj_buf, OBJ_BUF_SIZE);
+
+ LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_object(
+ &ui->forge, NULL, 0, uri_to_id(ui, SET_MESSAGE_URI));
+ lv2_atom_forge_property_head(&ui->forge, obj,
+ uri_to_id(ui, FILENAME_URI), 0);
+ lv2_atom_forge_string(&ui->forge, obj, (uint8_t*)filename, filename_len);
+
+ ui->write(ui->controller, 0, sizeof(LV2_Atom) + obj->size,
uri_to_id(ui, NS_ATOM "atomTransfer"),
- msg);
+ obj);
g_free(filename);
}
@@ -98,7 +100,7 @@ instantiate(const LV2UI_Descriptor* descriptor,
const LV2_Feature* const* features)
{
SamplerUI* ui = (SamplerUI*)malloc(sizeof(SamplerUI));
- ui->map = NULL;
+ ui->map = NULL;
ui->write = write_function;
ui->controller = controller;
ui->button = NULL;
@@ -117,7 +119,7 @@ instantiate(const LV2UI_Descriptor* descriptor,
return NULL;
}
- ui->forge = lv2_atom_forge_new(ui->map);
+ lv2_atom_forge_init(&ui->forge, ui->map);
ui->button = gtk_button_new_with_label("Load Sample");
g_signal_connect(ui->button, "clicked",
diff --git a/plugins/eg-sampler.lv2/uris.h b/plugins/eg-sampler.lv2/uris.h
index d4df237..5e968ed 100644
--- a/plugins/eg-sampler.lv2/uris.h
+++ b/plugins/eg-sampler.lv2/uris.h
@@ -18,8 +18,8 @@
#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-#define SAMPLER_URI "http://lv2plug.in/plugins/eg-sampler"
-#define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
-#define FILENAME_URI SAMPLER_URI "#filename"
-#define ATOM_MESSAGE_URI "http://lv2plug.in/ns/ext/atom#Message"
-#define SET_MESSAGE_URI "http: //example.org/set"
+#define SAMPLER_URI "http://lv2plug.in/plugins/eg-sampler"
+#define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
+#define FILENAME_URI SAMPLER_URI "#filename"
+#define ATOM_OBJECT_URI NS_ATOM "Object"
+#define SET_MESSAGE_URI "http: //example.org/set"