refine self-automating plugin interface
authorRobin Gareus <robin@gareus.org>
Sun, 5 Jun 2016 12:44:54 +0000 (14:44 +0200)
committerRobin Gareus <robin@gareus.org>
Sun, 5 Jun 2016 12:44:54 +0000 (14:44 +0200)
* thin automation at end
* allow plugins to disable its internal write state (ctrl port)
* Debug messages

libs/ardour/ardour/debug.h
libs/ardour/ardour/lv2_extensions.h
libs/ardour/ardour/lv2_plugin.h
libs/ardour/debug.cc
libs/ardour/lv2_plugin.cc

index f8e8bfa5e00a1e4a6a1d2c2763928f24483ef5c8..41935087bd319617aa99df87d5517face0b70f0e 100644 (file)
@@ -54,6 +54,7 @@ namespace PBD {
                LIBARDOUR_API extern DebugBits AudioPlayback;
                LIBARDOUR_API extern DebugBits Panning;
                LIBARDOUR_API extern DebugBits LV2;
+               LIBARDOUR_API extern DebugBits LV2Automate;
                LIBARDOUR_API extern DebugBits CaptureAlignment;
                LIBARDOUR_API extern DebugBits PluginManager;
                LIBARDOUR_API extern DebugBits AudioUnits;
index d49846c8fdfdc70573b37ff6aff8443b8f570972..e299b0864acb639f3fdf64e54f04ca0d415d77da 100644 (file)
@@ -94,6 +94,7 @@ typedef struct {
 #define LV2_AUTOMATE_URI__control LV2_AUTOMATE_URI_PREFIX "automationControl"
 /** lv2:portProperty */
 #define LV2_AUTOMATE_URI__controlled LV2_AUTOMATE_URI_PREFIX "automationControlled"
+#define LV2_AUTOMATE_URI__controller LV2_AUTOMATE_URI_PREFIX "automationController"
 
 /** atom messages */
 #define LV2_AUTOMATE_URI__event LV2_AUTOMATE_URI_PREFIX "event"
index 34e68fdc7f22419a3da03ab7d04eb318a261bc19..6552e40ac3e5239ac638d52318af2411d9a205e2 100644 (file)
@@ -210,7 +210,8 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
                PORT_POSITION = 1 << 7,  ///< Event port understands position
                PORT_PATCHMSG = 1 << 8,  ///< Event port supports patch:Message
                PORT_AUTOCTRL = 1 << 9,  ///< Event port supports auto:AutomationControl
-               PORT_CTRLED   = 1 << 10  ///< Port prop auto:AutomationControlled (can be self controlled)
+               PORT_CTRLED   = 1 << 10, ///< Port prop auto:AutomationControlled (can be self controlled)
+               PORT_CTRLER   = 1 << 11  ///< Port prop auto:AutomationController (can be self set)
        } PortFlag;
 
        typedef unsigned PortFlags;
index 4f204f9a2b7ec8649615e2e2e08ab36b63e9a449..4dd7714812d85253e3a5f92572ba4152f1e90f34 100644 (file)
@@ -50,6 +50,7 @@ PBD::DebugBits PBD::DEBUG::Solo = PBD::new_debug_bit ("solo");
 PBD::DebugBits PBD::DEBUG::AudioPlayback = PBD::new_debug_bit ("audioplayback");
 PBD::DebugBits PBD::DEBUG::Panning = PBD::new_debug_bit ("panning");
 PBD::DebugBits PBD::DEBUG::LV2 = PBD::new_debug_bit ("lv2");
+PBD::DebugBits PBD::DEBUG::LV2Automate = PBD::new_debug_bit ("lv2automate");
 PBD::DebugBits PBD::DEBUG::CaptureAlignment = PBD::new_debug_bit ("capturealignment");
 PBD::DebugBits PBD::DEBUG::PluginManager = PBD::new_debug_bit ("pluginmanager");
 PBD::DebugBits PBD::DEBUG::AudioUnits = PBD::new_debug_bit ("audiounits");
index ca0a5b45e3f13a0378239a32ad5fddd67035ed64..1244d29366dbac62f0540e8db64fb6493dadc1bb 100644 (file)
@@ -174,6 +174,7 @@ public:
        LilvNode* auto_can_write_automatation; // lv2:optionalFeature
        LilvNode* auto_automation_control; // atom:supports
        LilvNode* auto_automation_controlled; // lv2:portProperty
+       LilvNode* auto_automation_controller; // lv2:portProperty
 #endif
 
 private:
@@ -639,6 +640,11 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                                flags |= PORT_CTRLED;
                        }
                }
+               if (lilv_port_has_property(_impl->plugin, port, _world.auto_automation_controller)) {
+                       if ((flags & PORT_INPUT) && (flags & PORT_CONTROL)) {
+                               flags |= PORT_CTRLER;
+                       }
+               }
 #endif
 
                _port_flags.push_back(flags);
@@ -2063,7 +2069,8 @@ LV2Plugin::automatable() const
 void
 LV2Plugin::set_automation_control (uint32_t i, boost::shared_ptr<AutomationControl> c)
 {
-       if ((_port_flags[i] & PORT_CTRLED)) {
+       if ((_port_flags[i] & (PORT_CTRLED | PORT_CTRLER))) {
+               DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("Ctrl Port %1\n", i));
                _ctrl_map [i] = AutomationCtrlPtr (new AutomationCtrl(c));
        }
 }
@@ -2470,8 +2477,12 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                                const uint32_t p = ((const LV2_Atom_Int*)parameter)->body;
                                                                const float v = ((const LV2_Atom_Float*)value)->body;
                                                                // -> add automation event..
+                                                               DEBUG_TRACE(DEBUG::LV2Automate,
+                                                                               string_compose ("Event p: %1 t: %2 v: %3\n", p, frames, v));
                                                                AutomationCtrlPtr c = get_automation_control (p);
-                                                               if (c && c->ac->automation_state() == Touch) {
+                                                               if (c &&
+                                                                    (c->ac->automation_state() == Touch || c->ac->automation_state() == Write)
+                                                                  ) {
                                                                        framepos_t when = std::max ((framepos_t) 0, _session.transport_frame() + frames - _current_latency);
                                                                        assert (_session.transport_frame() + frames - _current_latency >= 0);
                                                                        if (c->guard) {
@@ -2488,11 +2499,42 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                        // writes automation for its own inputs
                                                        // -> put them in "touch" mode (preferably "exclusive plugin touch(TM)"
                                                        for (AutomationCtrlMap::iterator i = _ctrl_map.begin(); i != _ctrl_map.end(); ++i) {
-                                                               i->second->ac->set_automation_state (Touch);
+                                                               if (_port_flags[i->first] & PORT_CTRLED) {
+                                                                       DEBUG_TRACE(DEBUG::LV2Automate,
+                                                                               string_compose ("Setup p: %1\n", i->first));
+                                                                       i->second->ac->set_automation_state (Touch);
+                                                               }
                                                        }
                                                }
                                                else if (obj->body.otype == _uri_map.urids.auto_finalize) {
                                                        // set [touched] parameters to "play" ??
+                                                       // allow plugin to change its mode (from analyze to apply)
+                                                       const LV2_Atom* parameter = NULL;
+                                                       const LV2_Atom* value    = NULL;
+                                                       lv2_atom_object_get(obj,
+                                                                           _uri_map.urids.auto_parameter, &parameter,
+                                                                           _uri_map.urids.auto_value,     &value,
+                                                                           0);
+                                                       if (parameter && value) {
+                                                               const uint32_t p = ((const LV2_Atom_Int*)parameter)->body;
+                                                               const float v = ((const LV2_Atom_Float*)value)->body;
+                                                               AutomationCtrlPtr c = get_automation_control (p);
+                                                               DEBUG_TRACE(DEBUG::LV2Automate,
+                                                                               string_compose ("Finalize p: %1 v: %2\n", p, v));
+                                                               if (c && _port_flags[p] & PORT_CTRLER) {
+                                                                       c->ac->set_value(v, Controllable::NoGroup);
+                                                               }
+                                                       } else {
+                                                               DEBUG_TRACE(DEBUG::LV2Automate, "Finalize\n");
+                                                       }
+                                                       for (AutomationCtrlMap::iterator i = _ctrl_map.begin(); i != _ctrl_map.end(); ++i) {
+                                                               // guard will be false if an event was written
+                                                               if ((_port_flags[i->first] & PORT_CTRLED) && !i->second->guard) {
+                                                                       DEBUG_TRACE(DEBUG::LV2Automate,
+                                                                               string_compose ("Thin p: %1\n", i->first));
+                                                                       i->second->ac->alist ()->thin (20);
+                                                               }
+                                                       }
                                                }
                                                else if (obj->body.otype == _uri_map.urids.auto_start) {
                                                        const LV2_Atom* parameter = NULL;
@@ -2502,6 +2544,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                        if (parameter) {
                                                                const uint32_t p = ((const LV2_Atom_Int*)parameter)->body;
                                                                AutomationCtrlPtr c = get_automation_control (p);
+                                                               DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("Start Touch p: %1\n", p));
                                                                if (c) {
                                                                        c->ac->start_touch (std::max ((framepos_t)0, _session.transport_frame() - _current_latency));
                                                                        c->guard = true;
@@ -2516,6 +2559,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                        if (parameter) {
                                                                const uint32_t p = ((const LV2_Atom_Int*)parameter)->body;
                                                                AutomationCtrlPtr c = get_automation_control (p);
+                                                               DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("End Touch p: %1\n", p));
                                                                if (c) {
                                                                        c->ac->stop_touch (true, std::max ((framepos_t)0, _session.transport_frame() - _current_latency));
                                                                }
@@ -2792,6 +2836,7 @@ LV2World::LV2World()
        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);
+       auto_automation_controller  = lilv_new_uri(world, LV2_AUTOMATE_URI__controller);
 #endif
 #ifdef HAVE_LV2_1_2_0
        bufz_powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
@@ -2816,6 +2861,7 @@ LV2World::~LV2World()
        lilv_node_free(auto_can_write_automatation);
        lilv_node_free(auto_automation_control);
        lilv_node_free(auto_automation_controlled);
+       lilv_node_free(auto_automation_controller);
 #endif
        lilv_node_free(patch_Message);
        lilv_node_free(patch_writable);