summaryrefslogtreecommitdiff
path: root/libs/ardour/lv2_plugin.cc
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-04-05 00:15:54 +0000
committerDavid Robillard <d@drobilla.net>2012-04-05 00:15:54 +0000
commit338e83d9dc2aca8ced4358df7dae13e11a5c71a7 (patch)
treec58e6d936fe1fff99c962edecebd28b047f375b2 /libs/ardour/lv2_plugin.cc
parentdaad719546d96bfe9ce7e8e1b7fc8f66c4189b71 (diff)
Implement LV2 worker extension.
This is done by way of a generic Worker object/thread, which currently just applies to one LV2 plugin, but the idea is to share one thread and set of buffers among many plugins. The same pattern may also be useful elsewhere in Ardour. The responding part gets a bit tricker when sharing a worker between plugins, it's not a blocker, and I'm lazy, sooo here's this. This commit also adds a new portable in-process semaphore to PBD. The existing one is pretty weird and uses a named semaphore on OSX for reasons unknown to me. Perhaps as a quick fix to avoid POSIX semaphores being utterly broken on OSX? It would probably be a good idea to replace that with this new one, which uses Mach kernel semaphores on OSX which work well, though I am not sure how pedantically real-time safe they are to signal. git-svn-id: svn://localhost/ardour2/branches/3.0@11790 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/lv2_plugin.cc')
-rw-r--r--libs/ardour/lv2_plugin.cc84
1 files changed, 76 insertions, 8 deletions
diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc
index 91dd1578fb..556b8d4357 100644
--- a/libs/ardour/lv2_plugin.cc
+++ b/libs/ardour/lv2_plugin.cc
@@ -43,6 +43,7 @@
#include "ardour/debug.h"
#include "ardour/lv2_plugin.h"
#include "ardour/session.h"
+#include "ardour/worker.h"
#include "i18n.h"
#include <locale.h>
@@ -51,6 +52,7 @@
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/ext/state/state.h"
+#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
#include "lv2_evbuf.h"
@@ -113,20 +115,45 @@ public:
static LV2World _world;
+/** Called by the plugin to schedule non-RT work. */
+static LV2_Worker_Status
+work_schedule(LV2_Worker_Schedule_Handle handle,
+ uint32_t size,
+ const void* data)
+{
+ Worker* worker = (Worker*)handle;
+ return worker->schedule(size, data) ?
+ LV2_WORKER_SUCCESS : LV2_WORKER_ERR_UNKNOWN;
+}
+
+/** Called by the plugin to respond to non-RT work. */
+static LV2_Worker_Status
+work_respond(LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data)
+{
+ Worker* worker = (Worker*)handle;
+ return worker->respond(size, data) ?
+ LV2_WORKER_SUCCESS : LV2_WORKER_ERR_UNKNOWN;
+}
+
struct LV2Plugin::Impl {
Impl() : plugin(0), ui(0), ui_type(0), name(0), author(0), instance(0)
+ , worker(0), work_iface(0)
#ifdef HAVE_NEW_LILV
, state(0)
#endif
{}
- LilvPlugin* plugin;
- const LilvUI* ui;
- const LilvNode* ui_type;
- LilvNode* name;
- LilvNode* author;
- LilvInstance* instance;
+ LilvPlugin* plugin;
+ const LilvUI* ui;
+ const LilvNode* ui_type;
+ LilvNode* name;
+ LilvNode* author;
+ LilvInstance* instance;
+ Worker* worker;
+ LV2_Worker_Interface* work_iface;
#ifdef HAVE_NEW_LILV
- LilvState* state;
+ LilvState* state;
#endif
};
@@ -177,6 +204,7 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
_instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access";
_data_access_feature.URI = "http://lv2plug.in/ns/ext/data-access";
_make_path_feature.URI = LV2_STATE__makePath;
+ _work_schedule_feature.URI = LV2_WORKER__schedule;
LilvPlugin* plugin = _impl->plugin;
@@ -192,7 +220,7 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
lilv_node_free(state_iface_uri);
#endif
- _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 7);
+ _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 8);
_features[0] = &_instance_access_feature;
_features[1] = &_data_access_feature;
_features[2] = &_make_path_feature;
@@ -200,6 +228,7 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
_features[4] = _uri_map.urid_map_feature();
_features[5] = _uri_map.urid_unmap_feature();
_features[6] = NULL;
+ _features[7] = NULL;
LV2_State_Make_Path* make_path = (LV2_State_Make_Path*)malloc(
sizeof(LV2_State_Make_Path));
@@ -207,6 +236,18 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
make_path->path = &lv2_state_make_path;
_make_path_feature.data = make_path;
+ LilvNode* worker_schedule = lilv_new_uri(_world.world, LV2_WORKER__schedule);
+ if (lilv_plugin_has_feature(plugin, worker_schedule)) {
+ LV2_Worker_Schedule* schedule = (LV2_Worker_Schedule*)malloc(
+ sizeof(LV2_Worker_Schedule));
+ _impl->worker = new Worker(this, 4096);
+ schedule->handle = _impl->worker;
+ schedule->schedule_work = work_schedule;
+ _work_schedule_feature.data = schedule;
+ _features[6] = &_work_schedule_feature;
+ }
+ lilv_node_free(worker_schedule);
+
_impl->instance = lilv_plugin_instantiate(plugin, rate, _features);
_impl->name = lilv_plugin_get_name(plugin);
_impl->author = lilv_plugin_get_author_name(plugin);
@@ -220,6 +261,8 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
_data_access_extension_data.extension_data = _impl->instance->lv2_descriptor->extension_data;
_data_access_feature.data = &_data_access_extension_data;
+ _impl->work_iface = (LV2_Worker_Interface*)extension_data(LV2_WORKER__interface);
+
if (lilv_plugin_has_feature(plugin, _world.lv2_inPlaceBroken)) {
error << string_compose(
_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
@@ -369,6 +412,10 @@ LV2Plugin::~LV2Plugin ()
lilv_node_free(_impl->name);
lilv_node_free(_impl->author);
+ free(_features);
+ free(_make_path_feature.data);
+ free(_work_schedule_feature.data);
+
delete _to_ui;
delete _from_ui;
@@ -850,6 +897,7 @@ LV2Plugin::write_to_ui(uint32_t index,
uint32_t size,
uint8_t* body)
{
+ std::cerr << "WRITE TO UI" << std::endl;
write_to(_to_ui, index, protocol, size, body);
}
@@ -888,6 +936,19 @@ LV2Plugin::emit_to_ui(void* controller, UIMessageSink sink)
}
void
+LV2Plugin::work(uint32_t size, const void* data)
+{
+ _impl->work_iface->work(
+ _impl->instance->lv2_handle, work_respond, _impl->worker, size, data);
+}
+
+void
+LV2Plugin::work_response(uint32_t size, const void* data)
+{
+ _impl->work_iface->work_response(_impl->instance->lv2_handle, size, data);
+}
+
+void
LV2Plugin::set_insert_info(const PluginInsert* insert)
{
_insert_id = insert->id();
@@ -1297,6 +1358,13 @@ LV2Plugin::run(pframes_t nframes)
}
lilv_instance_run(_impl->instance, nframes);
+
+ if (_impl->work_iface) {
+ _impl->worker->emit_responses();
+ if (_impl->work_iface->end_run) {
+ _impl->work_iface->end_run(_impl->instance->lv2_handle);
+ }
+ }
}
void