diff --git a/libs/ardour/ardour/readonly_control.h b/libs/ardour/ardour/readonly_control.h index 0e130938af..3a0dd6ebf1 100644 --- a/libs/ardour/ardour/readonly_control.h +++ b/libs/ardour/ardour/readonly_control.h @@ -35,11 +35,11 @@ class LIBARDOUR_API ReadOnlyControl : public PBD::Destructible public: ReadOnlyControl (std::shared_ptr, const ParameterDescriptor&, uint32_t pnum); - double get_parameter () const; + virtual double get_parameter () const; std::string describe_parameter (); const ParameterDescriptor& desc() const { return _desc; } -private: +protected: std::weak_ptr _plugin; const ParameterDescriptor _desc; uint32_t _parameter_num; diff --git a/libs/ardour/region_fx_plugin.cc b/libs/ardour/region_fx_plugin.cc index 9f5cffbf6f..7107c9d105 100644 --- a/libs/ardour/region_fx_plugin.cc +++ b/libs/ardour/region_fx_plugin.cc @@ -37,6 +37,76 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +class TimedReadOnlyControl : public ReadOnlyControl { +public: + TimedReadOnlyControl (std::shared_ptr p, const ParameterDescriptor& desc, uint32_t pnum) + : ReadOnlyControl (p, desc, pnum) + , _flush (false) + {} + + double get_parameter () const { + std::shared_ptr p = _plugin.lock(); + + if (!p) { + return 0; + } + samplepos_t when = p->session().audible_sample (); + + Glib::Threads::Mutex::Lock lm (_history_mutex); + auto it = _history.lower_bound (when); + if (it != _history.begin ()) { + --it; + } + if (it == _history.end ()) { + return p->get_parameter (_parameter_num); + } else { + return it->second; + } + } + + void flush () { + _flush = true; + } + + void store_value (samplepos_t start, samplepos_t end) { + std::shared_ptr p = _plugin.lock(); + if (!p) { + return; + } + double value = p->get_parameter (_parameter_num); + Glib::Threads::Mutex::Lock lm (_history_mutex); + if (_flush) { + _flush = false; + _history.clear (); + } + auto it = _history.lower_bound (start); + if (it != _history.begin ()) { + --it; + if (it->second == value) { + return; + } + assert (start > it->first); + if (start - it->first < 512) { + return; + } + } + _history[start] = value; + + if (_history.size () > 2000 && std::distance (_history.begin(), it) > 1500) { + samplepos_t when = min (start, p->session().audible_sample ()); + auto io = _history.lower_bound (when - p->session().sample_rate ()); + if (std::distance (io, it) > 1) { + _history.erase (_history.begin(), io); + } + } + } + +private: + std::map _history; + mutable Glib::Threads::Mutex _history_mutex; + bool _flush; +}; + RegionFxPlugin::RegionFxPlugin (Session& s, Temporal::TimeDomain const td, std::shared_ptr plug) : SessionObject (s, (plug ? plug->name () : string ("toBeRenamed"))) , TimeDomainProvider (td) @@ -320,7 +390,7 @@ RegionFxPlugin::create_parameters () plugin->get_parameter_descriptor (i, desc); if (!plugin->parameter_is_input (i)) { - _control_outputs[i] = std::shared_ptr (new ReadOnlyControl (plugin, desc, i)); + _control_outputs[i] = std::shared_ptr (new TimedReadOnlyControl (plugin, desc, i)); continue; } @@ -549,6 +619,11 @@ void RegionFxPlugin::flush () { _flush.store (1); + + for (auto const& i : _control_outputs) { + shared_ptr toc = std::dynamic_pointer_cast(i.second); + toc->flush (); + } } bool @@ -1167,6 +1242,11 @@ RegionFxPlugin::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t } } + for (auto const& i : _control_outputs) { + shared_ptr toc = std::dynamic_pointer_cast(i.second); + toc->store_value (start + pos, end + pos); + } + const samplecnt_t l = effective_latency (); if (_plugin_signal_latency != l) { _plugin_signal_latency= l;