we always only use the "C" locale when saving.
[ardour.git] / libs / ardour / lv2_plugin.cc
index 3b9a3ef286e8c5ab3536594677be550644ad402c..cceb6020e9c330d1cd384d7e4db74b7c5b48a4d2 100644 (file)
@@ -132,6 +132,7 @@ public:
        LilvNode* lv2_enumeration;
        LilvNode* lv2_freewheeling;
        LilvNode* lv2_inPlaceBroken;
+       LilvNode* lv2_isSideChain;
        LilvNode* lv2_integer;
        LilvNode* lv2_default;
        LilvNode* lv2_minimum;
@@ -364,6 +365,8 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _was_activated          = false;
        _has_state_interface    = false;
        _can_write_automation   = false;
+       _max_latency            = 0;
+       _current_latency        = 0;
        _impl->block_length     = _session.get_block_size();
 
        _instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access";
@@ -631,6 +634,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
 
                _port_flags.push_back(flags);
                _port_minimumSize.push_back(minimumSize);
+               DEBUG_TRACE(DEBUG::LV2, string_compose("port %1 buffer %2 bytes\n", i, minimumSize));
        }
 
        _control_data = new float[num_ports];
@@ -672,6 +676,9 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                        lilv_instance_connect_port(_impl->instance, i, &_control_data[i]);
 
                        if (latent && i == latency_index) {
+                               LilvNode *max;
+                               lilv_port_get_range(_impl->plugin, port, NULL, NULL, &max);
+                               _max_latency = max ? lilv_node_as_float(max) : .02 * _sample_rate;
                                _latency_control_port  = &_control_data[i];
                                *_latency_control_port = 0;
                        }
@@ -802,6 +809,7 @@ LV2Plugin::~LV2Plugin ()
 #endif
 
        free(_features);
+       free(_log_feature.data);
        free(_make_path_feature.data);
        free(_work_schedule_feature.data);
 
@@ -822,6 +830,7 @@ LV2Plugin::~LV2Plugin ()
        delete [] _shadow_data;
        delete [] _defaults;
        delete [] _ev_buffers;
+       delete _impl;
 }
 
 bool
@@ -1118,7 +1127,7 @@ LV2Plugin::add_state(XMLNode* root) const
 
        XMLNode*    child;
        char        buf[32];
-       LocaleGuard lg(X_("C"));
+       LocaleGuard lg ();
 
        for (uint32_t i = 0; i < parameter_count(); ++i) {
                if (parameter_is_input(i) && parameter_is_control(i)) {
@@ -1791,13 +1800,13 @@ int
 LV2Plugin::set_state(const XMLNode& node, int version)
 {
        XMLNodeList          nodes;
-       const XMLProperty*   prop;
+       XMLProperty const * prop;
        XMLNodeConstIterator iter;
        XMLNode*             child;
        const char*          sym;
        const char*          value;
        uint32_t             port_id;
-       LocaleGuard          lg(X_("C"));
+       LocaleGuard          lg ();
 
        if (node.name() != state_node_name()) {
                error << _("Bad node sent to LV2Plugin::set_state") << endmsg;
@@ -1927,6 +1936,56 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c
        return 0;
 }
 
+Plugin::IOPortDescription
+LV2Plugin::describe_io_port (ARDOUR::DataType dt, bool input, uint32_t id) const
+{
+       PortFlags match = 0;
+       switch (dt) {
+               case DataType::AUDIO:
+                       match = PORT_AUDIO;
+                       break;
+               case DataType::MIDI:
+                       match = PORT_SEQUENCE | PORT_MIDI; // ignore old PORT_EVENT
+                       break;
+               default:
+                       return Plugin::IOPortDescription ("?");
+                       break;
+       }
+       if (input) {
+               match |= PORT_INPUT;
+       } else {
+               match |= PORT_OUTPUT;
+       }
+
+       uint32_t p = 0;
+       uint32_t idx = UINT32_MAX;
+
+       uint32_t const num_ports = parameter_count();
+       for (uint32_t port_index = 0; port_index < num_ports; ++port_index) {
+               PortFlags flags = _port_flags[port_index];
+               if ((flags & match) == match) {
+                       if (p == id) {
+                               idx = port_index;
+                       }
+                       ++p;
+               }
+       }
+       if (idx == UINT32_MAX) {
+               return Plugin::IOPortDescription ("?");
+       }
+
+       LilvNode* name = lilv_port_get_name(_impl->plugin,
+                       lilv_plugin_get_port_by_index(_impl->plugin, idx));
+       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)) {
+               iod.is_sidechain = true;
+       }
+       return iod;
+}
+
 string
 LV2Plugin::describe_parameter(Evoral::Parameter which)
 {
@@ -1957,6 +2016,12 @@ LV2Plugin::describe_parameter(Evoral::Parameter which)
        }
 }
 
+framecnt_t
+LV2Plugin::max_latency () const
+{
+       return _max_latency;
+}
+
 framecnt_t
 LV2Plugin::signal_latency() const
 {
@@ -2055,8 +2120,7 @@ LV2Plugin::allocate_atom_event_buffers()
                        LilvNodes* atom_supports = lilv_port_get_value(
                                p, port, _world.atom_supports);
 
-                       if (!lilv_nodes_contains(buffer_types, _world.atom_Sequence)
-                                       || !lilv_nodes_contains(atom_supports, _world.midi_MidiEvent)) {
+                       if (lilv_nodes_contains(buffer_types, _world.atom_Sequence)) {
                                if (lilv_port_is_a(p, port, _world.lv2_InputPort)) {
                                        count_atom_in++;
                                }
@@ -2083,7 +2147,7 @@ LV2Plugin::allocate_atom_event_buffers()
                return;
        }
 
-       DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers of %d bytes\n", total_atom_buffers, minimumSize));
+       DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers of %2 bytes\n", total_atom_buffers, minimumSize));
        _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,
@@ -2464,19 +2528,18 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                                            _uri_map.urids.patch_value,    &value,
                                                                            0);
 
-                                                       if (!property || !value ||
-                                                           property->type != _uri_map.urids.atom_URID ||
-                                                           value->type    != _uri_map.urids.atom_Path) {
+                                                       if (property && value &&
+                                                           property->type == _uri_map.urids.atom_URID &&
+                                                           value->type    == _uri_map.urids.atom_Path) {
+                                                               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
+                                                               // TODO: This should emit the control's Changed signal
+                                                               PropertyChanged(prop_id, Variant(Variant::PATH, path));
+                                                       } else {
                                                                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
-                                                       // TODO: This should emit the control's Changed signal
-                                                       PropertyChanged(prop_id, Variant(Variant::PATH, path));
                                                }
                                        }
                                }
@@ -2496,6 +2559,13 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
        _next_cycle_speed = _session.transport_speed();
        _next_cycle_start = _session.transport_frame() + (nframes * _next_cycle_speed);
 
+       if (_latency_control_port) {
+               framecnt_t new_latency = signal_latency ();
+               if (_current_latency != new_latency) {
+                       LatencyChanged (_current_latency, new_latency); /* EMIT SIGNAL */
+               }
+               _current_latency = new_latency;
+       }
        return 0;
 }
 
@@ -2680,6 +2750,7 @@ LV2World::LV2World()
        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_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);
@@ -2706,7 +2777,7 @@ LV2World::LV2World()
        patch_writable     = lilv_new_uri(world, LV2_PATCH__writable);
        patch_Message      = lilv_new_uri(world, LV2_PATCH__Message);
 #ifdef LV2_EXTENDED
-       lv2_noSampleAccurateCtrl    = lilv_new_uri(world, LV2_CORE_PREFIX "noSampleAccurateControls");
+       lv2_noSampleAccurateCtrl    = lilv_new_uri(world, "http://ardour.org/lv2/ext#noSampleAccurateControls");
        auto_can_write_automatation = lilv_new_uri(world, LV2_AUTOMATE_URI__can_write);
        auto_automation_control     = lilv_new_uri(world, LV2_AUTOMATE_URI__control);
        auto_automation_controlled  = lilv_new_uri(world, LV2_AUTOMATE_URI__controlled);
@@ -2757,6 +2828,7 @@ LV2World::~LV2World()
        lilv_node_free(lv2_sampleRate);
        lilv_node_free(lv2_reportsLatency);
        lilv_node_free(lv2_integer);
+       lilv_node_free(lv2_isSideChain);
        lilv_node_free(lv2_inPlaceBroken);
        lilv_node_free(lv2_OutputPort);
        lilv_node_free(lv2_InputPort);