/*
- Copyright (C) 2008 Paul Davis
- Author: Dave Robillard
+ Copyright (C) 2008-2010 Paul Davis
+ Author: David Robillard
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <cmath>
#include <cstring>
+#include <glibmm.h>
+
#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/pathscanner.h"
#include "i18n.h"
#include <locale.h>
+#include "lv2ext/lv2_persist.h"
+
using namespace std;
using namespace ARDOUR;
using namespace PBD;
"http://lv2plug.in/ns/ext/event",
"http://lv2plug.in/ns/ext/midi#MidiEvent");
-LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, LV2World& world, SLV2Plugin plugin, nframes_t rate)
+LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, LV2World& world, SLV2Plugin plugin, framecnt_t rate)
: Plugin (e, session)
, _world(world)
, _features(NULL)
}
void
-LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate)
+LV2Plugin::init (LV2World& world, SLV2Plugin plugin, framecnt_t rate)
{
- _world = world;
- _plugin = plugin;
- _ui = NULL;
- _control_data = 0;
- _shadow_data = 0;
+ _world = world;
+ _plugin = plugin;
+ _ui = NULL;
+ _control_data = 0;
+ _shadow_data = 0;
_latency_control_port = 0;
- _was_activated = false;
-
+ _was_activated = false;
+
+ _instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access";
+ _data_access_feature.URI = "http://lv2plug.in/ns/ext/data-access";
+ _persist_feature.URI = "http://lv2plug.in/ns/ext/persist";
+ _persist_feature.data = NULL;
+
+ SLV2Value persist_uri = slv2_value_new_uri(_world.world, _persist_feature.URI);
+ _supports_persist = slv2_plugin_has_feature(plugin, persist_uri);
+ slv2_value_free(persist_uri);
+
+ _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 5);
+ _features[0] = &_instance_access_feature;
+ _features[1] = &_data_access_feature;
+ _features[2] = &_persist_feature;
+ _features[3] = _uri_map.feature();
+ _features[4] = NULL;
+
_instance = slv2_plugin_instantiate(plugin, rate, _features);
- _name = slv2_plugin_get_name(plugin);
- assert(_name);
- _author = slv2_plugin_get_author_name(plugin);
+ _name = slv2_plugin_get_name(plugin);
+ _author = slv2_plugin_get_author_name(plugin);
if (_instance == 0) {
error << _("LV2: Failed to instantiate plugin ") << slv2_plugin_get_uri(plugin) << endl;
throw failed_constructor();
}
+ _instance_access_feature.data = (void*)_instance->lv2_handle;
+ _data_access_extension_data.extension_data = _instance->lv2_descriptor->extension_data;
+ _data_access_feature.data = &_data_access_extension_data;
+
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
error << string_compose(
_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
slv2_value_free(_author);
throw failed_constructor();
}
-
- _instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access";
- _instance_access_feature.data = (void*)_instance->lv2_handle;
-
- _data_access_extension_data.extension_data = _instance->lv2_descriptor->extension_data;
- _data_access_feature.URI = "http://lv2plug.in/ns/ext/data-access";
- _data_access_feature.data = &_data_access_extension_data;
-
- _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 4);
- _features[0] = &_instance_access_feature;
- _features[1] = &_data_access_feature;
- _features[2] = _uri_map.feature();
- _features[3] = NULL;
_sample_rate = rate;
- const uint32_t num_ports = slv2_plugin_get_num_ports(plugin);
+ const bool latent = slv2_plugin_has_latency(plugin);
+ uint32_t latency_port = (latent ? slv2_plugin_get_latency_port_index(plugin) : 0);
+ const uint32_t num_ports = slv2_plugin_get_num_ports(plugin);
_control_data = new float[num_ports];
- _shadow_data = new float[num_ports];
- _defaults = new float[num_ports];
-
- const bool latent = slv2_plugin_has_latency(plugin);
- uint32_t latency_port = (latent ? slv2_plugin_get_latency_port_index(plugin) : 0);
+ _shadow_data = new float[num_ports];
+ _defaults = new float[num_ports];
for (uint32_t i = 0; i < num_ports; ++i) {
- SLV2Port port = slv2_plugin_get_port_by_index(plugin, i);
- SLV2Value sym = slv2_port_get_symbol(_plugin, port);
+ SLV2Port port = slv2_plugin_get_port_by_index(plugin, i);
+ SLV2Value sym = slv2_port_get_symbol(_plugin, port);
_port_indices.insert(std::make_pair(slv2_value_as_string(sym), i));
if (parameter_is_control(i)) {
SLV2Value def;
_defaults[i] = 0.0f;
}
}
-
+
SLV2UIs uis = slv2_plugin_get_uis(_plugin);
if (slv2_uis_size(uis) > 0) {
for (unsigned i=0; i < slv2_uis_size(uis); ++i) {
deactivate ();
cleanup ();
- GoingAway (); /* EMIT SIGNAL */
-
slv2_instance_free(_instance);
slv2_value_free(_name);
slv2_value_free(_author);
LV2Plugin::default_value (uint32_t port)
{
return _defaults[port];
-}
+}
const char*
LV2Plugin::port_symbol (uint32_t index)
{
if (which < slv2_plugin_get_num_ports(_plugin)) {
_shadow_data[which] = val;
-#if 0
ParameterChanged (which, val); /* EMIT SIGNAL */
+#if 0
if (which < parameter_count() && controls[which]) {
controls[which]->Changed ();
}
-#endif
-
+#endif
+
} else {
warning << string_compose (_("Illegal parameter number used with plugin \"%1\"."
- "This is a bug in either Ardour or the LV2 plugin (%2)"),
- name(), unique_id()) << endmsg;
+ "This is a bug in either %2 or the LV2 plugin (%3)"),
+ name(), PROGRAM_NAME, unique_id()) << endmsg;
}
}
}
}
}
-
+
return 0;
}
+struct LV2Value { void* value; uint32_t type; };
+typedef std::map< std::string, LV2Value > LV2State;
+
+static void
+lv2_persist_store_callback(void* callback_data,
+ const char* key,
+ const void* value,
+ size_t size,
+ uint32_t type)
+{
+ cout << "LV2 PERSIST STORE " << key << " = " << value << " :: " << type << endl;
+}
+
XMLNode&
LV2Plugin::get_state()
{
}
}
+ if (_supports_persist) {
+ // Create state directory for this plugin instance
+ const std::string state_path = Glib::build_filename(_session.plugins_dir(), _id.to_s());
+ cout << "LV2 plugin state path " << state_path << endl;
+
+ // Get LV2 Persist extension data from plugin instance
+ LV2_Persist* persist = (LV2_Persist*)slv2_instance_get_extension_data(
+ _instance, "http://lv2plug.in/ns/ext/persist");
+ if (!persist) {
+ warning << string_compose(
+ _("Plugin \"%1\% failed to return LV2 persist data"),
+ unique_id());
+ return *root; // FIXME: Possibly inconsistent state
+ }
+
+ LV2State state;
+ persist->save(_instance->lv2_handle, lv2_persist_store_callback, &state);
+ }
+
return *root;
}
}
bool
-LV2Plugin::load_preset(const string uri)
+LV2Plugin::load_preset(const string& uri)
{
const string query = string(
"PREFIX lv2p: <http://lv2plug.in/ns/dev/presets#>\n"
" ?port lv2:symbol ?sym ; lv2p:value ?val . }";
SLV2Results values = slv2_plugin_query_sparql(_plugin, query.c_str());
for (; !slv2_results_finished(values); slv2_results_next(values)) {
- SLV2Value sym = slv2_results_get_binding_value(values, 0);
+ SLV2Value sym = slv2_results_get_binding_value(values, 0);
SLV2Value val = slv2_results_get_binding_value(values, 1);
if (slv2_value_is_float(val)) {
uint32_t index = _port_indices[slv2_value_as_string(sym)];
{
return false;
}
-
+
bool
LV2Plugin::has_editor() const
{
}
int
-LV2Plugin::set_state(const XMLNode& node)
+LV2Plugin::set_state(const XMLNode& node, int version)
{
- XMLNodeList nodes;
- XMLProperty *prop;
+ XMLNodeList nodes;
+ XMLProperty* prop;
XMLNodeConstIterator iter;
- XMLNode *child;
- const char *sym;
- const char *value;
- uint32_t port_id;
- LocaleGuard lg (X_("POSIX"));
+ XMLNode* child;
+ const char* sym;
+ const char* value;
+ uint32_t port_id;
+ LocaleGuard lg(X_("POSIX"));
if (node.name() != state_node_name()) {
error << _("Bad node sent to LV2Plugin::set_state") << endmsg;
return -1;
}
- nodes = node.children ("Port");
-
+ if (version < 3000){
+ nodes = node.children ("port");
+ } else {
+ nodes = node.children ("Port");
+ }
+
for (iter = nodes.begin(); iter != nodes.end(); ++iter){
child = *iter;
}
map<string,uint32_t>::iterator i = _port_indices.find(sym);
+
if (i != _port_indices.end()) {
port_id = i->second;
} else {
set_parameter (port_id, atof(value));
}
-
+
latency_compute_run ();
return 0;
SLV2Value def, min, max;
slv2_port_get_range(_plugin, port, &def, &min, &max);
-
+
desc.integer_step = slv2_port_has_property(_plugin, port, _world.integer);
- desc.toggled = slv2_port_has_property(_plugin, port, _world.toggled);
- desc.logarithmic = slv2_port_has_property(_plugin, port, _world.logarithmic);
+ desc.toggled = slv2_port_has_property(_plugin, port, _world.toggled);
+ desc.logarithmic = slv2_port_has_property(_plugin, port, _world.logarithmic);
desc.sr_dependent = slv2_port_has_property(_plugin, port, _world.srate);
- desc.label = slv2_value_as_string(slv2_port_get_name(_plugin, port));
- desc.lower = min ? slv2_value_as_float(min) : 0.0f;
- desc.upper = max ? slv2_value_as_float(max) : 1.0f;
- desc.min_unbound = false; // TODO (LV2 extension)
- desc.max_unbound = false; // TODO (LV2 extension)
-
+ desc.label = slv2_value_as_string(slv2_port_get_name(_plugin, port));
+ desc.lower = min ? slv2_value_as_float(min) : 0.0f;
+ desc.upper = max ? slv2_value_as_float(max) : 1.0f;
+ desc.min_unbound = false; // TODO: LV2 extension required
+ desc.max_unbound = false; // TODO: LV2 extension required
+
if (desc.integer_step) {
- desc.step = 1.0;
+ desc.step = 1.0;
desc.smallstep = 0.1;
desc.largestep = 10.0;
} else {
const float delta = desc.upper - desc.lower;
- desc.step = delta / 1000.0f;
+ desc.step = delta / 1000.0f;
desc.smallstep = delta / 10000.0f;
desc.largestep = delta/10.0f;
}
{
if (which.type() == PluginAutomation && which.id() < parameter_count()) {
SLV2Value name = slv2_port_get_name(_plugin,
- slv2_plugin_get_port_by_index(_plugin, which));
+ slv2_plugin_get_port_by_index(_plugin, which.id()));
string ret(slv2_value_as_string(name));
slv2_value_free(name);
return ret;
}
}
-nframes_t
+framecnt_t
LV2Plugin::signal_latency () const
{
if (_latency_control_port) {
- return (nframes_t) floor (*_latency_control_port);
+ return (framecnt_t) floor (*_latency_control_port);
} else {
return 0;
}
int
LV2Plugin::connect_and_run (BufferSet& bufs,
ChanMapping in_map, ChanMapping out_map,
- nframes_t nframes, nframes_t offset)
+ pframes_t nframes, framecnt_t offset)
{
cycles_t then = get_cycles ();
slv2_instance_connect_port(_instance, port_index, NULL);
}
}
-
+
run (nframes);
-
+
midi_out_index = 0;
for (uint32_t port_index = 0; port_index < parameter_count(); ++port_index) {
if (parameter_is_midi(port_index) && parameter_is_output(port_index)) {
bufs.flush_lv2_midi(true, buf_index);
}
}
-
+
cycles_t now = get_cycles ();
set_cycles ((uint32_t) (now - then));
}
void
-LV2Plugin::run (nframes_t nframes)
+LV2Plugin::run (pframes_t nframes)
{
for (uint32_t i = 0; i < parameter_count(); ++i) {
if (parameter_is_control(i) && parameter_is_input(i)) {
/* we need to run the plugin so that it can set its latency
parameter.
*/
-
+
activate ();
-
+
uint32_t port_index = 0;
- uint32_t in_index = 0;
- uint32_t out_index = 0;
- const nframes_t bufsize = 1024;
+ uint32_t in_index = 0;
+ uint32_t out_index = 0;
+
+ const framecnt_t bufsize = 1024;
float buffer[bufsize];
- memset(buffer,0,sizeof(float)*bufsize);
-
- /* Note that we've already required that plugins
- be able to handle in-place processing.
- */
-
+ memset(buffer, 0, sizeof(float) * bufsize);
+
+ // FIXME: Ensure plugins can handle in-place processing
+
port_index = 0;
-
+
while (port_index < parameter_count()) {
if (parameter_is_audio (port_index)) {
if (parameter_is_input (port_index)) {
}
port_index++;
}
-
+
run (bufsize);
deactivate ();
}
: world(slv2_world_new())
{
slv2_world_load_all(world);
- input_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_INPUT);
- output_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_OUTPUT);
- control_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_CONTROL);
- audio_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_AUDIO);
- event_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_EVENT);
- midi_class = slv2_value_new_uri(world, SLV2_EVENT_CLASS_MIDI);
+ input_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_INPUT);
+ output_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_OUTPUT);
+ control_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_CONTROL);
+ audio_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_AUDIO);
+ event_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_EVENT);
+ midi_class = slv2_value_new_uri(world, SLV2_EVENT_CLASS_MIDI);
in_place_broken = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "inPlaceBroken");
- integer = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "integer");
- toggled = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "toggled");
- srate = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "sampleRate");
- gtk_gui = slv2_value_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI");
- external_gui = slv2_value_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external");
- logarithmic = slv2_value_new_uri(world, "http://lv2plug.in/ns/dev/extportinfo#logarithmic");
+ integer = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "integer");
+ toggled = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "toggled");
+ srate = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "sampleRate");
+ gtk_gui = slv2_value_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI");
+ external_gui = slv2_value_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external");
+ logarithmic = slv2_value_new_uri(world, "http://lv2plug.in/ns/dev/extportinfo#logarithmic");
}
LV2World::~LV2World()
: _lv2_world(lv2_world)
, _slv2_plugin(slv2_plugin)
{
+ type = ARDOUR::LV2;
}
LV2PluginInfo::~LV2PluginInfo()
catch (failed_constructor &err) {
return PluginPtr ((Plugin*) 0);
- }
-
+ }
+
return PluginPtr();
}
-PluginInfoList
+PluginInfoList*
LV2PluginInfo::discover (void* lv2_world)
{
- PluginInfoList plugs;
-
- LV2World* world = (LV2World*)lv2_world;
- SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
+ PluginInfoList* plugs = new PluginInfoList;
+ LV2World* world = (LV2World*)lv2_world;
+ SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
- cerr << "LV2: Discovered " << slv2_plugins_size (plugins) << " plugins\n";
+ cerr << "LV2: Discovering " << slv2_plugins_size (plugins) << " plugins" << endl;
for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
SLV2Plugin p = slv2_plugins_get_at(plugins, i);
cerr << "LV2: invalid plugin\n";
continue;
}
-
+
+ info->type = LV2;
+
info->name = string(slv2_value_as_string(name));
slv2_value_free(name);
world->input_class, world->audio_class, NULL));
info->n_inputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
world->input_class, world->event_class, NULL));
-
+
info->n_outputs.set_audio(slv2_plugin_get_num_ports_of_class(p,
world->output_class, world->audio_class, NULL));
info->n_outputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
info->unique_id = slv2_value_as_uri(slv2_plugin_get_uri(p));
info->index = 0; // Meaningless for LV2
-
- plugs.push_back (info);
+
+ plugs->push_back (info);
}
+ cerr << "Done LV2 discovery" << endl;
+
return plugs;
}