/*
- Copyright (C) 2008 Paul Davis
+ Copyright (C) 2008 Paul Davis
Author: Dave Robillard
This program is free software; you can redistribute it and/or modify
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "ardour/audio_buffer.h"
+#include "ardour/lv2_event_buffer.h"
#include "ardour/lv2_plugin.h"
#include "pbd/stl_delete.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
-
+
+URIMap LV2Plugin::_uri_map;
+uint32_t LV2Plugin::_midi_event_type = _uri_map.uri_to_id(
+ "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)
: Plugin (e, session)
, _world(world)
_shadow_data = 0;
_latency_control_port = 0;
_was_activated = false;
-
+
_instance = slv2_plugin_instantiate(plugin, rate, _features);
_name = slv2_plugin_get_name(plugin);
assert(_name);
}
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
- error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
+ error << string_compose(
+ _("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
slv2_value_as_string(_name));
slv2_value_free(_name);
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*) * 3);
+
+ _features = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * 4);
_features[0] = &_instance_access_feature;
_features[1] = &_data_access_feature;
- _features[2] = NULL;
+ _features[2] = _uri_map.feature();
+ _features[3] = NULL;
_sample_rate = rate;
_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) {
break;
}
}
+
+ // if gtk gui is not available, try to find external gui
+ if (!_ui) {
+ for (unsigned i=0; i < slv2_uis_size(uis); ++i) {
+ SLV2UI ui = slv2_uis_get_at(uis, i);
+ if (slv2_ui_is_a(ui, _world.external_gui)) {
+ _ui = ui;
+ break;
+ }
+ }
+ }
}
latency_compute_run ();
cleanup ();
GoingAway (); /* EMIT SIGNAL */
-
+
slv2_instance_free(_instance);
slv2_value_free(_name);
slv2_value_free(_author);
delete [] _shadow_data;
}
+bool
+LV2Plugin::is_external_ui() const
+{
+ return slv2_ui_is_a(_ui, _world.external_gui);
+}
+
string
LV2Plugin::unique_id() const
{
LV2Plugin::default_value (uint32_t port)
{
return _defaults[port];
-}
+}
const char*
LV2Plugin::port_symbol (uint32_t index)
controls[which]->Changed ();
}
#endif
-
+
} else {
warning << string_compose (_("Illegal parameter number used with plugin \"%1\"."
"This is a bug in either Ardour or the LV2 plugin (%2)"),
}
}
}
-
+
return 0;
}
if (parameter_is_input(i) && parameter_is_control(i)) {
child = new XMLNode("Port");
- snprintf(buf, sizeof(buf), "%u", i);
- child->add_property("number", string(buf));
+ /*snprintf(buf, sizeof(buf), "%u", i);
+ child->add_property("number", string(buf));*/
child->add_property("symbol", port_symbol(i));
snprintf(buf, sizeof(buf), "%+f", _shadow_data[i]);
child->add_property("value", string(buf));
}
bool
-LV2Plugin::save_preset (string name)
+LV2Plugin::save_preset (string /*name*/)
{
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;
XMLNodeConstIterator iter;
XMLNode *child;
- const char *port;
- const char *data;
+ const char *sym;
+ const char *value;
uint32_t port_id;
LocaleGuard lg (X_("POSIX"));
nodes = node.children ("Port");
- for(iter = nodes.begin(); iter != nodes.end(); ++iter){
+ for (iter = nodes.begin(); iter != nodes.end(); ++iter){
child = *iter;
- if ((prop = child->property("number")) != 0) {
- port = prop->value().c_str();
+ if ((prop = child->property("symbol")) != 0) {
+ sym = prop->value().c_str();
+ } else {
+ warning << _("LV2: port has no symbol, ignored") << endmsg;
+ continue;
+ }
+
+ map<string,uint32_t>::iterator i = _port_indices.find(sym);
+ if (i != _port_indices.end()) {
+ port_id = i->second;
} else {
- warning << _("LV2: no lv2 port number") << endmsg;
+ warning << _("LV2: port has unknown index, ignored") << endmsg;
continue;
}
if ((prop = child->property("value")) != 0) {
- data = prop->value().c_str();
+ value = prop->value().c_str();
} else {
- warning << _("LV2: no lv2 port data") << endmsg;
+ warning << _("LV2: port has no value, ignored") << endmsg;
continue;
}
- sscanf (port, "%" PRIu32, &port_id);
- set_parameter (port_id, atof(data));
+ 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 = false; // TODO (LV2 extension)
+ 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)
-
+
if (desc.integer_step) {
desc.step = 1.0;
desc.smallstep = 0.1;
}
int
-LV2Plugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_index, nframes_t nframes, nframes_t offset)
+LV2Plugin::connect_and_run (BufferSet& bufs,
+ ChanMapping in_map, ChanMapping out_map,
+ nframes_t nframes, nframes_t offset)
{
- uint32_t port_index;
- cycles_t then, now;
+ cycles_t then = get_cycles ();
- port_index = 0;
-
- then = get_cycles ();
-
- const uint32_t nbufs = bufs.count().n_audio();
-
- while (port_index < parameter_count()) {
+ uint32_t audio_in_index = 0;
+ uint32_t audio_out_index = 0;
+ uint32_t midi_in_index = 0;
+ uint32_t midi_out_index = 0;
+ for (uint32_t port_index = 0; port_index < parameter_count(); ++port_index) {
if (parameter_is_audio(port_index)) {
if (parameter_is_input(port_index)) {
- const size_t index = min(in_index, nbufs - 1);
+ const uint32_t buf_index = in_map.get(DataType::AUDIO, audio_in_index++);
+ //cerr << port_index << " : " << " AUDIO IN " << buf_index << endl;
slv2_instance_connect_port(_instance, port_index,
- bufs.get_audio(index).data(offset));
- in_index++;
+ bufs.get_audio(buf_index).data(offset));
} else if (parameter_is_output(port_index)) {
- const size_t index = min(out_index,nbufs - 1);
+ const uint32_t buf_index = out_map.get(DataType::AUDIO, audio_out_index++);
+ //cerr << port_index << " : " << " AUDIO OUT " << buf_index << endl;
slv2_instance_connect_port(_instance, port_index,
- bufs.get_audio(index).data(offset));
- out_index++;
+ bufs.get_audio(buf_index).data(offset));
}
} else if (parameter_is_midi(port_index)) {
- // FIXME: Switch MIDI buffer format to LV2 event buffer
if (parameter_is_input(port_index)) {
- //const size_t index = min(in_index, nbufs - 1);
- //slv2_instance_connect_port(_instance, port_index,
- // bufs.get_midi(index).data(offset));
- // FIXME: hope it's connection optional...
- slv2_instance_connect_port(_instance, port_index, NULL);
- in_index++;
+ const uint32_t buf_index = in_map.get(DataType::MIDI, midi_in_index++);
+ //cerr << port_index << " : " << " MIDI IN " << buf_index << endl;
+ slv2_instance_connect_port(_instance, port_index,
+ bufs.get_lv2_midi(true, buf_index).data());
} else if (parameter_is_output(port_index)) {
- //const size_t index = min(out_index,nbufs - 1);
- //slv2_instance_connect_port(_instance, port_index,
-ss // bufs.get_midi(index).data(offset));
- // FIXME: hope it's connection optional...
- slv2_instance_connect_port(_instance, port_index, NULL);
- out_index++;
+ const uint32_t buf_index = out_map.get(DataType::MIDI, midi_out_index++);
+ //cerr << port_index << " : " << " MIDI OUT " << buf_index << endl;
+ slv2_instance_connect_port(_instance, port_index,
+ bufs.get_lv2_midi(false, buf_index).data());
}
+ } else if (!parameter_is_control(port_index)) {
+ // Optional port (it'd better be if we've made it this far...)
+ slv2_instance_connect_port(_instance, port_index, NULL);
}
- port_index++;
}
-
+
run (nframes);
- now = get_cycles ();
+
+ 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)) {
+ const uint32_t buf_index = out_map.get(DataType::MIDI, midi_out_index++);
+ bufs.flush_lv2_midi(true, buf_index);
+ }
+ }
+
+ cycles_t now = get_cycles ();
set_cycles ((uint32_t) (now - then));
return 0;
LV2Plugin::parameter_is_midi (uint32_t param) const
{
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
- return slv2_port_is_a(_plugin, port, _world.event_class)
- && slv2_port_supports_event(_plugin, port, _world.midi_class);
+ return slv2_port_is_a(_plugin, port, _world.event_class);
+ // && slv2_port_supports_event(_plugin, port, _world.midi_class);
}
bool
/* 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;
float buffer[bufsize];
memset(buffer,0,sizeof(float)*bufsize);
-
+
/* Note that we've already required that plugins
be able to 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 ();
}
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()
catch (failed_constructor &err) {
return PluginPtr ((Plugin*) 0);
- }
-
+ }
+
return PluginPtr();
}
-PluginInfoList
+PluginInfoList*
LV2PluginInfo::discover (void* lv2_world)
{
- PluginInfoList plugs;
-
+ PluginInfoList* plugs = new PluginInfoList;
+
LV2World* world = (LV2World*)lv2_world;
SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
+ 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);
LV2PluginInfoPtr info (new LV2PluginInfo(lv2_world, p));
SLV2Value name = slv2_plugin_get_name(p);
+
+ if (!name) {
+ cerr << "LV2: invalid plugin\n";
+ continue;
+ }
+
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;
}