refine self-automating plugin interface

* thin automation at end
* allow plugins to disable its internal write state (ctrl port)
* Debug messages
This commit is contained in:
Robin Gareus 2016-06-05 14:44:54 +02:00
parent b4a020cdf5
commit 37b90c2a9e
5 changed files with 54 additions and 4 deletions

View 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;

View 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"

View 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;

View 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");

View 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);