mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
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:
parent
79fcb3d0ba
commit
520bbfe515
11 changed files with 191 additions and 30 deletions
|
|
@ -40,6 +40,7 @@
|
||||||
#include "ardour/midi_ring_buffer.h"
|
#include "ardour/midi_ring_buffer.h"
|
||||||
#include "ardour/midi_state_tracker.h"
|
#include "ardour/midi_state_tracker.h"
|
||||||
#include "ardour/parameter_descriptor.h"
|
#include "ardour/parameter_descriptor.h"
|
||||||
|
#include "ardour/tailtime.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
#include "ardour/variant.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.
|
* 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:
|
public:
|
||||||
Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&);
|
Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&);
|
||||||
|
|
@ -172,12 +173,14 @@ public:
|
||||||
return plugin_latency ();
|
return plugin_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
samplecnt_t signal_tailtime () const
|
||||||
|
{
|
||||||
|
return plugin_tailtime ();
|
||||||
|
}
|
||||||
|
|
||||||
/** the max possible latency a plugin will have */
|
/** the max possible latency a plugin will have */
|
||||||
virtual samplecnt_t max_latency () const { return 0; }
|
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 int set_block_size (pframes_t nframes) = 0;
|
||||||
virtual bool requires_fixed_sized_buffers () const { return false; }
|
virtual bool requires_fixed_sized_buffers () const { return false; }
|
||||||
virtual bool inplace_broken () 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.
|
/** tail duration in samples. e.g. for reverb or delay plugins.
|
||||||
*
|
*
|
||||||
* The default when unknown is 2 sec */
|
* The default when unknown is 2 sec */
|
||||||
virtual samplecnt_t plugin_tail () const;
|
virtual samplecnt_t plugin_tailtime () const;
|
||||||
|
|
||||||
|
|
||||||
/** Fill _presets with our presets */
|
/** Fill _presets with our presets */
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace ARDOUR
|
||||||
{
|
{
|
||||||
class ReadOnlyControl;
|
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:
|
public:
|
||||||
RegionFxPlugin (Session&, Temporal::TimeDomain const, std::shared_ptr<Plugin> = std::shared_ptr<Plugin> ());
|
RegionFxPlugin (Session&, Temporal::TimeDomain const, std::shared_ptr<Plugin> = std::shared_ptr<Plugin> ());
|
||||||
|
|
@ -61,6 +61,8 @@ public:
|
||||||
|
|
||||||
/* Latent */
|
/* Latent */
|
||||||
samplecnt_t signal_latency () const;
|
samplecnt_t signal_latency () const;
|
||||||
|
/* TailTime */
|
||||||
|
samplecnt_t signal_tailtime () const;
|
||||||
|
|
||||||
/* PlugInsertBase */
|
/* PlugInsertBase */
|
||||||
uint32_t get_count () const
|
uint32_t get_count () const
|
||||||
|
|
@ -153,10 +155,6 @@ public:
|
||||||
return _required_buffers;
|
return _required_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wrapped Plugin API */
|
|
||||||
PBD::Signal0<void> TailChanged;
|
|
||||||
samplecnt_t effective_tail () const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* disallow copy construction */
|
/* disallow copy construction */
|
||||||
RegionFxPlugin (RegionFxPlugin const&);
|
RegionFxPlugin (RegionFxPlugin const&);
|
||||||
|
|
@ -178,7 +176,8 @@ private:
|
||||||
/** details of the match currently being used */
|
/** details of the match currently being used */
|
||||||
Match _match;
|
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;
|
typedef std::vector<std::shared_ptr<Plugin>> Plugins;
|
||||||
Plugins _plugins;
|
Plugins _plugins;
|
||||||
|
|
|
||||||
69
libs/ardour/ardour/tailtime.h
Normal file
69
libs/ardour/ardour/tailtime.h
Normal 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__*/
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ public:
|
||||||
|
|
||||||
/* API for Ardour -- Setup/Processing */
|
/* API for Ardour -- Setup/Processing */
|
||||||
uint32_t plugin_latency ();
|
uint32_t plugin_latency ();
|
||||||
uint32_t plugin_tail ();
|
uint32_t plugin_tailtime ();
|
||||||
bool set_block_size (int32_t);
|
bool set_block_size (int32_t);
|
||||||
bool activate ();
|
bool activate ();
|
||||||
bool deactivate ();
|
bool deactivate ();
|
||||||
|
|
@ -444,7 +444,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
samplecnt_t plugin_latency () const;
|
samplecnt_t plugin_latency () const;
|
||||||
samplecnt_t plugin_tail () const;
|
samplecnt_t plugin_tailtime () const;
|
||||||
void init ();
|
void init ();
|
||||||
void find_presets ();
|
void find_presets ();
|
||||||
void forward_resize_view (int w, int h);
|
void forward_resize_view (int w, int h);
|
||||||
|
|
|
||||||
|
|
@ -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->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 ());
|
rfx->set_block_size (_session.get_block_size ());
|
||||||
|
|
||||||
if (from_set_state) {
|
if (from_set_state) {
|
||||||
|
|
@ -2576,7 +2576,7 @@ AudioRegion::fx_tail_changed (bool no_emit)
|
||||||
{
|
{
|
||||||
uint32_t t = 0;
|
uint32_t t = 0;
|
||||||
for (auto const& rfx : _plugins) {
|
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) {
|
if (t == _fx_tail) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -318,14 +318,7 @@ Plugin::input_streams () const
|
||||||
}
|
}
|
||||||
|
|
||||||
samplecnt_t
|
samplecnt_t
|
||||||
Plugin::effective_tail () const
|
Plugin::plugin_tailtime () 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
|
|
||||||
{
|
{
|
||||||
return _session.sample_rate () * Config->get_tail_duration_sec ();
|
return _session.sample_rate () * Config->get_tail_duration_sec ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2475,7 +2475,7 @@ Region::fx_tail_changed (bool)
|
||||||
{
|
{
|
||||||
uint32_t t = 0;
|
uint32_t t = 0;
|
||||||
for (auto const& rfx : _plugins) {
|
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) {
|
if (t == _fx_tail) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,7 @@ RegionFxPlugin::get_state () const
|
||||||
XMLNode* node = new XMLNode (/*state_node_name*/ "RegionFXPlugin");
|
XMLNode* node = new XMLNode (/*state_node_name*/ "RegionFXPlugin");
|
||||||
|
|
||||||
Latent::add_state (node);
|
Latent::add_state (node);
|
||||||
|
TailTime::add_state (node);
|
||||||
|
|
||||||
node->set_property ("type", _plugins[0]->state_node_name ());
|
node->set_property ("type", _plugins[0]->state_node_name ());
|
||||||
node->set_property ("unique-id", _plugins[0]->unique_id ());
|
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 */
|
ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Latent::set_state (node, version);
|
||||||
|
TailTime::set_state (node, version);
|
||||||
|
|
||||||
return 0;
|
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->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->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->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 ());
|
plugin->set_insert (this, _plugins.size ());
|
||||||
|
|
@ -503,12 +507,12 @@ RegionFxPlugin::signal_latency () const
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::samplecnt_t
|
ARDOUR::samplecnt_t
|
||||||
RegionFxPlugin::effective_tail () const
|
RegionFxPlugin::signal_tailtime () const
|
||||||
{
|
{
|
||||||
if (_plugins.empty ()) {
|
if (_plugins.empty ()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _plugins.front ()->effective_tail ();
|
return _plugins.front ()->signal_tailtime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlugInsertBase::UIElements
|
PlugInsertBase::UIElements
|
||||||
|
|
@ -1440,6 +1444,11 @@ RegionFxPlugin::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t
|
||||||
_plugin_signal_latency= l;
|
_plugin_signal_latency= l;
|
||||||
LatencyChanged (); /* EMIT SIGNAL */
|
LatencyChanged (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
const samplecnt_t t = effective_latency ();
|
||||||
|
if (_plugin_signal_tailtime != l) {
|
||||||
|
_plugin_signal_tailtime = t;
|
||||||
|
TailTimeChanged (); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
87
libs/ardour/tailtime.cc
Normal file
87
libs/ardour/tailtime.cc
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -678,9 +678,9 @@ VST3Plugin::set_block_size (pframes_t n_samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
samplecnt_t
|
samplecnt_t
|
||||||
VST3Plugin::plugin_tail () const
|
VST3Plugin::plugin_tailtime () const
|
||||||
{
|
{
|
||||||
return _plug->plugin_tail ();
|
return _plug->plugin_tailtime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
samplecnt_t
|
samplecnt_t
|
||||||
|
|
@ -1816,7 +1816,7 @@ VST3PI::plugin_latency ()
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
VST3PI::plugin_tail ()
|
VST3PI::plugin_tailtime ()
|
||||||
{
|
{
|
||||||
if (!_plugin_tail) { // XXX this is currently never reset
|
if (!_plugin_tail) { // XXX this is currently never reset
|
||||||
_plugin_tail = _processor->getTailSamples ();
|
_plugin_tail = _processor->getTailSamples ();
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ libardour_sources = [
|
||||||
'system_exec.cc',
|
'system_exec.cc',
|
||||||
'revision.cc',
|
'revision.cc',
|
||||||
'rt_midibuffer.cc',
|
'rt_midibuffer.cc',
|
||||||
|
'tailtime.cc',
|
||||||
'template_utils.cc',
|
'template_utils.cc',
|
||||||
'tempo_map_importer.cc',
|
'tempo_map_importer.cc',
|
||||||
'thawlist.cc',
|
'thawlist.cc',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue