From 520bbfe515265d13314c845fb8ff3bca217e9105 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 30 Aug 2024 21:21:42 +0200 Subject: [PATCH] Add proper API to expose plugin tailtime This is in preparation to display current tail time, and allow a user to override it. This is similar to existing processor latency API. --- libs/ardour/ardour/plugin.h | 13 ++-- libs/ardour/ardour/region_fx_plugin.h | 11 ++-- libs/ardour/ardour/tailtime.h | 69 +++++++++++++++++++++ libs/ardour/ardour/vst3_plugin.h | 4 +- libs/ardour/audioregion.cc | 4 +- libs/ardour/plugin.cc | 9 +-- libs/ardour/region.cc | 2 +- libs/ardour/region_fx_plugin.cc | 15 ++++- libs/ardour/tailtime.cc | 87 +++++++++++++++++++++++++++ libs/ardour/vst3_plugin.cc | 6 +- libs/ardour/wscript | 1 + 11 files changed, 191 insertions(+), 30 deletions(-) create mode 100644 libs/ardour/ardour/tailtime.h create mode 100644 libs/ardour/tailtime.cc diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index b8510bbc35..01ad34f8a7 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -40,6 +40,7 @@ #include "ardour/midi_ring_buffer.h" #include "ardour/midi_state_tracker.h" #include "ardour/parameter_descriptor.h" +#include "ardour/tailtime.h" #include "ardour/types.h" #include "ardour/variant.h" @@ -74,7 +75,7 @@ typedef std::set PluginOutputConfiguration; * * Plugins are not used directly in Ardour but always wrapped by a PluginInsert. */ -class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public HasLatency +class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public HasLatency, public HasTailTime { public: Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&); @@ -172,12 +173,14 @@ public: return plugin_latency (); } + samplecnt_t signal_tailtime () const + { + return plugin_tailtime (); + } + /** the max possible latency a plugin will have */ virtual samplecnt_t max_latency () const { return 0; } - samplecnt_t effective_tail() const; - PBD::Signal0 TailChanged; - virtual int set_block_size (pframes_t nframes) = 0; virtual bool requires_fixed_sized_buffers () const { return false; } virtual bool inplace_broken () const { return false; } @@ -429,7 +432,7 @@ private: /** tail duration in samples. e.g. for reverb or delay plugins. * * The default when unknown is 2 sec */ - virtual samplecnt_t plugin_tail () const; + virtual samplecnt_t plugin_tailtime () const; /** Fill _presets with our presets */ diff --git a/libs/ardour/ardour/region_fx_plugin.h b/libs/ardour/ardour/region_fx_plugin.h index 72b35bd6df..74e8c0fd50 100644 --- a/libs/ardour/ardour/region_fx_plugin.h +++ b/libs/ardour/ardour/region_fx_plugin.h @@ -43,7 +43,7 @@ namespace ARDOUR { class ReadOnlyControl; -class LIBARDOUR_API RegionFxPlugin : public SessionObject, public PlugInsertBase, public Latent, public Temporal::TimeDomainProvider +class LIBARDOUR_API RegionFxPlugin : public SessionObject, public PlugInsertBase, public Latent, public TailTime, public Temporal::TimeDomainProvider { public: RegionFxPlugin (Session&, Temporal::TimeDomain const, std::shared_ptr = std::shared_ptr ()); @@ -61,6 +61,8 @@ public: /* Latent */ samplecnt_t signal_latency () const; + /* TailTime */ + samplecnt_t signal_tailtime () const; /* PlugInsertBase */ uint32_t get_count () const @@ -153,10 +155,6 @@ public: return _required_buffers; } - /* wrapped Plugin API */ - PBD::Signal0 TailChanged; - samplecnt_t effective_tail () const; - private: /* disallow copy construction */ RegionFxPlugin (RegionFxPlugin const&); @@ -178,7 +176,8 @@ private: /** details of the match currently being used */ Match _match; - uint32_t _plugin_signal_latency; + samplecnt_t _plugin_signal_latency; + samplecnt_t _plugin_signal_tailtime; typedef std::vector> Plugins; Plugins _plugins; diff --git a/libs/ardour/ardour/tailtime.h b/libs/ardour/ardour/tailtime.h new file mode 100644 index 0000000000..f0e6c038cf --- /dev/null +++ b/libs/ardour/ardour/tailtime.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ardour_tailtime_h__ +#define __ardour_tailtime_h__ + +#include "pbd/signals.h" + +#include "ardour/libardour_visibility.h" +#include "ardour/types.h" + +namespace ARDOUR { + +class LIBARDOUR_API HasTailTime { +public: + virtual ~HasTailTime () {} + virtual samplecnt_t signal_tailtime () const = 0; +}; + +class LIBARDOUR_API TailTime : public HasTailTime { +public: + TailTime (); + TailTime (TailTime const&); + virtual ~TailTime() {} + + samplecnt_t effective_tailtime () const; + + samplecnt_t user_latency () const { + if (_use_user_tailtime) { + return _user_tailtime; + } else { + return 0; + } + } + + void unset_user_tailtime (); + void set_user_tailtime (samplecnt_t val); + + PBD::Signal0 TailTimeChanged; + +protected: + int set_state (const XMLNode& node, int version); + void add_state (XMLNode*) const; + +private: + samplecnt_t _use_user_tailtime; + samplecnt_t _user_tailtime; +}; + +} /* namespace */ + + +#endif /* __ardour_tailtime_h__*/ + diff --git a/libs/ardour/ardour/vst3_plugin.h b/libs/ardour/ardour/vst3_plugin.h index feadc6b52b..3ac40037b6 100644 --- a/libs/ardour/ardour/vst3_plugin.h +++ b/libs/ardour/ardour/vst3_plugin.h @@ -182,7 +182,7 @@ public: /* API for Ardour -- Setup/Processing */ uint32_t plugin_latency (); - uint32_t plugin_tail (); + uint32_t plugin_tailtime (); bool set_block_size (int32_t); bool activate (); bool deactivate (); @@ -444,7 +444,7 @@ public: private: samplecnt_t plugin_latency () const; - samplecnt_t plugin_tail () const; + samplecnt_t plugin_tailtime () const; void init (); void find_presets (); void forward_resize_view (int w, int h); diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 89d79c6579..51260a0959 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -2488,7 +2488,7 @@ AudioRegion::_add_plugin (std::shared_ptr rfx, std::shared_ptrLatencyChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fx_latency_changed, this, false)); - rfx->TailChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fx_tail_changed, this, false)); + rfx->TailTimeChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fx_tail_changed, this, false)); rfx->set_block_size (_session.get_block_size ()); if (from_set_state) { @@ -2576,7 +2576,7 @@ AudioRegion::fx_tail_changed (bool no_emit) { uint32_t t = 0; for (auto const& rfx : _plugins) { - t = max (t, rfx->effective_tail ()); + t = max (t, rfx->effective_tailtime ()); } if (t == _fx_tail) { return; diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 6c4d0fe378..06e442d91a 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -318,14 +318,7 @@ Plugin::input_streams () const } samplecnt_t -Plugin::effective_tail () const -{ - /* consider adding a user-override per plugin; compare to HasLatency, Latent */ - return max (0, min (plugin_tail (), Config->get_max_tail_samples ())); -} - -samplecnt_t -Plugin::plugin_tail () const +Plugin::plugin_tailtime () const { return _session.sample_rate () * Config->get_tail_duration_sec (); } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index a90f0bc8cc..eced85fec7 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -2475,7 +2475,7 @@ Region::fx_tail_changed (bool) { uint32_t t = 0; for (auto const& rfx : _plugins) { - t = max (t, rfx->plugin()->effective_tail ()); + t = max (t, rfx->effective_tailtime ()); } if (t == _fx_tail) { return; diff --git a/libs/ardour/region_fx_plugin.cc b/libs/ardour/region_fx_plugin.cc index 1b10eaef2c..b0547e94d5 100644 --- a/libs/ardour/region_fx_plugin.cc +++ b/libs/ardour/region_fx_plugin.cc @@ -250,6 +250,7 @@ RegionFxPlugin::get_state () const XMLNode* node = new XMLNode (/*state_node_name*/ "RegionFXPlugin"); Latent::add_state (node); + TailTime::add_state (node); node->set_property ("type", _plugins[0]->state_node_name ()); node->set_property ("unique-id", _plugins[0]->unique_id ()); @@ -383,6 +384,10 @@ RegionFxPlugin::set_state (const XMLNode& node, int version) ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ } } + + Latent::set_state (node, version); + TailTime::set_state (node, version); + return 0; } @@ -422,7 +427,6 @@ RegionFxPlugin::add_plugin (std::shared_ptr plugin) plugin->ParameterChangedExternally.connect_same_thread (*this, boost::bind (&RegionFxPlugin::parameter_changed_externally, this, _1, _2)); plugin->StartTouch.connect_same_thread (*this, boost::bind (&RegionFxPlugin::start_touch, this, _1)); plugin->EndTouch.connect_same_thread (*this, boost::bind (&RegionFxPlugin::end_touch, this, _1)); - plugin->TailChanged.connect_same_thread (*this, [this](){ TailChanged (); }); } plugin->set_insert (this, _plugins.size ()); @@ -503,12 +507,12 @@ RegionFxPlugin::signal_latency () const } ARDOUR::samplecnt_t -RegionFxPlugin::effective_tail () const +RegionFxPlugin::signal_tailtime () const { if (_plugins.empty ()) { return 0; } - return _plugins.front ()->effective_tail (); + return _plugins.front ()->signal_tailtime (); } PlugInsertBase::UIElements @@ -1440,6 +1444,11 @@ RegionFxPlugin::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t _plugin_signal_latency= l; LatencyChanged (); /* EMIT SIGNAL */ } + const samplecnt_t t = effective_latency (); + if (_plugin_signal_tailtime != l) { + _plugin_signal_tailtime = t; + TailTimeChanged (); /* EMIT SIGNAL */ + } return true; } diff --git a/libs/ardour/tailtime.cc b/libs/ardour/tailtime.cc new file mode 100644 index 0000000000..fca81206d2 --- /dev/null +++ b/libs/ardour/tailtime.cc @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2024 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pbd/xml++.h" + +#include "ardour/tailtime.h" +#include "ardour/rc_configuration.h" + +using namespace ARDOUR; + +TailTime::TailTime () + : HasTailTime () + , _use_user_tailtime (false) + , _user_tailtime (0) +{} + +TailTime::TailTime (TailTime const& other) + : HasTailTime () + , _use_user_tailtime (other._use_user_tailtime) + , _user_tailtime (other._user_tailtime) +{} + +samplecnt_t +TailTime::effective_tailtime () const +{ + if (_use_user_tailtime) { + return _user_tailtime; + } else { + return std::max (0, std::min (signal_tailtime (), Config->get_max_tail_samples ())); + } +} + +void +TailTime::set_user_tailtime (samplecnt_t val) +{ + if (_use_user_tailtime && _user_tailtime == val) { + return; + } + _use_user_tailtime = true; + _user_tailtime = val; + TailTimeChanged (); /* EMIT SIGNAL */ +} + +void +TailTime::unset_user_tailtime () +{ + if (!_use_user_tailtime) { + return; + } + _use_user_tailtime = false; + _user_tailtime = 0; + TailTimeChanged (); /* EMIT SIGNAL */ +} + + + +int +TailTime::set_state (const XMLNode& node, int version) +{ + node.get_property ("user-tailtime", _user_tailtime); + if (!node.get_property ("use-user-tailtime", _use_user_tailtime)) { + _use_user_tailtime = _user_tailtime > 0; + } + return 0; +} + +void +TailTime::add_state (XMLNode* node) const +{ + node->set_property ("user-tailtime", _user_tailtime); + node->set_property ("use-user-tailtime", _use_user_tailtime); +} diff --git a/libs/ardour/vst3_plugin.cc b/libs/ardour/vst3_plugin.cc index 6ff5509362..27c5f691a5 100644 --- a/libs/ardour/vst3_plugin.cc +++ b/libs/ardour/vst3_plugin.cc @@ -678,9 +678,9 @@ VST3Plugin::set_block_size (pframes_t n_samples) } samplecnt_t -VST3Plugin::plugin_tail () const +VST3Plugin::plugin_tailtime () const { - return _plug->plugin_tail (); + return _plug->plugin_tailtime (); } samplecnt_t @@ -1816,7 +1816,7 @@ VST3PI::plugin_latency () } uint32_t -VST3PI::plugin_tail () +VST3PI::plugin_tailtime () { if (!_plugin_tail) { // XXX this is currently never reset _plugin_tail = _processor->getTailSamples (); diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 1ca9653a6a..6da16f8c45 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -256,6 +256,7 @@ libardour_sources = [ 'system_exec.cc', 'revision.cc', 'rt_midibuffer.cc', + 'tailtime.cc', 'template_utils.cc', 'tempo_map_importer.cc', 'thawlist.cc',