From 1a50b6b8eac917b835ae79dc908e59c0eb3663b2 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 7 Aug 2020 22:02:56 +0200 Subject: [PATCH] Update Plugin API to allow timestamped parameter changes This is in preparation for VST3 automation. --- libs/ardour/ardour/audio_unit.h | 2 +- libs/ardour/ardour/automatable.h | 7 ++--- libs/ardour/ardour/ladspa_plugin.h | 2 +- libs/ardour/ardour/luaproc.h | 2 +- libs/ardour/ardour/lv2_plugin.h | 2 +- libs/ardour/ardour/plugin.h | 7 ++++- libs/ardour/ardour/plugin_insert.h | 2 +- libs/ardour/ardour/vst_plugin.h | 2 +- libs/ardour/audio_unit.cc | 6 ++--- libs/ardour/ladspa_plugin.cc | 10 ++++---- libs/ardour/luaproc.cc | 8 +++--- libs/ardour/lv2_plugin.cc | 8 +++--- libs/ardour/plugin.cc | 2 +- libs/ardour/plugin_insert.cc | 41 +++++++++++++++++++++++++----- libs/ardour/vst_plugin.cc | 10 ++++---- 15 files changed, 73 insertions(+), 38 deletions(-) diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index feae338e86..cf42dacb69 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -71,7 +71,7 @@ class LIBARDOUR_API AUPlugin : public ARDOUR::Plugin const char * maker () const { return _info->creator.c_str(); } uint32_t parameter_count () const; float default_value (uint32_t port); - void set_parameter (uint32_t which, float val); + void set_parameter (uint32_t which, float val, sampleoffset_t); float get_parameter (uint32_t which) const; PluginOutputConfiguration possible_output () const { return _output_configs; } diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index a9756ebfb4..5b413f0b54 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -127,10 +127,11 @@ protected: SlavableControlList slavables () const { return SlavableControlList(); } -private: - inline void find_next_ac_event (boost::shared_ptr, double start, double end, Evoral::ControlEvent& ev) const; - inline void find_prev_ac_event (boost::shared_ptr, double start, double end, Evoral::ControlEvent& ev) const; +protected: + void find_next_ac_event (boost::shared_ptr, double start, double end, Evoral::ControlEvent& ev) const; + void find_prev_ac_event (boost::shared_ptr, double start, double end, Evoral::ControlEvent& ev) const; +private: PBD::ScopedConnectionList _control_connections; ///< connections to our controls' signals }; diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h index bcc7eb66a9..7d10524092 100644 --- a/libs/ardour/ardour/ladspa_plugin.h +++ b/libs/ardour/ardour/ladspa_plugin.h @@ -53,7 +53,7 @@ class LIBARDOUR_API LadspaPlugin : public ARDOUR::Plugin const char* maker() const { return _descriptor->Maker; } uint32_t parameter_count() const { return _descriptor->PortCount; } float default_value (uint32_t port) { return _default_value (port); } - void set_parameter (uint32_t port, float val); + void set_parameter (uint32_t port, float val, sampleoffset_t); float get_parameter (uint32_t port) const; int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; uint32_t nth_parameter (uint32_t port, bool& ok) const; diff --git a/libs/ardour/ardour/luaproc.h b/libs/ardour/ardour/luaproc.h index d2acc9600d..7042c9d25c 100644 --- a/libs/ardour/ardour/luaproc.h +++ b/libs/ardour/ardour/luaproc.h @@ -68,7 +68,7 @@ public: uint32_t parameter_count() const; float default_value (uint32_t port); - void set_parameter (uint32_t port, float val); + void set_parameter (uint32_t port, float val, sampleoffset_t); float get_parameter (uint32_t port) const; int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; uint32_t nth_parameter (uint32_t port, bool& ok) const; diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index 11c9e7ee66..098a766077 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -79,7 +79,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee uint32_t parameter_count () const; float default_value (uint32_t port); samplecnt_t max_latency () const; - void set_parameter (uint32_t port, float val); + void set_parameter (uint32_t port, float val, sampleoffset_t); float get_parameter (uint32_t port) const; std::string get_docs() const; std::string get_parameter_docs(uint32_t which) const; diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 56c0b691a9..38af432c51 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -368,8 +368,13 @@ protected: /* should be overridden by plugin API specific derived types to * actually implement changing the parameter. The derived type should * call this after the change is made. + * + * @param which parameter-id + * @param val the raw value (plugin internal) + * @param when time offset of samples in current cycle (0 .. n_samples) + * when the event is effective. */ - virtual void set_parameter (uint32_t which, float val); + virtual void set_parameter (uint32_t which, float val, sampleoffset_t when); /** Do the actual saving of the current plugin settings to a preset of the provided name. * Should return a URI on success, or an empty string on failure. diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index 200edf0d4c..439df5d46c 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -323,7 +323,7 @@ private: void parameter_changed_externally (uint32_t, float); - void set_parameter (Evoral::Parameter param, float val); + void set_parameter (Evoral::Parameter param, float val, sampleoffset_t); float default_parameter_value (const Evoral::Parameter& param); diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index 2f22095332..78668cad31 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -58,7 +58,7 @@ public: float default_value (uint32_t port); float get_parameter (uint32_t port) const; uint32_t nth_parameter (uint32_t port, bool& ok) const; - void set_parameter (uint32_t port, float val); + void set_parameter (uint32_t port, float val, sampleoffset_t); void set_parameter_automated (uint32_t port, float val); bool load_preset (PresetRecord); int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 706d216eaa..cf2f4838b5 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -508,7 +508,7 @@ AUPlugin::AUPlugin (const AUPlugin& other) set_state (root, Stateful::loading_state_version); for (size_t i = 0; i < descriptors.size(); ++i) { - set_parameter (i, other.get_parameter (i)); + set_parameter (i, other.get_parameter (i), 0); } } @@ -961,7 +961,7 @@ AUPlugin::plugin_latency () const } void -AUPlugin::set_parameter (uint32_t which, float val) +AUPlugin::set_parameter (uint32_t which, float val, sampleoffset_t when) { if (which >= descriptors.size()) { return; @@ -989,7 +989,7 @@ AUPlugin::set_parameter (uint32_t which, float val) /* Note the 1st argument, which means "Don't notify us about a change we made ourselves" */ AUEventListenerNotify (_parameter_listener, NULL, &theEvent); - Plugin::set_parameter (which, val); + Plugin::set_parameter (which, val, when); } float diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index f9ac3eb63f..30b385a6e2 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -295,7 +295,7 @@ LadspaPlugin::_default_value (uint32_t port) const } void -LadspaPlugin::set_parameter (uint32_t which, float val) +LadspaPlugin::set_parameter (uint32_t which, float val, sampleoffset_t when) { if (which < _descriptor->PortCount) { @@ -318,7 +318,7 @@ LadspaPlugin::set_parameter (uint32_t which, float val) << endmsg; } - Plugin::set_parameter (which, val); + Plugin::set_parameter (which, val, when); } /** @return `plugin' value */ @@ -403,7 +403,7 @@ LadspaPlugin::set_state (const XMLNode& node, int version) continue; } - set_parameter (port_id, value); + set_parameter (port_id, value, 0); } latency_compute_run (); @@ -448,7 +448,7 @@ LadspaPlugin::set_state_2X (const XMLNode& node, int /* version */) } sscanf (port, "%" PRIu32, &port_id); - set_parameter (port_id, atof(data)); + set_parameter (port_id, atof(data), 0); } latency_compute_run (); @@ -774,7 +774,7 @@ LadspaPlugin::load_preset (PresetRecord r) if (defs) { for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) { if (parameter_is_input (defs->items[i].pid)) { - set_parameter(defs->items[i].pid, defs->items[i].value); + set_parameter(defs->items[i].pid, defs->items[i].value, 0); PresetPortSetValue (defs->items[i].pid, defs->items[i].value); /* EMIT SIGNAL */ } } diff --git a/libs/ardour/luaproc.cc b/libs/ardour/luaproc.cc index ba388a2569..ab68f0f906 100644 --- a/libs/ardour/luaproc.cc +++ b/libs/ardour/luaproc.cc @@ -916,7 +916,7 @@ LuaProc::set_state (const XMLNode& node, int version) continue; } - set_parameter (port_id, value); + set_parameter (port_id, value, 0); } return Plugin::set_state (node, version); @@ -940,14 +940,14 @@ LuaProc::default_value (uint32_t port) } void -LuaProc::set_parameter (uint32_t port, float val) +LuaProc::set_parameter (uint32_t port, float val, sampleoffset_t when) { assert (port < parameter_count ()); if (get_parameter (port) == val) { return; } _shadow_data[port] = val; - Plugin::set_parameter (port, val); + Plugin::set_parameter (port, val, when); } float @@ -1176,7 +1176,7 @@ LuaProc::load_preset (PresetRecord r) assert (false); continue; } - set_parameter (index, value); + set_parameter (index, value, 0); PresetPortSetValue (index, value); /* EMIT SIGNAL */ } } diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 91f8e8b462..0e1740edb6 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -263,7 +263,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->set_parameter(port_index, *(const float*)value, 0); self->PresetPortSetValue (port_index, *(const float*)value); /* EMIT SIGNAL */ } } @@ -1222,7 +1222,7 @@ LV2Plugin::port_index (const char* symbol) const } void -LV2Plugin::set_parameter(uint32_t which, float val) +LV2Plugin::set_parameter(uint32_t which, float val, sampleoffset_t when) { DEBUG_TRACE(DEBUG::LV2, string_compose( "%1 set parameter %2 to %3\n", name(), which, val)); @@ -1240,7 +1240,7 @@ LV2Plugin::set_parameter(uint32_t which, float val) name(), PROGRAM_NAME, unique_id()) << endmsg; } - Plugin::set_parameter(which, val); + Plugin::set_parameter(which, val, when); } float @@ -2212,7 +2212,7 @@ LV2Plugin::set_state(const XMLNode& node, int version) continue; } - set_parameter(port_id, val); + set_parameter(port_id, val, 0); } std::string template_dir; diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 748019e450..3e5eac4e2d 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -489,7 +489,7 @@ Plugin::clear_preset () } void -Plugin::set_parameter (uint32_t /* which */, float /* value */) +Plugin::set_parameter (uint32_t /* which */, float /* value */, sampleoffset_t /* when */) { _parameter_changed_since_last_preset = true; PresetDirty (); /* EMIT SIGNAL */ diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index a654f2b625..18f49cd764 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -289,7 +289,7 @@ PluginInsert::control_list_automation_state_changed (Evoral::Parameter which, Au = boost::dynamic_pointer_cast(control (which)); if (c && s != Off) { - _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_sample())); + _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_sample()), 0); } } @@ -595,12 +595,12 @@ PluginInsert::parameter_changed_externally (uint32_t which, float val) if (i != _plugins.end()) { ++i; for (; i != _plugins.end(); ++i) { - (*i)->set_parameter (which, val); + (*i)->set_parameter (which, val, 0); } } boost::shared_ptr iasp = _impulseAnalysisPlugin.lock(); if (iasp) { - iasp->set_parameter (which, val); + iasp->set_parameter (which, val, 0); } } @@ -909,11 +909,40 @@ PluginInsert::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t e boost::shared_ptr clist (c.list()); /* we still need to check for Touch and Latch */ if (clist && (static_cast (*clist)).automation_playback ()) { + /* 1. Set value at [sub]cycle start */ bool valid; - const float val = c.list()->rt_safe_eval (start, valid); + float val = clist->rt_safe_eval (start, valid); if (valid) { c.set_value_unchecked(val); } +#if 0 + /* 2. VST3: events between now and end. */ + assert (_plugins.front()->requires_fixed_sized_buffers()); + samplepos_t now = start; + while (true) { + Evoral::ControlEvent next_event (end, 0.0f); + find_next_ac_event (*ci, now, end, next_event); + if (next_event.when >= end) { + break; + } + now = next_event.when; + const float val = c.list()->rt_safe_eval (now, valid); + if (valid) { + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + (*i)->set_parameter (clist->parameter().id(), val, now - start); + } + } + } +#endif +#if 0 + /* 3. set value at cycle-end */ + val = c.list()->rt_safe_eval (end, valid); + if (valid) { + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + (*i)->set_parameter (clist->parameter().id(), val, end - start); + } + } +#endif } } } @@ -2990,12 +3019,12 @@ PluginInsert::PluginControl::actually_set_value (double user_val, PBD::Controlla /* FIXME: probably should be taking out some lock here.. */ for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) { - (*i)->set_parameter (_list->parameter().id(), user_val); + (*i)->set_parameter (_list->parameter().id(), user_val, 0); } boost::shared_ptr iasp = _plugin->_impulseAnalysisPlugin.lock(); if (iasp) { - iasp->set_parameter (_list->parameter().id(), user_val); + iasp->set_parameter (_list->parameter().id(), user_val, 0); } AutomationControl::actually_set_value (user_val, group_override); diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index e75b3b72c4..ef6a7e0bc8 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -187,7 +187,7 @@ VSTPlugin::get_parameter (uint32_t which) const } void -VSTPlugin::set_parameter (uint32_t which, float newval) +VSTPlugin::set_parameter (uint32_t which, float newval, sampleoffset_t when) { if (which == UINT32_MAX - 1) { // ardour uses enable-semantics: 1: enabled, 0: bypassed @@ -217,15 +217,15 @@ VSTPlugin::set_parameter (uint32_t which, float newval) if (!PBD::floateq (curval, oldval, 1)) { /* value has changed, follow rest of the notification path */ - Plugin::set_parameter (which, newval); + Plugin::set_parameter (which, newval, when); } } void -VSTPlugin::parameter_changed_externally (uint32_t which, float value ) +VSTPlugin::parameter_changed_externally (uint32_t which, float value) { ParameterChangedExternally (which, value); /* EMIT SIGNAL */ - Plugin::set_parameter (which, value); + Plugin::set_parameter (which, value, 0); } @@ -531,7 +531,7 @@ VSTPlugin::load_user_preset (PresetRecord r) assert (false); } - set_parameter (index, value); + set_parameter (index, value, 0); PresetPortSetValue (index, value); /* EMIT SIGNAL */ } }