13
0

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.
This commit is contained in:
Robin Gareus 2024-08-30 21:21:42 +02:00
parent 79fcb3d0ba
commit 520bbfe515
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
11 changed files with 191 additions and 30 deletions

View File

@ -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<uint32_t> 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<void> 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 */

View File

@ -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<Plugin> = std::shared_ptr<Plugin> ());
@ -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<void> 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<std::shared_ptr<Plugin>> Plugins;
Plugins _plugins;

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 Robin Gareus <robin@gareus.org>
*
* 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<void> 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__*/

View File

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

View File

@ -2488,7 +2488,7 @@ AudioRegion::_add_plugin (std::shared_ptr<RegionFxPlugin> rfx, std::shared_ptr<R
}
rfx->LatencyChanged.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<uint32_t> (t, rfx->effective_tail ());
t = max<uint32_t> (t, rfx->effective_tailtime ());
}
if (t == _fx_tail) {
return;

View File

@ -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<samplecnt_t> (0, min<samplecnt_t> (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 ();
}

View File

@ -2475,7 +2475,7 @@ Region::fx_tail_changed (bool)
{
uint32_t t = 0;
for (auto const& rfx : _plugins) {
t = max<uint32_t> (t, rfx->plugin()->effective_tail ());
t = max<uint32_t> (t, rfx->effective_tailtime ());
}
if (t == _fx_tail) {
return;

View File

@ -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)
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;
}

87
libs/ardour/tailtime.cc Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2024 Robin Gareus <robin@gareus.org>
*
* 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<samplecnt_t> (0, std::min<samplecnt_t> (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);
}

View File

@ -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 ();

View File

@ -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',