X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Flv2_plugin.cc;h=c12e4930d5c5f00df4c35f65b2693a3d1f0cfc08;hb=22bc62ed4360aaea29c131cc7dead87fa25ef228;hp=4f41b51d1b11ac414f738d71e1a81e30f65b98f6;hpb=6dfb11c2d08201f1a27818955707590b762f5a40;p=ardour.git diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 4f41b51d1b..c12e4930d5 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -66,6 +66,7 @@ #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" +#include "lv2/lv2plug.in/ns/extensions/units/units.h" #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" @@ -78,7 +79,7 @@ #include #endif -// Compatibility for lv2-1.0.0 +// Compatibility for old LV2 #ifndef LV2_ATOM_CONTENTS_CONST #define LV2_ATOM_CONTENTS_CONST(type, atom) \ ((const void*)((const uint8_t*)(atom) + sizeof(type))) @@ -86,6 +87,15 @@ #ifndef LV2_ATOM_BODY_CONST #define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom) #endif +#ifndef LV2_PATCH__property +#define LV2_PATCH__property LV2_PATCH_PREFIX "property" +#endif +#ifndef LV2_PATCH__value +#define LV2_PATCH__value LV2_PATCH_PREFIX "value" +#endif +#ifndef LV2_PATCH__writable +#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable" +#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 @@ -97,34 +107,6 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -URIMap LV2Plugin::_uri_map; - -LV2Plugin::URIDs LV2Plugin::urids = { - _uri_map.uri_to_id(LV2_ATOM__Chunk), - _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_MIDI__MidiEvent), - _uri_map.uri_to_id(LV2_TIME__Position), - _uri_map.uri_to_id(LV2_TIME__bar), - _uri_map.uri_to_id(LV2_TIME__barBeat), - _uri_map.uri_to_id(LV2_TIME__beatUnit), - _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_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 { public: LV2World (); @@ -151,6 +133,9 @@ public: LilvNode* lv2_freewheeling; LilvNode* lv2_inPlaceBroken; LilvNode* lv2_integer; + LilvNode* lv2_default; + LilvNode* lv2_minimum; + LilvNode* lv2_maximum; LilvNode* lv2_reportsLatency; LilvNode* lv2_sampleRate; LilvNode* lv2_toggled; @@ -163,7 +148,10 @@ public: LilvNode* ui_GtkUI; LilvNode* ui_external; LilvNode* ui_externalkx; + LilvNode* units_hz; + LilvNode* units_db; LilvNode* units_unit; + LilvNode* units_render; LilvNode* units_midiNote; LilvNode* patch_writable; LilvNode* patch_Message; @@ -220,11 +208,11 @@ log_vprintf(LV2_Log_Handle /*handle*/, { char* str = NULL; const int ret = g_vasprintf(&str, fmt, args); - if (type == LV2Plugin::urids.log_Error) { + if (type == URIMap::instance().urids.log_Error) { error << str << endmsg; - } else if (type == LV2Plugin::urids.log_Warning) { + } else if (type == URIMap::instance().urids.log_Warning) { warning << str << endmsg; - } else if (type == LV2Plugin::urids.log_Note) { + } else if (type == URIMap::instance().urids.log_Note) { info << str << endmsg; } // TODO: Toggleable log:Trace message support @@ -278,6 +266,7 @@ LV2Plugin::LV2Plugin (AudioEngine& engine, , _insert_id("0") , _patch_port_in_index((uint32_t)-1) , _patch_port_out_index((uint32_t)-1) + , _uri_map(URIMap::instance()) { init(c_plugin, rate); } @@ -291,6 +280,7 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other) , _insert_id(other._insert_id) , _patch_port_in_index((uint32_t)-1) , _patch_port_out_index((uint32_t)-1) + , _uri_map(URIMap::instance()) { init(other._impl->plugin, other._sample_rate); @@ -613,6 +603,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate) } } + load_supported_properties(_property_descriptors); allocate_atom_event_buffers(); latency_compute_run(); } @@ -923,7 +914,7 @@ LV2Plugin::add_state(XMLNode* root) const XMLNode* child; char buf[16]; - LocaleGuard lg(X_("POSIX")); + LocaleGuard lg(X_("C")); for (uint32_t i = 0; i < parameter_count(); ++i) { if (parameter_is_input(i) && parameter_is_control(i)) { @@ -975,11 +966,17 @@ LV2Plugin::add_state(XMLNode* root) const } } -static inline const LilvNode* +// TODO: Once we can rely on lilv 0.16.0, lilv_world_get can replace this +static LilvNode* get_value(LilvWorld* world, const LilvNode* subject, const LilvNode* predicate) { LilvNodes* vs = lilv_world_find_nodes(world, subject, predicate, NULL); - return vs ? lilv_nodes_get_first(vs) : NULL; + if (vs) { + LilvNode* node = lilv_node_duplicate(lilv_nodes_get_first(vs)); + lilv_nodes_free(vs); + return node; + } + return NULL; } void @@ -993,12 +990,13 @@ LV2Plugin::find_presets() LILV_FOREACH(nodes, i, presets) { const LilvNode* preset = lilv_nodes_get(presets, i); lilv_world_load_resource(_world.world, preset); - const LilvNode* name = get_value(_world.world, preset, rdfs_label); + LilvNode* name = get_value(_world.world, preset, rdfs_label); if (name) { _presets.insert(std::make_pair(lilv_node_as_string(preset), Plugin::PresetRecord( lilv_node_as_string(preset), lilv_node_as_string(name)))); + lilv_node_free(name); } else { warning << string_compose( _("Plugin \"%1\" preset \"%2\" is missing a label\n"), @@ -1021,7 +1019,7 @@ set_port_value(const char* port_symbol, uint32_t type) { LV2Plugin* self = (LV2Plugin*)user_data; - if (type != 0 && type != self->_uri_map.uri_to_id(LV2_ATOM__Float)) { + if (type != 0 && type != URIMap::instance().urids.atom_Float) { return; // TODO: Support non-float ports } @@ -1076,11 +1074,25 @@ ARDOUR::lv2plugin_get_port_value(const char* port_symbol, std::string LV2Plugin::do_save_preset(string name) { + LilvNode* plug_name = lilv_plugin_get_name(_impl->plugin); + const string prefix = legalize_for_uri(lilv_node_as_string(plug_name)); const string base_name = legalize_for_uri(name); const string file_name = base_name + ".ttl"; const string bundle = Glib::build_filename( Glib::get_home_dir(), - Glib::build_filename(".lv2", base_name + ".lv2")); + Glib::build_filename(".lv2", prefix + "_" + base_name + ".lv2")); + +#ifdef HAVE_LILV_0_21_3 + /* delete reference to old preset (if any) */ + const PresetRecord* r = preset_by_label(name); + if (r) { + LilvNode* pset = lilv_new_uri (_world.world, r->uri.c_str()); + if (pset) { + lilv_world_unload_resource (_world.world, pset); + lilv_node_free(pset); + } + } +#endif LilvState* state = lilv_state_new_from_instance( _impl->plugin, @@ -1112,7 +1124,7 @@ LV2Plugin::do_save_preset(string name) 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 +#ifdef HAVE_LILV_0_21_3 lilv_world_unload_resource(_world.world, node_preset); lilv_world_unload_bundle(_world.world, node_bundle); #endif @@ -1120,20 +1132,44 @@ LV2Plugin::do_save_preset(string name) lilv_world_load_resource(_world.world, node_preset); lilv_node_free(node_bundle); lilv_node_free(node_preset); + lilv_node_free(plug_name); return uri; } void LV2Plugin::do_remove_preset(string name) { - string preset_file = Glib::build_filename( - Glib::get_home_dir(), - Glib::build_filename( - Glib::build_filename(".lv2", "presets"), - name + ".ttl" - ) - ); - ::g_unlink(preset_file.c_str()); +#ifdef HAVE_LILV_0_21_3 + /* Look up preset record by label (FIXME: ick, label as ID) */ + const PresetRecord* r = preset_by_label(name); + if (!r) { + return; + } + + /* Load a LilvState for the preset. */ + LilvWorld* world = _world.world; + LilvNode* pset = lilv_new_uri(world, r->uri.c_str()); + LilvState* state = lilv_state_new_from_world(world, _uri_map.urid_map(), pset); + if (!state) { + lilv_node_free(pset); + return; + } + + /* Unload preset from world. */ + lilv_world_unload_resource(world, pset); + + /* Delete it from the file system. This will remove the preset file and the entry + from the manifest. If this results in an empty manifest (i.e. the + preset is the only thing in the bundle), then the bundle is removed. */ + lilv_state_delete(world, state); + + lilv_state_free(state); + lilv_node_free(pset); +#endif + /* Without lilv_state_delete(), we could delete the preset file, but this + would leave a broken bundle/manifest around, so the preset would still + be visible, but broken. Naively deleting a bundle is too dangerous, so + we simply do not support preset deletion with older Lilv */ } bool @@ -1224,7 +1260,11 @@ static void forge_variant(LV2_Atom_Forge* forge, const Variant& value) { switch (value.type()) { - case Variant::VOID: + case Variant::NOTHING: + break; + case Variant::BEATS: + // No atom type for this, just forge a double + lv2_atom_forge_double(forge, value.get_beats().to_double()); break; case Variant::BOOL: lv2_atom_forge_bool(forge, value.get_bool()); @@ -1288,7 +1328,7 @@ 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) { + } else if (value.type() == Variant::NOTHING) { error << "LV2: set_property called with void value" << endmsg; return; } @@ -1302,15 +1342,15 @@ LV2Plugin::set_property(uint32_t key, const Variant& value) // 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_object(forge, &frame, 1, _uri_map.urids.patch_Set); + lv2_atom_forge_key(forge, _uri_map.urids.patch_property); lv2_atom_forge_urid(forge, key); - lv2_atom_forge_key(forge, LV2Plugin::urids.patch_value); + lv2_atom_forge_key(forge, _uri_map.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_blank(forge, &frame, 1, _uri_map.urids.patch_Set); + lv2_atom_forge_property_head(forge, _uri_map.urids.patch_property, 0); lv2_atom_forge_urid(forge, key); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_value, 0); + lv2_atom_forge_property_head(forge, _uri_map.urids.patch_value, 0); #endif forge_variant(forge, value); @@ -1318,13 +1358,80 @@ LV2Plugin::set_property(uint32_t key, const Variant& 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, + _uri_map.urids.atom_eventTransfer, lv2_atom_total_size(atom), (const uint8_t*)atom); } +const ParameterDescriptor& +LV2Plugin::get_property_descriptor(uint32_t id) const +{ + PropertyDescriptors::const_iterator p = _property_descriptors.find(id); + if (p != _property_descriptors.end()) { + return p->second; + } + return Plugin::get_property_descriptor(id); +} + +static void +load_parameter_descriptor_units(LilvWorld* lworld, ParameterDescriptor& desc, const LilvNodes* units) +{ + if (lilv_nodes_contains(units, _world.units_midiNote)) { + desc.unit = ParameterDescriptor::MIDI_NOTE; + } else if (lilv_nodes_contains(units, _world.units_db)) { + desc.unit = ParameterDescriptor::DB; + } else if (lilv_nodes_contains(units, _world.units_hz)) { + desc.unit = ParameterDescriptor::HZ; + } + if (lilv_nodes_size(units) > 0) { + const LilvNode* unit = lilv_nodes_get_first(units); + LilvNode* render = get_value(lworld, unit, _world.units_render); + if (render) { + desc.print_fmt = lilv_node_as_string(render); + lilv_node_free(render); + } + } +} + +static void +load_parameter_descriptor(LV2World& world, + ParameterDescriptor& desc, + Variant::Type datatype, + const LilvNode* subject) +{ + LilvWorld* lworld = _world.world; + LilvNode* label = get_value(lworld, subject, _world.rdfs_label); + LilvNode* def = get_value(lworld, subject, _world.lv2_default); + LilvNode* minimum = get_value(lworld, subject, _world.lv2_minimum); + LilvNode* maximum = get_value(lworld, subject, _world.lv2_maximum); + LilvNodes* units = lilv_world_find_nodes(lworld, subject, _world.units_unit, NULL); + if (label) { + desc.label = lilv_node_as_string(label); + } + if (def && lilv_node_is_float(def)) { + desc.normal = lilv_node_as_float(def); + } + if (minimum && lilv_node_is_float(minimum)) { + desc.lower = lilv_node_as_float(minimum); + } + if (maximum && lilv_node_is_float(maximum)) { + desc.upper = lilv_node_as_float(maximum); + } + load_parameter_descriptor_units(lworld, desc, units); + desc.datatype = datatype; + desc.toggled |= datatype == Variant::BOOL; + desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG; + desc.update_steps(); + + lilv_nodes_free(units); + lilv_node_free(label); + lilv_node_free(def); + lilv_node_free(minimum); + lilv_node_free(maximum); +} + void -LV2Plugin::get_supported_properties(std::vector& descs) +LV2Plugin::load_supported_properties(PropertyDescriptors& descs) { LilvWorld* lworld = _world.world; const LilvNode* subject = lilv_plugin_get_uri(_impl->plugin); @@ -1333,27 +1440,28 @@ LV2Plugin::get_supported_properties(std::vector& descs) 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); + LilvNode* range = get_value(lworld, prop, _world.rdfs_range); + if (!range) { + warning << string_compose(_("LV2: property <%1> has no range datatype, ignoring"), + lilv_node_as_uri(prop)) << endmsg; + continue; + } // 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)); + error << string_compose(_("LV2: property <%1> has unsupported datatype <%1>"), + lilv_node_as_uri(prop), lilv_node_as_uri(range)) << endmsg; 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); + desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop)); + desc.datatype = datatype; + load_parameter_descriptor(_world, desc, datatype, prop); + descs.insert(std::make_pair(desc.key, desc)); + lilv_node_free(range); } lilv_nodes_free(properties); @@ -1375,15 +1483,15 @@ LV2Plugin::announce_property_values() // 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); + lv2_atom_forge_object(forge, &frame, 1, _uri_map.urids.patch_Get); #else - lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Get); + lv2_atom_forge_blank(forge, &frame, 1, _uri_map.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, + _uri_map.urids.atom_eventTransfer, lv2_atom_total_size(atom), (const uint8_t*)atom); } @@ -1444,9 +1552,9 @@ LV2Plugin::work_response(uint32_t size, const void* data) } void -LV2Plugin::set_insert_info(const PluginInsert* insert) +LV2Plugin::set_insert_id(PBD::ID id) { - _insert_id = insert->id(); + _insert_id = id; } int @@ -1459,7 +1567,7 @@ LV2Plugin::set_state(const XMLNode& node, int version) const char* sym; const char* value; uint32_t port_id; - LocaleGuard lg(X_("POSIX")); + LocaleGuard lg(X_("C")); if (node.name() != state_node_name()) { error << _("Bad node sent to LV2Plugin::set_state") << endmsg; @@ -1516,10 +1624,24 @@ LV2Plugin::set_state(const XMLNode& node, int version) plugin_dir(), Glib::build_filename(prop->value(), "state.ttl")); - LilvState* state = lilv_state_new_from_file( - _world.world, _uri_map.urid_map(), NULL, state_file.c_str()); + if (!Glib::file_test (state_file, Glib::FileTest (Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR))) { + /* this should be done in lilv_state_new_from_file() + * some systems don't like realpath() calls with an non-existent file. + * (hopefully this fixes crashes on OSX 10.5/PPC, see #6456, + * segfault in __asm realpath$DARWIN_EXTSN + * if so, backport upstream to liblilv) + */ + error << string_compose( + "LV2: expected state file \"%1\" does not exist.", + state_file) << endmsg; + } else { - lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL); + LilvState* state = lilv_state_new_from_file( + _world.world, _uri_map.urid_map(), NULL, state_file.c_str()); + + // lilv_state_restore allows/ignores possible NULL state + lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL); + } } latency_compute_run(); @@ -1532,20 +1654,28 @@ int LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) const { const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which); + if (!port) { + error << string_compose("LV2: get descriptor of non-existent port %1", which) + << endmsg; + return 1; + } LilvNodes* portunits; LilvNode *def, *min, *max; lilv_port_get_range(_impl->plugin, port, &def, &min, &max); portunits = lilv_port_get_value(_impl->plugin, port, _world.units_unit); + // TODO: Once we can rely on lilv 0.18.0 being present, + // load_parameter_descriptor() can be used for ports as well desc.integer_step = lilv_port_has_property(_impl->plugin, port, _world.lv2_integer); desc.toggled = lilv_port_has_property(_impl->plugin, port, _world.lv2_toggled); desc.logarithmic = lilv_port_has_property(_impl->plugin, port, _world.ext_logarithmic); desc.sr_dependent = lilv_port_has_property(_impl->plugin, port, _world.lv2_sampleRate); desc.label = lilv_node_as_string(lilv_port_get_name(_impl->plugin, port)); + desc.normal = def ? lilv_node_as_float(def) : 0.0f; desc.lower = min ? lilv_node_as_float(min) : 0.0f; desc.upper = max ? lilv_node_as_float(max) : 1.0f; - desc.midinote = lilv_nodes_contains(portunits, _world.units_midiNote); + load_parameter_descriptor_units(_world.world, desc, portunits); if (desc.sr_dependent) { desc.lower *= _session.frame_rate (); @@ -1555,20 +1685,11 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c 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.smallstep = 0.1; - desc.largestep = 10.0; - } else { - const float delta = desc.upper - desc.lower; - desc.step = delta / 1000.0f; - desc.smallstep = delta / 10000.0f; - desc.largestep = delta / 10.0f; - } - desc.enumeration = lilv_port_has_property(_impl->plugin, port, _world.lv2_enumeration); desc.scale_points = get_scale_points(which); + desc.update_steps(); + lilv_node_free(def); lilv_node_free(min); lilv_node_free(max); @@ -1628,6 +1749,11 @@ LV2Plugin::automatable() const } } + for (PropertyDescriptors::const_iterator p = _property_descriptors.begin(); + p != _property_descriptors.end(); + ++p) { + ret.insert(ret.end(), Evoral::Parameter(PluginPropertyAutomation, 0, p->first)); + } return ret; } @@ -1716,7 +1842,7 @@ LV2Plugin::allocate_atom_event_buffers() _atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*)); for (int i = 0; i < total_atom_buffers; ++i ) { _atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM, - LV2Plugin::urids.atom_Chunk, LV2Plugin::urids.atom_Sequence); + _uri_map.urids.atom_Chunk, _uri_map.urids.atom_Sequence); } _atom_ev_buffers[total_atom_buffers] = 0; return; @@ -1734,42 +1860,44 @@ write_position(LV2_Atom_Forge* forge, framepos_t position, framecnt_t offset) { + const URIMap::URIDs& urids = URIMap::instance().urids; + 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_object(forge, &frame, 1, urids.time_Position); + lv2_atom_forge_key(forge, urids.time_frame); lv2_atom_forge_long(forge, position); - lv2_atom_forge_key(forge, LV2Plugin::urids.time_speed); + lv2_atom_forge_key(forge, urids.time_speed); lv2_atom_forge_float(forge, speed); - lv2_atom_forge_key(forge, LV2Plugin::urids.time_barBeat); + lv2_atom_forge_key(forge, 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_key(forge, urids.time_bar); lv2_atom_forge_long(forge, bbt.bars - 1); - lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatUnit); + lv2_atom_forge_key(forge, urids.time_beatUnit); lv2_atom_forge_int(forge, t.meter().note_divisor()); - lv2_atom_forge_key(forge, LV2Plugin::urids.time_beatsPerBar); + lv2_atom_forge_key(forge, 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_key(forge, 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_blank(forge, &frame, 1, urids.time_Position); + lv2_atom_forge_property_head(forge, urids.time_frame, 0); lv2_atom_forge_long(forge, position); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_speed, 0); + lv2_atom_forge_property_head(forge, urids.time_speed, 0); lv2_atom_forge_float(forge, speed); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_barBeat, 0); + lv2_atom_forge_property_head(forge, urids.time_barBeat, 0); lv2_atom_forge_float(forge, bbt.beats - 1 + (bbt.ticks / Timecode::BBT_Time::ticks_per_beat)); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_bar, 0); + lv2_atom_forge_property_head(forge, urids.time_bar, 0); lv2_atom_forge_long(forge, bbt.bars - 1); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatUnit, 0); + lv2_atom_forge_property_head(forge, urids.time_beatUnit, 0); lv2_atom_forge_int(forge, t.meter().note_divisor()); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerBar, 0); + lv2_atom_forge_property_head(forge, urids.time_beatsPerBar, 0); lv2_atom_forge_float(forge, t.meter().divisions_per_bar()); - lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerMinute, 0); + lv2_atom_forge_property_head(forge, urids.time_beatsPerMinute, 0); lv2_atom_forge_float(forge, t.tempo().beats_per_minute()); #endif @@ -1880,7 +2008,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs, : m; // Now merge MIDI and any transport events into the buffer - const uint32_t type = LV2Plugin::urids.midi_MidiEvent; + const uint32_t type = _uri_map.urids.midi_MidiEvent; const framepos_t tend = _session.transport_frame() + nframes; ++metric_i; while (m != m_end || (metric_i != tmap.metrics_end() && @@ -1932,11 +2060,11 @@ LV2Plugin::connect_and_run(BufferSet& bufs, error << "Error reading from UI=>Plugin RingBuffer" << endmsg; break; } - if (msg.protocol == urids.atom_eventTransfer) { + if (msg.protocol == URIMap::instance().urids.atom_eventTransfer) { LV2_Evbuf* buf = _ev_buffers[msg.index]; LV2_Evbuf_Iterator i = lv2_evbuf_end(buf); const LV2_Atom* const atom = (const LV2_Atom*)&body[0]; - if (!lv2_evbuf_write(&i, nframes, 0, atom->type, atom->size, + if (!lv2_evbuf_write(&i, nframes - 1, 0, atom->type, atom->size, (const uint8_t*)(atom + 1))) { error << "Failed to write data to LV2 event buffer\n"; } @@ -1998,20 +2126,20 @@ LV2Plugin::connect_and_run(BufferSet& bufs, // 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) { + if (atom->type == _uri_map.urids.atom_Blank || + atom->type == _uri_map.urids.atom_Object) { LV2_Atom_Object* obj = (LV2_Atom_Object*)atom; - if (obj->body.otype == LV2Plugin::urids.patch_Set) { + if (obj->body.otype == _uri_map.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, + _uri_map.urids.patch_property, &property, + _uri_map.urids.patch_value, &value, 0); if (!property || !value || - property->type != LV2Plugin::urids.atom_URID || - value->type != LV2Plugin::urids.atom_Path) { + property->type != _uri_map.urids.atom_URID || + value->type != _uri_map.urids.atom_Path) { std::cerr << "warning: patch:Set for unknown property" << std::endl; continue; } @@ -2020,13 +2148,14 @@ LV2Plugin::connect_and_run(BufferSet& bufs, const char* path = (const char*)LV2_ATOM_BODY_CONST(value); // Emit PropertyChanged signal for UI + // TODO: This should emit the control's Changed signal PropertyChanged(prop_id, Variant(Variant::PATH, path)); } } } if (!_to_ui) continue; - write_to_ui(port_index, urids.atom_eventTransfer, + write_to_ui(port_index, URIMap::instance().urids.atom_eventTransfer, size + sizeof(LV2_Atom), data - sizeof(LV2_Atom)); } @@ -2210,8 +2339,6 @@ LV2World::LV2World() : world(lilv_world_new()) , _bundle_checked(false) { - lilv_world_load_all(world); - atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort); atom_Chunk = lilv_new_uri(world, LV2_ATOM__Chunk); atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence); @@ -2227,6 +2354,9 @@ LV2World::LV2World() lv2_OutputPort = lilv_new_uri(world, LILV_URI_OUTPUT_PORT); lv2_inPlaceBroken = lilv_new_uri(world, LV2_CORE__inPlaceBroken); lv2_integer = lilv_new_uri(world, LV2_CORE__integer); + lv2_default = lilv_new_uri(world, LV2_CORE__default); + lv2_minimum = lilv_new_uri(world, LV2_CORE__minimum); + lv2_maximum = lilv_new_uri(world, LV2_CORE__maximum); lv2_reportsLatency = lilv_new_uri(world, LV2_CORE__reportsLatency); lv2_sampleRate = lilv_new_uri(world, LV2_CORE__sampleRate); lv2_toggled = lilv_new_uri(world, LV2_CORE__toggled); @@ -2241,8 +2371,11 @@ LV2World::LV2World() ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI); ui_external = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external"); 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"); + units_unit = lilv_new_uri(world, LV2_UNITS__unit); + units_render = lilv_new_uri(world, LV2_UNITS__render); + units_hz = lilv_new_uri(world, LV2_UNITS__hz); + units_midiNote = lilv_new_uri(world, LV2_UNITS__midiNote); + units_db = lilv_new_uri(world, LV2_UNITS__db); patch_writable = lilv_new_uri(world, LV2_PATCH__writable); patch_Message = lilv_new_uri(world, LV2_PATCH__Message); } @@ -2251,8 +2384,11 @@ LV2World::~LV2World() { lilv_node_free(patch_Message); lilv_node_free(patch_writable); + lilv_node_free(units_hz); lilv_node_free(units_midiNote); + lilv_node_free(units_db); lilv_node_free(units_unit); + lilv_node_free(units_render); lilv_node_free(ui_externalkx); lilv_node_free(ui_external); lilv_node_free(ui_GtkUI); @@ -2306,6 +2442,7 @@ LV2World::load_bundled_plugins(bool verbose) lilv_node_free(node); } + lilv_world_load_all(world); _bundle_checked = true; } } @@ -2353,10 +2490,6 @@ LV2PluginInfo::discover() PluginInfoList* plugs = new PluginInfoList; const LilvPlugins* plugins = lilv_world_get_all_plugins(world.world); - 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); const LilvNode* pun = lilv_plugin_get_uri(p);