diff options
author | David Robillard <d@drobilla.net> | 2012-04-05 00:15:54 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-04-05 00:15:54 +0000 |
commit | 338e83d9dc2aca8ced4358df7dae13e11a5c71a7 (patch) | |
tree | c58e6d936fe1fff99c962edecebd28b047f375b2 /libs/ardour/lv2_plugin.cc | |
parent | daad719546d96bfe9ce7e8e1b7fc8f66c4189b71 (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.cc | 84 |
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 |