diff options
Diffstat (limited to 'libs/ardour/lv2_plugin.cc')
-rw-r--r-- | libs/ardour/lv2_plugin.cc | 195 |
1 files changed, 114 insertions, 81 deletions
diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 4f41b51d1b..cf33c22424 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -97,34 +97,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 +123,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; @@ -220,11 +195,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 +253,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 +267,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 +590,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate) } } + load_supported_properties(_property_descriptors); allocate_atom_event_buffers(); latency_compute_run(); } @@ -1021,7 +999,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 } @@ -1302,15 +1280,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 +1296,51 @@ 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 +set_parameter_descriptor(LV2World& world, + ParameterDescriptor& desc, + Variant::Type datatype, + const LilvNode* subject) +{ + LilvWorld* lworld = _world.world; + LilvNode* label = lilv_world_get(lworld, subject, _world.rdfs_label, NULL); + LilvNode* def = lilv_world_get(lworld, subject, _world.lv2_default, NULL); + LilvNode* minimum = lilv_world_get(lworld, subject, _world.lv2_minimum, NULL); + LilvNode* maximum = lilv_world_get(lworld, subject, _world.lv2_maximum, 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); + } + desc.datatype = datatype; + desc.toggled |= datatype == Variant::BOOL; + desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG; +} + void -LV2Plugin::get_supported_properties(std::vector<ParameterDescriptor>& descs) +LV2Plugin::load_supported_properties(PropertyDescriptors& descs) { LilvWorld* lworld = _world.world; const LilvNode* subject = lilv_plugin_get_uri(_impl->plugin); @@ -1333,27 +1349,28 @@ LV2Plugin::get_supported_properties(std::vector<ParameterDescriptor>& 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); + 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; + set_parameter_descriptor(_world, desc, datatype, prop); + descs.insert(std::make_pair(desc.key, desc)); + lilv_node_free(range); } lilv_nodes_free(properties); @@ -1375,15 +1392,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); } @@ -1532,6 +1549,11 @@ 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; @@ -1628,6 +1650,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 +1743,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 +1761,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 +1909,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,7 +1961,7 @@ 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]; @@ -1998,20 +2027,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 +2049,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)); } @@ -2227,6 +2257,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); |