OSC: remove debug output.
[ardour.git] / libs / ardour / lv2_plugin.cc
index 7248dfeaa1d71ed6287beec6508f62a6e90ba958..466540b22e61a0469b21fdd8e507c2c7c8b3a9e0 100644 (file)
@@ -71,6 +71,7 @@
 #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"
+#include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.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"
@@ -134,14 +135,18 @@ public:
        LilvNode* ext_causesArtifacts;
        LilvNode* ext_notAutomatic;
        LilvNode* ext_rangeSteps;
+       LilvNode* groups_group;
+       LilvNode* groups_element;
        LilvNode* lv2_AudioPort;
        LilvNode* lv2_ControlPort;
        LilvNode* lv2_InputPort;
        LilvNode* lv2_OutputPort;
+       LilvNode* lv2_designation;
        LilvNode* lv2_enumeration;
        LilvNode* lv2_freewheeling;
        LilvNode* lv2_inPlaceBroken;
        LilvNode* lv2_isSideChain;
+       LilvNode* lv2_index;
        LilvNode* lv2_integer;
        LilvNode* lv2_default;
        LilvNode* lv2_minimum;
@@ -544,11 +549,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _midname_interface = (const LV2_Midnam_Interface*)
                extension_data (LV2_MIDNAM__interface);
        if (_midname_interface) {
-               if (read_midnam ()) {
-                       printf ("READ MIDNAM FROM PLUGIN\n");
-               } else {
-                       printf ("**FAILED TO ** READ MIDNAM FROM PLUGIN\n");
-               }
+               read_midnam ();
        }
 #endif
 
@@ -986,10 +987,16 @@ LV2Plugin::read_midnam () {
                std::stringstream ss;
                ss << (void*)this;
                ss << unique_id();
-               MIDI::Name::MidiPatchManager::instance().remove_custom_midnam (ss.str());
-               rv = MIDI::Name::MidiPatchManager::instance().add_custom_midnam (ss.str(), midnam);
+               rv = MIDI::Name::MidiPatchManager::instance().update_custom_midnam (ss.str(), midnam);
        }
-       free (midnam);
+#ifndef NDEBUG
+       if (rv) {
+               info << string_compose(_("LV2: update midnam for plugin '%1'"), name ()) << endmsg;
+       } else {
+               warning << string_compose(_("LV2: Failed to parse midnam of plugin '%1'"), name ()) << endmsg;
+       }
+#endif
+       _midname_interface->free (midnam);
        return rv;
 }
 
@@ -1003,7 +1010,7 @@ LV2Plugin::midnam_model () {
        if (model) {
                rv = model;
        }
-       free (model);
+       _midname_interface->free (model);
        return rv;
 }
 #endif
@@ -1257,7 +1264,7 @@ LV2Plugin::file_dir() const
 const std::string
 LV2Plugin::state_dir(unsigned num) const
 {
-       return Glib::build_filename(plugin_dir(), string_compose("state%1", num));
+       return Glib::build_filename(plugin_dir(), string("state") + PBD::to_string (num));
 }
 
 /** Implementation of state:makePath for files created at instantiation time.
@@ -1291,26 +1298,26 @@ LV2Plugin::add_state(XMLNode* root) const
        assert(_insert_id != PBD::ID("0"));
 
        XMLNode*    child;
-       char        buf[32];
        LocaleGuard lg;
 
        for (uint32_t i = 0; i < parameter_count(); ++i) {
                if (parameter_is_input(i) && parameter_is_control(i)) {
                        child = new XMLNode("Port");
-                       child->add_property("symbol", port_symbol(i));
-                       snprintf(buf, sizeof(buf), "%+f", _shadow_data[i]);
-                       child->add_property("value", string(buf));
+                       child->set_property("symbol", port_symbol(i));
+                       child->set_property("value", _shadow_data[i]);
                        root->add_child_nocopy(*child);
                }
        }
 
        if (!_plugin_state_dir.empty()) {
-               root->add_property("template-dir", _plugin_state_dir);
+               root->set_property("template-dir", _plugin_state_dir);
        }
 
        if (_has_state_interface) {
                // Provisionally increment state version and create directory
                const std::string new_dir = state_dir(++_state_version);
+               // and keep track of it (for templates & archive)
+               unsigned int saved_state = _state_version;;
                g_mkdir_with_parents(new_dir.c_str(), 0744);
 
                LilvState* state = lilv_state_new_from_instance(
@@ -1356,9 +1363,10 @@ LV2Plugin::add_state(XMLNode* root) const
                        lilv_state_free(state);
                        PBD::remove_directory(new_dir);
                        --_state_version;
+                       saved_state = _state_version;
                }
 
-               root->add_property("state-dir", string_compose("state%1", _state_version));
+               root->set_property("state-dir", string("state") + PBD::to_string (saved_state));
        }
 }
 
@@ -1424,6 +1432,7 @@ set_port_value(const char* port_symbol,
        const uint32_t port_index = self->port_index(port_symbol);
        if (port_index != (uint32_t)-1) {
                self->set_parameter(port_index, *(const float*)value);
+               self->PresetPortSetValue (port_index, *(const float*)value); /* EMIT SIGNAL */
        }
 }
 
@@ -1637,7 +1646,8 @@ LV2Plugin::write_from_ui(uint32_t       index,
                if (_atom_ev_buffers && _atom_ev_buffers[0]) {
                        bufsiz =  lv2_evbuf_get_capacity(_atom_ev_buffers[0]);
                }
-               rbs = max((size_t) bufsiz * 8, rbs);
+               int fact = ceilf(_session.frame_rate () / 3000.f);
+               rbs = max((size_t) bufsiz * std::max (8, fact), rbs);
                _from_ui = new RingBuffer<uint8_t>(rbs);
        }
 
@@ -1747,12 +1757,12 @@ 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, _uri_map.urids.patch_Set);
+       lv2_atom_forge_object(forge, &frame, 0, _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, _uri_map.urids.patch_value);
 #else
-       lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Set);
+       lv2_atom_forge_blank(forge, &frame, 0, _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, _uri_map.urids.patch_value, 0);
@@ -1814,14 +1824,26 @@ load_parameter_descriptor(LV2World&            world,
        if (label) {
                desc.label = lilv_node_as_string(label);
        }
-       if (def && lilv_node_is_float(def)) {
-               desc.normal = lilv_node_as_float(def);
+       if (def) {
+               if (lilv_node_is_float(def)) {
+                       desc.normal = lilv_node_as_float(def);
+               } else if (lilv_node_is_int(def)) {
+                       desc.normal = lilv_node_as_int(def);
+               }
        }
-       if (minimum && lilv_node_is_float(minimum)) {
-               desc.lower = lilv_node_as_float(minimum);
+       if (minimum) {
+               if (lilv_node_is_float(minimum)) {
+                       desc.lower = lilv_node_as_float(minimum);
+               } else if (lilv_node_is_int(minimum)) {
+                       desc.lower = lilv_node_as_int(minimum);
+               }
        }
-       if (maximum && lilv_node_is_float(maximum)) {
-               desc.upper = lilv_node_as_float(maximum);
+       if (maximum) {
+               if (lilv_node_is_float(maximum)) {
+                       desc.upper = lilv_node_as_float(maximum);
+               } else if (lilv_node_is_int(maximum)) {
+                       desc.upper = lilv_node_as_int(maximum);
+               }
        }
        load_parameter_descriptor_units(lworld, desc, units);
        desc.datatype      = datatype;
@@ -1889,9 +1911,9 @@ 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, _uri_map.urids.patch_Get);
+       lv2_atom_forge_object(forge, &frame, 0, _uri_map.urids.patch_Get);
 #else
-       lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Get);
+       lv2_atom_forge_blank(forge, &frame, 0, _uri_map.urids.patch_Get);
 #endif
 
        // Write message to UI=>Plugin ring
@@ -1980,12 +2002,8 @@ int
 LV2Plugin::set_state(const XMLNode& node, int version)
 {
        XMLNodeList          nodes;
-       XMLProperty const * prop;
        XMLNodeConstIterator iter;
        XMLNode*             child;
-       const char*          sym;
-       const char*          value;
-       uint32_t             port_id;
        LocaleGuard          lg;
 
        if (node.name() != state_node_name()) {
@@ -2005,15 +2023,16 @@ LV2Plugin::set_state(const XMLNode& node, int version)
 
                child = *iter;
 
-               if ((prop = child->property("symbol")) != 0) {
-                       sym = prop->value().c_str();
-               } else {
+               std::string sym;
+               if (!child->get_property("symbol", sym)) {
                        warning << _("LV2: port has no symbol, ignored") << endmsg;
                        continue;
                }
 
                map<string, uint32_t>::iterator i = _port_indices.find(sym);
 
+               uint32_t port_id;
+
                if (i != _port_indices.end()) {
                        port_id = i->second;
                } else {
@@ -2021,31 +2040,32 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                        continue;
                }
 
-               if ((prop = child->property("value")) != 0) {
-                       value = prop->value().c_str();
-               } else {
+               float val;
+               if (!child->get_property("value", val)) {
                        warning << _("LV2: port has no value, ignored") << endmsg;
                        continue;
                }
 
-               set_parameter(port_id, atof(value));
+               set_parameter(port_id, val);
        }
 
-       if ((prop = node.property("template-dir")) != 0) {
-               set_state_dir (prop->value ());
+       std::string template_dir;
+       if (node.get_property("template-dir", template_dir)) {
+               set_state_dir (template_dir);
        }
 
        _state_version = 0;
-       if ((prop = node.property("state-dir")) != 0) {
-               if (sscanf(prop->value().c_str(), "state%u", &_state_version) != 1) {
+       std::string state_dir;
+       if (node.get_property("state-dir", state_dir) != 0) {
+               if (sscanf(state_dir.c_str(), "state%u", &_state_version) != 1) {
                        error << string_compose(
                                "LV2: failed to parse state version from \"%1\"",
-                               prop->value()) << endmsg;
+                               state_dir) << endmsg;
                }
 
                std::string state_file = Glib::build_filename(
                        plugin_dir(),
-                       Glib::build_filename(prop->value(), "state.ttl"));
+                       Glib::build_filename(state_dir, "state.ttl"));
 
                LilvState* state = lilv_state_new_from_file(
                        _world.world, _uri_map.urid_map(), NULL, state_file.c_str());
@@ -2181,13 +2201,55 @@ LV2Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) const
                return Plugin::IOPortDescription ("?");
        }
 
-       LilvNode* name = lilv_port_get_name(_impl->plugin,
-                       lilv_plugin_get_port_by_index(_impl->plugin, idx));
+       const LilvPort* pport = lilv_plugin_get_port_by_index (_impl->plugin, idx);
+
+       LilvNode* name = lilv_port_get_name(_impl->plugin, pport);
        Plugin::IOPortDescription iod (lilv_node_as_string (name));
        lilv_node_free(name);
 
-       if (lilv_port_has_property(_impl->plugin,
-                               lilv_plugin_get_port_by_index(_impl->plugin, idx), _world.lv2_isSideChain)) {
+       /* get the port's pg:group */
+       LilvNodes* groups = lilv_port_get_value (_impl->plugin, pport, _world.groups_group);
+       if (lilv_nodes_size (groups) > 0) {
+               const LilvNode* group = lilv_nodes_get_first (groups);
+               LilvNodes* grouplabel = lilv_world_find_nodes (_world.world, group, _world.rdfs_label, NULL);
+
+               /* get the name of the port-group */
+               if (lilv_nodes_size (grouplabel) > 0) {
+                       const LilvNode* grpname = lilv_nodes_get_first (grouplabel);
+                       iod.group_name = lilv_node_as_string (grpname);
+               }
+               lilv_nodes_free (grouplabel);
+
+               /* get all port designations.
+                * we're interested in e.g. lv2:designation pg:right */
+               LilvNodes* designations = lilv_port_get_value (_impl->plugin, pport, _world.lv2_designation);
+               if (lilv_nodes_size (designations) > 0) {
+                       /* get all pg:elements of the pg:group */
+                       LilvNodes* group_childs = lilv_world_find_nodes (_world.world, group, _world.groups_element, NULL);
+                       if (lilv_nodes_size (group_childs) > 0) {
+                               /* iterate over all port designations .. */
+                               LILV_FOREACH (nodes, i, designations) {
+                                       const LilvNode* designation = lilv_nodes_get (designations, i);
+                                       /* match the lv2:designation's element against the port-group's element */
+                                       LILV_FOREACH (nodes, j, group_childs) {
+                                               const LilvNode* group_element = lilv_nodes_get (group_childs, j);
+                                               LilvNodes* elem = lilv_world_find_nodes (_world.world, group_element, _world.lv2_designation, designation);
+                                               /* found it. Now look up the index (channel-number) of the pg:Element */
+                                               if (lilv_nodes_size (elem) > 0) {
+                                                       LilvNodes* idx = lilv_world_find_nodes (_world.world, lilv_nodes_get_first (elem), _world.lv2_index, NULL);
+                                                       if (lilv_node_is_int (lilv_nodes_get_first (idx))) {
+                                                               iod.group_channel = lilv_node_as_int(lilv_nodes_get_first (idx));
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               lilv_nodes_free (groups);
+               lilv_nodes_free (designations);
+       }
+
+       if (lilv_port_has_property(_impl->plugin, pport, _world.lv2_isSideChain)) {
                iod.is_sidechain = true;
        }
        return iod;
@@ -2384,7 +2446,7 @@ write_position(LV2_Atom_Forge*     forge,
        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, urids.time_Position);
+       lv2_atom_forge_object(forge, &frame, 0, urids.time_Position);
        lv2_atom_forge_key(forge, urids.time_frame);
        lv2_atom_forge_long(forge, position);
        lv2_atom_forge_key(forge, urids.time_speed);
@@ -2445,7 +2507,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
        }
 
        if (_bpm_control_port) {
-               *_bpm_control_port = tmap.tempo_at_frame (start).beats_per_minute();
+               *_bpm_control_port = tmap.tempo_at_frame (start).note_types_per_minute();
        }
 
 #ifdef LV2_EXTENDED
@@ -2517,7 +2579,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                        if (valid && (flags & PORT_INPUT)) {
                                if ((flags & PORT_POSITION)) {
                                        Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
-                                       double bpm = tmap.tempo_at_frame (start).beats_per_minute();
+                                       double bpm = tmap.tempo_at_frame (start).note_types_per_minute();
                                        double beatpos = (bbt.bars - 1) * tmetric.meter().divisions_per_bar()
                                                       + (bbt.beats - 1)
                                                       + (bbt.ticks / Timecode::BBT_Time::ticks_per_beat);
@@ -2549,7 +2611,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                        MetricSection* metric = (metric_i != tmap.metrics_end())
                                                ? *metric_i : NULL;
                                        if (m != m_end && (!metric || metric->frame() > (*m).time())) {
-                                               const Evoral::MIDIEvent<framepos_t> ev(*m, false);
+                                               const Evoral::Event<framepos_t> ev(*m, false);
                                                if (ev.time() < nframes) {
                                                        LV2_Evbuf_Iterator eend = lv2_evbuf_end(_ev_buffers[port_index]);
                                                        lv2_evbuf_write(&eend, ev.time(), 0, type, ev.size(), ev.buffer());
@@ -2558,8 +2620,8 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                        } else {
                                                tmetric.set_metric(metric);
                                                Timecode::BBT_Time bbt;
-                                               bbt = tmap.bbt_at_pulse (metric->pulse());
-                                               double bpm = tmap.tempo_at_frame (start/*XXX*/).beats_per_minute();
+                                               bbt = tmap.bbt_at_frame (metric->frame());
+                                               double bpm = tmap.tempo_at_frame (start/*XXX*/).note_types_per_minute();
                                                write_position(&_impl->forge, _ev_buffers[port_index],
                                                               tmetric, bbt, speed, bpm,
                                                               metric->frame(),
@@ -2775,7 +2837,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                        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 == _uri_map.urids.state_Changed) {
+                                               if (obj->body.otype == _uri_map.urids.state_StateChanged) {
                                                        _session.set_dirty ();
                                                }
                                        }
@@ -2832,7 +2894,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                 * so it needs to be realative to that.
                 */
                TempoMetric t = tmap.metric_at(start);
-               _current_bpm = tmap.tempo_at_frame (start).beats_per_minute();
+               _current_bpm = tmap.tempo_at_frame (start).note_types_per_minute();
                Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
                double beatpos = (bbt.bars - 1) * t.meter().divisions_per_bar()
                               + (bbt.beats - 1)
@@ -3066,12 +3128,15 @@ LV2World::LV2World()
        ext_causesArtifacts= lilv_new_uri(world, LV2_PORT_PROPS__causesArtifacts);
        ext_notAutomatic   = lilv_new_uri(world, LV2_PORT_PROPS__notAutomatic);
        ext_rangeSteps     = lilv_new_uri(world, LV2_PORT_PROPS__rangeSteps);
+       groups_group       = lilv_new_uri(world, LV2_PORT_GROUPS__group);
+       groups_element     = lilv_new_uri(world, LV2_PORT_GROUPS__element);
        lv2_AudioPort      = lilv_new_uri(world, LILV_URI_AUDIO_PORT);
        lv2_ControlPort    = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
        lv2_InputPort      = lilv_new_uri(world, LILV_URI_INPUT_PORT);
        lv2_OutputPort     = lilv_new_uri(world, LILV_URI_OUTPUT_PORT);
        lv2_inPlaceBroken  = lilv_new_uri(world, LV2_CORE__inPlaceBroken);
        lv2_isSideChain    = lilv_new_uri(world, LV2_CORE_PREFIX "isSideChain");
+       lv2_index          = lilv_new_uri(world, LV2_CORE__index);
        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);
@@ -3079,6 +3144,7 @@ LV2World::LV2World()
        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);
+       lv2_designation    = lilv_new_uri(world, LV2_CORE__designation);
        lv2_enumeration    = lilv_new_uri(world, LV2_CORE__enumeration);
        lv2_freewheeling   = lilv_new_uri(world, LV2_CORE__freeWheeling);
        midi_MidiEvent     = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
@@ -3147,11 +3213,13 @@ LV2World::~LV2World()
        lilv_node_free(rdfs_label);
        lilv_node_free(rdfs_range);
        lilv_node_free(midi_MidiEvent);
+       lilv_node_free(lv2_designation);
        lilv_node_free(lv2_enumeration);
        lilv_node_free(lv2_freewheeling);
        lilv_node_free(lv2_toggled);
        lilv_node_free(lv2_sampleRate);
        lilv_node_free(lv2_reportsLatency);
+       lilv_node_free(lv2_index);
        lilv_node_free(lv2_integer);
        lilv_node_free(lv2_isSideChain);
        lilv_node_free(lv2_inPlaceBroken);
@@ -3159,6 +3227,8 @@ LV2World::~LV2World()
        lilv_node_free(lv2_InputPort);
        lilv_node_free(lv2_ControlPort);
        lilv_node_free(lv2_AudioPort);
+       lilv_node_free(groups_group);
+       lilv_node_free(groups_element);
        lilv_node_free(ext_rangeSteps);
        lilv_node_free(ext_notAutomatic);
        lilv_node_free(ext_causesArtifacts);
@@ -3282,10 +3352,7 @@ LV2PluginInfo::in_category (const std::string &c) const
 {
        // TODO use untranslated lilv_plugin_get_class()
        // match gtk2_ardour/plugin_selector.cc
-       if (category == c) {
-               return true;
-       }
-       return false;
+       return category == c;
 }
 
 bool