aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-07-07 23:11:33 +0000
committerDavid Robillard <d@drobilla.net>2011-07-07 23:11:33 +0000
commit273d983e26e326513cb52c925eb15cb247c22560 (patch)
treeb05aa1193141caa334be5fa56045d5841db07bae
parentcf303b78414279edb2b0cae6c95471260039e806 (diff)
downloadlv2-273d983e26e326513cb52c925eb15cb247c22560.tar.xz
Add stub LV2 persist support to sampler plugin.
-rw-r--r--plugins/eg-amp.lv2/amp.c2
-rw-r--r--plugins/eg-sampler.lv2/sampler.c104
-rw-r--r--plugins/eg-sampler.lv2/sampler.ttl3
-rw-r--r--plugins/eg-sampler.lv2/wscript3
4 files changed, 86 insertions, 26 deletions
diff --git a/plugins/eg-amp.lv2/amp.c b/plugins/eg-amp.lv2/amp.c
index 3fca0c0..d5e6bea 100644
--- a/plugins/eg-amp.lv2/amp.c
+++ b/plugins/eg-amp.lv2/amp.c
@@ -102,7 +102,7 @@ cleanup(LV2_Handle instance)
}
const void*
-extension_data(const char * uri)
+extension_data(const char* uri)
{
return NULL;
}
diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c
index 173f844..dd0b5f7 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 Gabriel M. Beddingfield <gabriel@teuton.org>,
- James Morris <jwm.art.net@gmail.com>,
- David Robillard <d@drobilla.net>
+ James Morris <jwm.art.net@gmail.com>,
+ 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
@@ -19,11 +19,11 @@
/**
@file sampler.c Sampler Plugin
-
+
A simple example of an LV2 sampler that dynamically loads samples (based on
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()
@@ -44,9 +44,13 @@
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
#include "lv2/lv2plug.in/ns/ext/event/event-helpers.h"
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
+#include "lv2/lv2plug.in/ns/ext/persist/persist.h"
+
+#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
#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 STRING_BUF 8192
enum {
@@ -63,6 +67,9 @@ typedef struct {
} SampleFile;
typedef struct {
+ /* Features */
+ LV2_URI_Map_Feature* uri_map;
+
/* Sample */
SampleFile* samp;
SampleFile* pending_samp;
@@ -91,8 +98,8 @@ handle_load_sample(Sampler* plugin)
SF_INFO* const info = &plugin->pending_samp->info;
SNDFILE* const sample = sf_open(plugin->pending_samp->filepath,
- SFM_READ,
- info);
+ SFM_READ,
+ info);
if (!sample
|| !info->frames
@@ -124,9 +131,7 @@ handle_load_sample(Sampler* plugin)
void*
worker_thread_main(void* arg)
{
- Sampler* plugin;
-
- plugin = (Sampler*)arg;
+ Sampler* plugin = (Sampler*)arg;
pthread_mutex_lock(&plugin->pending_samp_mutex);
while (true) {
@@ -134,7 +139,7 @@ worker_thread_main(void* arg)
pthread_cond_wait(&plugin->pending_samp_cond,
&plugin->pending_samp_mutex);
- /* Then load it */
+ /* Then load it */
handle_load_sample(plugin);
}
pthread_mutex_unlock(&plugin->pending_samp_mutex);
@@ -168,7 +173,7 @@ connect_port(LV2_Handle instance,
plugin->eventPort = (LV2_Event_Buffer*)data;
break;
case SAMPLER_OUT:
- plugin->outputPort = (float*)data;
+ plugin->outputPort = (float*)data;
break;
default:
break;
@@ -212,12 +217,10 @@ instantiate(const LV2_Descriptor* descriptor,
/* Scan host features for event and uri-map */
for (int i = 0; features[i]; ++i) {
if (strcmp(features[i]->URI, LV2_URI_MAP_URI) == 0) {
- LV2_URI_Map_Feature*
- map_feature = (LV2_URI_Map_Feature*)features[i]->data;
-
- plugin->midi_event_id
- = map_feature->uri_to_id(map_feature->callback_data,
- LV2_EVENT_URI, MIDI_EVENT_URI);
+ plugin->uri_map = (LV2_URI_Map_Feature*)features[i]->data;
+ plugin->midi_event_id = plugin->uri_map->uri_to_id(
+ plugin->uri_map->callback_data,
+ LV2_EVENT_URI, MIDI_EVENT_URI);
} else if (strcmp(features[i]->URI, LV2_EVENT_URI) == 0) {
plugin->event_ref = (LV2_Event_Feature*)features[i]->data;
}
@@ -256,16 +259,16 @@ run(LV2_Handle instance,
/* Read incoming events */
LV2_Event_Iterator iterator;
- for (lv2_event_begin(&iterator, plugin->eventPort);
- lv2_event_is_valid(&iterator);
- lv2_event_increment(&iterator)) {
-
+ for (lv2_event_begin(&iterator, plugin->eventPort);
+ lv2_event_is_valid(&iterator);
+ lv2_event_increment(&iterator)) {
+
ev = lv2_event_get(&iterator, NULL);
if (ev->type == 0) {
if (plugin->event_ref) {
plugin->event_ref->lv2_event_unref(
- plugin->event_ref->callback_data, ev);
+ plugin->event_ref->callback_data, ev);
}
} else if (ev->type == plugin->midi_event_id) {
uint8_t* const data = (uint8_t* const)(ev + 1);
@@ -331,6 +334,59 @@ run(LV2_Handle instance,
}
}
+static uint32_t
+uri_to_id(Sampler* plugin, const char* uri)
+{
+ return plugin->uri_map->uri_to_id(plugin->uri_map->callback_data,
+ NULL,
+ uri);
+}
+
+static void
+save(LV2_Handle instance,
+ LV2_Persist_Store_Function store,
+ void* callback_data)
+{
+ Sampler* plugin = (Sampler*)instance;
+ store(callback_data,
+ uri_to_id(plugin, FILENAME_URI),
+ plugin->samp->filepath,
+ strlen(plugin->samp->filepath) + 1,
+ uri_to_id(plugin, NS_ATOM "String"),
+ LV2_PERSIST_IS_POD | LV2_PERSIST_IS_PORTABLE);
+}
+
+static void
+restore(LV2_Handle instance,
+ LV2_Persist_Retrieve_Function retrieve,
+ void* callback_data)
+{
+ Sampler* plugin = (Sampler*)instance;
+
+ size_t size;
+ uint32_t type;
+ uint32_t flags;
+
+ const void* value = retrieve(
+ callback_data,
+ uri_to_id(plugin, FILENAME_URI),
+ &size, &type, &flags);
+
+ if (value) {
+ printf("Restored filename %s\n", (const char*)value);
+ }
+}
+
+const void*
+extension_data(const char* uri)
+{
+ static const LV2_Persist persist = { save, restore };
+ if (!strcmp(uri, LV2_PERSIST_URI)) {
+ return &persist;
+ }
+ return NULL;
+}
+
static const LV2_Descriptor descriptor = {
SAMPLER_URI,
instantiate,
@@ -339,13 +395,13 @@ static const LV2_Descriptor descriptor = {
run,
NULL, // deactivate,
cleanup,
- NULL, // extension_data
+ extension_data
};
LV2_SYMBOL_EXPORT
const LV2_Descriptor* lv2_descriptor(uint32_t index)
{
- switch (index) {
+ switch (index) {
case 0:
return &descriptor;
default:
diff --git a/plugins/eg-sampler.lv2/sampler.ttl b/plugins/eg-sampler.lv2/sampler.ttl
index 1926652..e944d0a 100644
--- a/plugins/eg-sampler.lv2/sampler.ttl
+++ b/plugins/eg-sampler.lv2/sampler.ttl
@@ -26,7 +26,8 @@
doap:license <http://opensource.org/licenses/isc-license> ;
lv2:requiredFeature <http://lv2plug.in/ns/ext/uri-map> ;
lv2:optionalFeature lv2:hardRtCapable ,
- <http://lv2plug.in/ns/ext/event> ;
+ <http://lv2plug.in/ns/ext/event> ,
+ <http://lv2plug.in/ns/ext/persist> ;
lv2:port [
a lv2:InputPort ,
lv2ev:EventPort ;
diff --git a/plugins/eg-sampler.lv2/wscript b/plugins/eg-sampler.lv2/wscript
index 2957ce1..a4b6535 100644
--- a/plugins/eg-sampler.lv2/wscript
+++ b/plugins/eg-sampler.lv2/wscript
@@ -24,6 +24,9 @@ def configure(conf):
conf.load('compiler_c')
autowaf.check_header(conf, 'c', 'lv2/lv2plug.in/ns/lv2core/lv2.h')
+ autowaf.check_header(conf, 'c', 'lv2/lv2plug.in/ns/ext/event/event-helpers.h')
+ autowaf.check_header(conf, 'c', 'lv2/lv2plug.in/ns/ext/uri-map/uri-map.h')
+ autowaf.check_header(conf, 'c', 'lv2/lv2plug.in/ns/ext/persist/persist.h')
autowaf.check_pkg(conf, 'sndfile', uselib_store='SNDFILE',
atleast_version='1.0.0', mandatory=True)