#include <cstring>
#include <glib/gstdio.h>
-#include <giomm/file.h>
#include <glib/gprintf.h>
#include <glibmm.h>
#include <boost/utility.hpp>
-#include "pbd/pathscanner.h"
+#include "pbd/file_utils.h"
+#include "pbd/stl_delete.h"
#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/xml++.h"
#include "ardour/types.h"
#include "ardour/utils.h"
#include "ardour/worker.h"
-#include "ardour/lv2_bundled_search_path.h"
+#include "ardour/search_paths.h"
#include "i18n.h"
#include <locale.h>
#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
-#ifdef HAVE_NEW_LV2
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
+#ifdef HAVE_LV2_1_2_0
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
#include "lv2/lv2plug.in/ns/ext/options/options.h"
#endif
#include <suil/suil.h>
#endif
+// Compatibility for lv2-1.0.0
+#ifndef LV2_ATOM_CONTENTS_CONST
+#define LV2_ATOM_CONTENTS_CONST(type, atom) \
+ ((const void*)((const uint8_t*)(atom) + sizeof(type)))
+#endif
+#ifndef LV2_ATOM_BODY_CONST
+#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
+#endif
+
/** The number of MIDI buffers that will fit in a UI/worker comm buffer.
This needs to be roughly the number of cycles the UI will get around to
actually processing the traffic. Lower values are flakier but save memory.
_uri_map.uri_to_id(LV2_ATOM__Path),
_uri_map.uri_to_id(LV2_ATOM__Sequence),
_uri_map.uri_to_id(LV2_ATOM__eventTransfer),
+ _uri_map.uri_to_id(LV2_ATOM__URID),
+ _uri_map.uri_to_id(LV2_ATOM__Blank),
+ _uri_map.uri_to_id(LV2_ATOM__Object),
_uri_map.uri_to_id(LV2_LOG__Error),
_uri_map.uri_to_id(LV2_LOG__Note),
_uri_map.uri_to_id(LV2_LOG__Warning),
_uri_map.uri_to_id(LV2_TIME__beatsPerBar),
_uri_map.uri_to_id(LV2_TIME__beatsPerMinute),
_uri_map.uri_to_id(LV2_TIME__frame),
- _uri_map.uri_to_id(LV2_TIME__speed)
+ _uri_map.uri_to_id(LV2_TIME__speed),
+ _uri_map.uri_to_id(LV2_PATCH__Get),
+ _uri_map.uri_to_id(LV2_PATCH__Set),
+ _uri_map.uri_to_id(LV2_PATCH__property),
+ _uri_map.uri_to_id(LV2_PATCH__value)
};
class LV2World : boost::noncopyable {
LV2World ();
~LV2World ();
- void load_bundled_plugins();
+ void load_bundled_plugins(bool verbose=false);
LilvWorld* world;
LilvNode* lv2_toggled;
LilvNode* midi_MidiEvent;
LilvNode* rdfs_comment;
+ LilvNode* rdfs_label;
+ LilvNode* rdfs_range;
LilvNode* rsz_minimumSize;
LilvNode* time_Position;
LilvNode* ui_GtkUI;
LilvNode* ui_externalkx;
LilvNode* units_unit;
LilvNode* units_midiNote;
+ LilvNode* patch_writable;
+ LilvNode* patch_Message;
private:
bool _bundle_checked;
const LV2_Worker_Interface* work_iface;
LilvState* state;
LV2_Atom_Forge forge;
+ LV2_Atom_Forge ui_forge;
};
LV2Plugin::LV2Plugin (AudioEngine& engine,
, _features(NULL)
, _worker(NULL)
, _insert_id("0")
+ , _patch_port_in_index((uint32_t)-1)
+ , _patch_port_out_index((uint32_t)-1)
{
init(c_plugin, rate);
}
, _features(NULL)
, _worker(NULL)
, _insert_id(other._insert_id)
+ , _patch_port_in_index((uint32_t)-1)
+ , _patch_port_out_index((uint32_t)-1)
{
init(other._impl->plugin, other._sample_rate);
_features[6] = &_log_feature;
unsigned n_features = 7;
-#ifdef HAVE_NEW_LV2
+#ifdef HAVE_LV2_1_2_0
_features[n_features++] = &_def_state_feature;
#endif
lv2_atom_forge_init(&_impl->forge, _uri_map.urid_map());
+ lv2_atom_forge_init(&_impl->ui_forge, _uri_map.urid_map());
-#ifdef HAVE_NEW_LV2
+#ifdef HAVE_LV2_1_2_0
LV2_URID atom_Int = _uri_map.uri_to_id(LV2_ATOM__Int);
LV2_Options_Option options[] = {
{ LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id(LV2_BUF_SIZE__minBlockLength),
throw failed_constructor();
}
-#ifdef HAVE_NEW_LILV
+#ifdef HAVE_LILV_0_16_0
// Load default state
LilvState* state = lilv_state_new_from_world(
_world.world, _uri_map.urid_map(), lilv_plugin_get_uri(_impl->plugin));
if (lilv_nodes_contains(atom_supports, _world.time_Position)) {
flags |= PORT_POSITION;
}
+ if (lilv_nodes_contains(atom_supports, _world.patch_Message)) {
+ flags |= PORT_PATCHMSG;
+ if (flags & PORT_INPUT) {
+ _patch_port_in_index = i;
+ } else {
+ _patch_port_out_index = i;
+ }
+ }
}
LilvNodes* min_size_v = lilv_port_get_value(_impl->plugin, port, _world.rsz_minimumSize);
LilvNode* min_size = min_size_v ? lilv_nodes_get_first(min_size_v) : NULL;
return g_strndup(abs_path.c_str(), abs_path.length());
}
-static void
-remove_directory(const std::string& path)
-{
- if (!Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
- warning << string_compose("\"%1\" is not a directory", path) << endmsg;
- return;
- }
-
- Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(path);
- Glib::RefPtr<Gio::FileEnumerator> e = dir->enumerate_children();
- Glib::RefPtr<Gio::FileInfo> fi;
- while ((fi = e->next_file())) {
- if (fi->get_type() == Gio::FILE_TYPE_DIRECTORY) {
- remove_directory(fi->get_name());
- } else {
- dir->get_child(fi->get_name())->remove();
- }
- }
- dir->remove();
-}
-
void
LV2Plugin::add_state(XMLNode* root) const
{
} else {
// State is identical, decrement version and nuke directory
lilv_state_free(state);
- remove_directory(new_dir);
+ PBD::remove_directory(new_dir);
--_state_version;
}
std::string uri = Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
LilvNode *node_bundle = lilv_new_uri(_world.world, Glib::filename_to_uri(Glib::build_filename(bundle, "/")).c_str());
LilvNode *node_preset = lilv_new_uri(_world.world, uri.c_str());
+#ifdef HAVE_LILV_0_19_2
+ lilv_world_unload_resource(_world.world, node_preset);
+ lilv_world_unload_bundle(_world.world, node_bundle);
+#endif
lilv_world_load_bundle(_world.world, node_bundle);
lilv_world_load_resource(_world.world, node_preset);
lilv_node_free(node_bundle);
return true;
}
+static void
+forge_variant(LV2_Atom_Forge* forge, const Variant& value)
+{
+ switch (value.type()) {
+ case Variant::VOID:
+ break;
+ case Variant::BOOL:
+ lv2_atom_forge_bool(forge, value.get_bool());
+ break;
+ case Variant::DOUBLE:
+ lv2_atom_forge_double(forge, value.get_double());
+ break;
+ case Variant::FLOAT:
+ lv2_atom_forge_float(forge, value.get_float());
+ break;
+ case Variant::INT:
+ lv2_atom_forge_int(forge, value.get_int());
+ break;
+ case Variant::LONG:
+ lv2_atom_forge_long(forge, value.get_long());
+ break;
+ case Variant::PATH:
+ lv2_atom_forge_path(
+ forge, value.get_path().c_str(), value.get_path().size());
+ break;
+ case Variant::STRING:
+ lv2_atom_forge_string(
+ forge, value.get_string().c_str(), value.get_string().size());
+ break;
+ case Variant::URI:
+ lv2_atom_forge_uri(
+ forge, value.get_uri().c_str(), value.get_uri().size());
+ break;
+ }
+}
+
+/** Get a variant type from a URI, return false iff no match found. */
+static bool
+uri_to_variant_type(const std::string& uri, Variant::Type& type)
+{
+ if (uri == LV2_ATOM__Bool) {
+ type = Variant::BOOL;
+ } else if (uri == LV2_ATOM__Double) {
+ type = Variant::DOUBLE;
+ } else if (uri == LV2_ATOM__Float) {
+ type = Variant::FLOAT;
+ } else if (uri == LV2_ATOM__Int) {
+ type = Variant::INT;
+ } else if (uri == LV2_ATOM__Long) {
+ type = Variant::LONG;
+ } else if (uri == LV2_ATOM__Path) {
+ type = Variant::PATH;
+ } else if (uri == LV2_ATOM__String) {
+ type = Variant::STRING;
+ } else if (uri == LV2_ATOM__URI) {
+ type = Variant::URI;
+ } else {
+ return false;
+ }
+ return true;
+}
+
void
-LV2Plugin::enable_ui_emmission()
+LV2Plugin::set_property(uint32_t key, const Variant& value)
+{
+ if (_patch_port_in_index == (uint32_t)-1) {
+ error << "LV2: set_property called with unset patch_port_in_index" << endmsg;
+ return;
+ } else if (value.type() == Variant::VOID) {
+ error << "LV2: set_property called with void value" << endmsg;
+ return;
+ }
+
+ // Set up forge to write to temporary buffer on the stack
+ LV2_Atom_Forge* forge = &_impl->ui_forge;
+ LV2_Atom_Forge_Frame frame;
+ uint8_t buf[PATH_MAX]; // Ought to be enough for anyone...
+
+ lv2_atom_forge_set_buffer(forge, buf, sizeof(buf));
+
+ // Serialize patch:Set message to set property
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.patch_Set);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.patch_property);
+ lv2_atom_forge_urid(forge, key);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.patch_value);
+#else
+ lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Set);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_property, 0);
+ lv2_atom_forge_urid(forge, key);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_value, 0);
+#endif
+
+ forge_variant(forge, value);
+
+ // Write message to UI=>Plugin ring
+ const LV2_Atom* const atom = (const LV2_Atom*)buf;
+ write_from_ui(_patch_port_in_index,
+ LV2Plugin::urids.atom_eventTransfer,
+ lv2_atom_total_size(atom),
+ (const uint8_t*)atom);
+}
+
+void
+LV2Plugin::get_supported_properties(std::vector<ParameterDescriptor>& descs)
+{
+ LilvWorld* lworld = _world.world;
+ const LilvNode* subject = lilv_plugin_get_uri(_impl->plugin);
+ LilvNodes* properties = lilv_world_find_nodes(
+ lworld, subject, _world.patch_writable, NULL);
+ LILV_FOREACH(nodes, p, properties) {
+ // Get label and range
+ const LilvNode* prop = lilv_nodes_get(properties, p);
+ LilvNode* label = lilv_world_get(lworld, prop, _world.rdfs_label, NULL);
+ LilvNode* range = lilv_world_get(lworld, prop, _world.rdfs_range, NULL);
+
+ // Convert range to variant type (TODO: support for multiple range types)
+ Variant::Type datatype;
+ if (!uri_to_variant_type(lilv_node_as_uri(range), datatype)) {
+ error << string_compose(_("LV2: unknown variant datatype \"%1\""),
+ lilv_node_as_uri(range));
+ continue;
+ }
+
+ // Add description to result
+ ParameterDescriptor desc;
+ desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop));
+ desc.label = lilv_node_as_string(label);
+ desc.datatype = datatype;
+ desc.toggled = datatype == Variant::BOOL;
+ desc.integer_step = datatype == Variant::INT || datatype == Variant::LONG;
+ descs.push_back(desc);
+
+ lilv_node_free(label);
+ lilv_node_free(range);
+ }
+ lilv_nodes_free(properties);
+}
+
+void
+LV2Plugin::announce_property_values()
+{
+ if (_patch_port_in_index == (uint32_t)-1) {
+ return;
+ }
+
+ // Set up forge to write to temporary buffer on the stack
+ LV2_Atom_Forge* forge = &_impl->ui_forge;
+ LV2_Atom_Forge_Frame frame;
+ uint8_t buf[PATH_MAX]; // Ought to be enough for anyone...
+
+ lv2_atom_forge_set_buffer(forge, buf, sizeof(buf));
+
+ // Serialize patch:Get message with no subject (implicitly plugin instance)
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.patch_Get);
+#else
+ lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Get);
+#endif
+
+ // Write message to UI=>Plugin ring
+ const LV2_Atom* const atom = (const LV2_Atom*)buf;
+ write_from_ui(_patch_port_in_index,
+ LV2Plugin::urids.atom_eventTransfer,
+ lv2_atom_total_size(atom),
+ (const uint8_t*)atom);
+}
+
+void
+LV2Plugin::enable_ui_emission()
{
if (!_to_ui) {
/* see note in LV2Plugin::write_from_ui() */
}
desc.enumeration = lilv_port_has_property(_impl->plugin, port, _world.lv2_enumeration);
+ desc.scale_points = get_scale_points(which);
lilv_node_free(def);
lilv_node_free(min);
uint8_t pos_buf[256];
lv2_atom_forge_set_buffer(forge, pos_buf, sizeof(pos_buf));
LV2_Atom_Forge_Frame frame;
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, LV2Plugin::urids.time_Position);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_frame);
+ lv2_atom_forge_long(forge, position);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_speed);
+ lv2_atom_forge_float(forge, speed);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_barBeat);
+ lv2_atom_forge_float(forge, bbt.beats - 1 +
+ (bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_bar);
+ lv2_atom_forge_long(forge, bbt.bars - 1);
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatUnit);
+ lv2_atom_forge_int(forge, t.meter().note_divisor());
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatsPerBar);
+ lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
+ lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatsPerMinute);
+ lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+#else
lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.time_Position);
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_frame, 0);
lv2_atom_forge_long(forge, position);
lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerMinute, 0);
lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+#endif
LV2_Evbuf_Iterator end = lv2_evbuf_end(buf);
const LV2_Atom* const atom = (const LV2_Atom*)pos_buf;
_ev_buffers[port_index] = scratch_bufs.get_lv2_midi(
(flags & PORT_INPUT), 0, (flags & PORT_EVENT));
}
+
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
} else {
continue; // Control port, leave buffer alone
}
}
+
// Write messages to UI
- if (_to_ui && (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
+ if ((_to_ui || _patch_port_out_index != (uint32_t)-1) &&
+ (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
LV2_Evbuf* buf = _ev_buffers[port_index];
for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(buf);
lv2_evbuf_is_valid(i);
uint32_t frames, subframes, type, size;
uint8_t* data;
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
+
+ // Intercept patch change messages to emit PropertyChanged signal
+ if ((flags & PORT_PATCHMSG)) {
+ LV2_Atom* atom = (LV2_Atom*)(data - sizeof(LV2_Atom));
+ if (atom->type == LV2Plugin::urids.atom_Blank ||
+ atom->type == LV2Plugin::urids.atom_Object) {
+ LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
+ if (obj->body.otype == LV2Plugin::urids.patch_Set) {
+ const LV2_Atom* property = NULL;
+ const LV2_Atom* value = NULL;
+ lv2_atom_object_get(obj,
+ LV2Plugin::urids.patch_property, &property,
+ LV2Plugin::urids.patch_value, &value,
+ 0);
+
+ if (!property || !value ||
+ property->type != LV2Plugin::urids.atom_URID ||
+ value->type != LV2Plugin::urids.atom_Path) {
+ std::cerr << "warning: patch:Set for unknown property" << std::endl;
+ continue;
+ }
+
+ const uint32_t prop_id = ((const LV2_Atom_URID*)property)->body;
+ const char* path = (const char*)LV2_ATOM_BODY_CONST(value);
+
+ // Emit PropertyChanged signal for UI
+ PropertyChanged(prop_id, Variant(Variant::PATH, path));
+ }
+ }
+ }
+
+ if (!_to_ui) continue;
write_to_ui(port_index, urids.atom_eventTransfer,
size + sizeof(LV2_Atom),
data - sizeof(LV2_Atom));
}
}
-boost::shared_ptr<Plugin::ScalePoints>
+boost::shared_ptr<ScalePoints>
LV2Plugin::get_scale_points(uint32_t port_index) const
{
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, port_index);
LilvScalePoints* points = lilv_port_get_scale_points(_impl->plugin, port);
- boost::shared_ptr<Plugin::ScalePoints> ret;
+ boost::shared_ptr<ScalePoints> ret;
if (!points) {
return ret;
}
- ret = boost::shared_ptr<Plugin::ScalePoints>(new ScalePoints());
+ ret = boost::shared_ptr<ScalePoints>(new ScalePoints());
LILV_FOREACH(scale_points, i, points) {
const LilvScalePoint* p = lilv_scale_points_get(points, i);
// Run the plugin so that it can set its latency parameter
+ bool was_activated = _was_activated;
activate();
uint32_t port_index = 0;
uint32_t in_index = 0;
uint32_t out_index = 0;
- const framecnt_t bufsize = 1024;
- float buffer[bufsize];
+ // this is done in the main thread. non realtime.
+ const framecnt_t bufsize = _engine.samples_per_cycle();
+ float *buffer = (float*) malloc(_engine.samples_per_cycle() * sizeof(float));
memset(buffer, 0, sizeof(float) * bufsize);
run(bufsize);
deactivate();
+ if (was_activated) {
+ activate();
+ }
+ free(buffer);
}
const LilvPort*
lv2_freewheeling = lilv_new_uri(world, LV2_CORE__freeWheeling);
midi_MidiEvent = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
+ rdfs_label = lilv_new_uri(world, LILV_NS_RDFS "label");
+ rdfs_range = lilv_new_uri(world, LILV_NS_RDFS "range");
rsz_minimumSize = lilv_new_uri(world, LV2_RESIZE_PORT__minimumSize);
time_Position = lilv_new_uri(world, LV2_TIME__Position);
ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI);
ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget");
units_unit = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit");
units_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote");
+ patch_writable = lilv_new_uri(world, LV2_PATCH__writable);
+ patch_Message = lilv_new_uri(world, LV2_PATCH__Message);
}
LV2World::~LV2World()
{
+ lilv_node_free(patch_Message);
+ lilv_node_free(patch_writable);
lilv_node_free(units_midiNote);
lilv_node_free(units_unit);
lilv_node_free(ui_externalkx);
lilv_node_free(time_Position);
lilv_node_free(rsz_minimumSize);
lilv_node_free(rdfs_comment);
+ lilv_node_free(rdfs_label);
+ lilv_node_free(rdfs_range);
lilv_node_free(midi_MidiEvent);
lilv_node_free(lv2_enumeration);
lilv_node_free(lv2_freewheeling);
lilv_node_free(atom_Sequence);
lilv_node_free(atom_Chunk);
lilv_node_free(atom_AtomPort);
+ lilv_world_free(world);
}
void
-LV2World::load_bundled_plugins()
+LV2World::load_bundled_plugins(bool verbose)
{
if (!_bundle_checked) {
- cout << "Scanning folders for bundled LV2s: " << ARDOUR::lv2_bundled_search_path().to_string() << endl;
- PathScanner scanner;
- vector<string *> *plugin_objects = scanner (ARDOUR::lv2_bundled_search_path().to_string(), lv2_filter, 0, true, true);
- if (plugin_objects) {
- for ( vector<string *>::iterator x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
+ if (verbose) {
+ cout << "Scanning folders for bundled LV2s: " << ARDOUR::lv2_bundled_search_path().to_string() << endl;
+ }
+
+ vector<string> plugin_objects;
+ find_paths_matching_filter (plugin_objects, ARDOUR::lv2_bundled_search_path(), lv2_filter, 0, true, true, true);
+ for ( vector<string>::iterator x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
#ifdef PLATFORM_WINDOWS
- string uri = "file:///" + **x + "/";
+ string uri = "file:///" + *x + "/";
#else
- string uri = "file://" + **x + "/";
+ string uri = "file://" + *x + "/";
#endif
- LilvNode *node = lilv_new_uri(world, uri.c_str());
- lilv_world_load_bundle(world, node);
- lilv_node_free(node);
- }
+ LilvNode *node = lilv_new_uri(world, uri.c_str());
+ lilv_world_load_bundle(world, node);
+ lilv_node_free(node);
}
- delete (plugin_objects);
_bundle_checked = true;
}
}
-LV2PluginInfo::LV2PluginInfo (const void* c_plugin)
- : _c_plugin(c_plugin)
+LV2PluginInfo::LV2PluginInfo (const char* plugin_uri)
{
type = ARDOUR::LV2;
+ _plugin_uri = strdup(plugin_uri);
}
LV2PluginInfo::~LV2PluginInfo()
-{}
+{
+ free(_plugin_uri);
+ _plugin_uri = NULL;
+}
PluginPtr
LV2PluginInfo::load(Session& session)
{
try {
PluginPtr plugin;
-
- plugin.reset(new LV2Plugin(session.engine(), session,
- (const LilvPlugin*)_c_plugin,
- session.frame_rate()));
-
- plugin->set_info(PluginInfoPtr(new LV2PluginInfo(*this)));
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(_world.world);
+ LilvNode* uri = lilv_new_uri(_world.world, _plugin_uri);
+ if (!uri) { throw failed_constructor(); }
+ const LilvPlugin* lp = lilv_plugins_get_by_uri(plugins, uri);
+ if (!lp) { throw failed_constructor(); }
+ plugin.reset(new LV2Plugin(session.engine(), session, lp, session.frame_rate()));
+ lilv_node_free(uri);
+ plugin->set_info(PluginInfoPtr(shared_from_this ()));
return plugin;
} catch (failed_constructor& err) {
return PluginPtr((Plugin*)0);
PluginInfoList*
LV2PluginInfo::discover()
{
- _world.load_bundled_plugins();
+ LV2World world;
+ world.load_bundled_plugins();
+ _world.load_bundled_plugins(true);
PluginInfoList* plugs = new PluginInfoList;
- const LilvPlugins* plugins = lilv_world_get_all_plugins(_world.world);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world.world);
- info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+ if (!Config->get_show_plugin_scan_window()) {
+ info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+ }
LILV_FOREACH(plugins, i, plugins) {
const LilvPlugin* p = lilv_plugins_get(plugins, i);
- LV2PluginInfoPtr info(new LV2PluginInfo((const void*)p));
+ const LilvNode* pun = lilv_plugin_get_uri(p);
+ if (!pun) continue;
+ LV2PluginInfoPtr info(new LV2PluginInfo(lilv_node_as_string(pun)));
LilvNode* name = lilv_plugin_get_name(p);
if (!name || !lilv_plugin_get_port_by_index(p, 0)) {
info->name = string(lilv_node_as_string(name));
lilv_node_free(name);
- ARDOUR::PluginScanMessage(_("LV2"), info->name);
+ ARDOUR::PluginScanMessage(_("LV2"), info->name, false);
const LilvPluginClass* pclass = lilv_plugin_get_class(p);
const LilvNode* label = lilv_plugin_class_get_label(pclass);
int count_midi_in = 0;
for (uint32_t i = 0; i < lilv_plugin_get_num_ports(p); ++i) {
const LilvPort* port = lilv_plugin_get_port_by_index(p, i);
- if (lilv_port_is_a(p, port, _world.atom_AtomPort)) {
+ if (lilv_port_is_a(p, port, world.atom_AtomPort)) {
LilvNodes* buffer_types = lilv_port_get_value(
- p, port, _world.atom_bufferType);
+ p, port, world.atom_bufferType);
LilvNodes* atom_supports = lilv_port_get_value(
- p, port, _world.atom_supports);
+ p, port, world.atom_supports);
- if (lilv_nodes_contains(buffer_types, _world.atom_Sequence)
- && lilv_nodes_contains(atom_supports, _world.midi_MidiEvent)) {
- if (lilv_port_is_a(p, port, _world.lv2_InputPort)) {
+ if (lilv_nodes_contains(buffer_types, world.atom_Sequence)
+ && lilv_nodes_contains(atom_supports, world.midi_MidiEvent)) {
+ if (lilv_port_is_a(p, port, world.lv2_InputPort)) {
count_midi_in++;
}
- if (lilv_port_is_a(p, port, _world.lv2_OutputPort)) {
+ if (lilv_port_is_a(p, port, world.lv2_OutputPort)) {
count_midi_out++;
}
}
info->n_inputs.set_audio(
lilv_plugin_get_num_ports_of_class(
- p, _world.lv2_InputPort, _world.lv2_AudioPort, NULL));
+ p, world.lv2_InputPort, world.lv2_AudioPort, NULL));
info->n_inputs.set_midi(
lilv_plugin_get_num_ports_of_class(
- p, _world.lv2_InputPort, _world.ev_EventPort, NULL)
+ p, world.lv2_InputPort, world.ev_EventPort, NULL)
+ count_midi_in);
info->n_outputs.set_audio(
lilv_plugin_get_num_ports_of_class(
- p, _world.lv2_OutputPort, _world.lv2_AudioPort, NULL));
+ p, world.lv2_OutputPort, world.lv2_AudioPort, NULL));
info->n_outputs.set_midi(
lilv_plugin_get_num_ports_of_class(
- p, _world.lv2_OutputPort, _world.ev_EventPort, NULL)
+ p, world.lv2_OutputPort, world.ev_EventPort, NULL)
+ count_midi_out);
info->unique_id = lilv_node_as_uri(lilv_plugin_get_uri(p));