Prepare to allow to disable latency-compensation
Previously "zero custom/user latency" meant "default plugin latency". This is now saved in a separate boolean allowing a user to reduce a processor's latency to zero. This also prepares for a global switch to use zero latency throughout the whole session.
This commit is contained in:
parent
26f37a4753
commit
3cffaeac74
|
@ -26,27 +26,61 @@
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class LIBARDOUR_API Latent {
|
class LIBARDOUR_API Latent {
|
||||||
public:
|
public:
|
||||||
Latent() : _user_latency (0) {}
|
Latent() : _user_latency (0) {}
|
||||||
virtual ~Latent() {}
|
virtual ~Latent() {}
|
||||||
|
|
||||||
virtual samplecnt_t signal_latency() const = 0;
|
virtual samplecnt_t signal_latency() const = 0;
|
||||||
samplecnt_t user_latency () const { return _user_latency; }
|
|
||||||
|
|
||||||
|
/* effective latency to be used while processing */
|
||||||
samplecnt_t effective_latency() const {
|
samplecnt_t effective_latency() const {
|
||||||
if (_user_latency) {
|
if (_zero_latency) {
|
||||||
|
return 0;
|
||||||
|
} else if (_use_user_latency) {
|
||||||
return _user_latency;
|
return _user_latency;
|
||||||
} else {
|
} else {
|
||||||
return signal_latency ();
|
return signal_latency ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set_user_latency (samplecnt_t val) { _user_latency = val; }
|
/* custom user-set latency, if any */
|
||||||
|
samplecnt_t user_latency () const {
|
||||||
|
if (_use_user_latency) {
|
||||||
|
return _user_latency;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
void unset_user_latency () {
|
||||||
samplecnt_t _user_latency;
|
_use_user_latency = false;
|
||||||
|
_user_latency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_user_latency (samplecnt_t val) {
|
||||||
|
_use_user_latency = true;
|
||||||
|
_user_latency = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void force_zero_latency (bool en) {
|
||||||
|
_zero_latency = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool zero_latency () {
|
||||||
|
return _zero_latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int set_state (const XMLNode& node, int version);
|
||||||
|
void add_state (XMLNode*) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
samplecnt_t _use_user_latency;
|
||||||
|
samplecnt_t _user_latency;
|
||||||
|
static bool _zero_latency;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} /* namespace */
|
||||||
|
|
||||||
|
|
||||||
#endif /* __ardour_latent_h__*/
|
#endif /* __ardour_latent_h__*/
|
||||||
|
|
|
@ -536,7 +536,7 @@ IO::state ()
|
||||||
node->add_child_nocopy (*pnode);
|
node->add_child_nocopy (*pnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
node->set_property (X_("user-latency"), _user_latency);
|
Latent::add_state (node);
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,7 @@ IO::set_state (const XMLNode& node, int version)
|
||||||
ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this));
|
ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
node.get_property ("user-latency", _user_latency);
|
Latent::set_state (node, version);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,10 +528,6 @@ LadspaPlugin::describe_parameter (Evoral::Parameter which)
|
||||||
ARDOUR::samplecnt_t
|
ARDOUR::samplecnt_t
|
||||||
LadspaPlugin::signal_latency () const
|
LadspaPlugin::signal_latency () const
|
||||||
{
|
{
|
||||||
if (_user_latency) {
|
|
||||||
return _user_latency;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_latency_control_port) {
|
if (_latency_control_port) {
|
||||||
return (samplecnt_t) floor (*_latency_control_port);
|
return (samplecnt_t) floor (*_latency_control_port);
|
||||||
} else {
|
} else {
|
||||||
|
|
42
libs/ardour/latent.cc
Normal file
42
libs/ardour/latent.cc
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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/latent.h"
|
||||||
|
|
||||||
|
using namespace ARDOUR;
|
||||||
|
|
||||||
|
bool ARDOUR::Latent::_zero_latency = false;
|
||||||
|
|
||||||
|
int
|
||||||
|
Latent::set_state (const XMLNode& node, int version)
|
||||||
|
{
|
||||||
|
node.get_property ("user-latency", _user_latency);
|
||||||
|
if (!node.get_property ("use-user-latency", _use_user_latency)) {
|
||||||
|
_use_user_latency = _user_latency > 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Latent::add_state (XMLNode* node) const
|
||||||
|
{
|
||||||
|
node->set_property ("user-latency", _user_latency);
|
||||||
|
node->set_property ("use-user-latency", _use_user_latency);
|
||||||
|
}
|
|
@ -651,8 +651,10 @@ PluginInsert::activate ()
|
||||||
if (!owner ()) {
|
if (!owner ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_plugin_signal_latency != signal_latency ()) {
|
|
||||||
_plugin_signal_latency = signal_latency ();
|
const samplecnt_t l = effective_latency ();
|
||||||
|
if (_plugin_signal_latency != l) {
|
||||||
|
_plugin_signal_latency = l;
|
||||||
latency_changed ();
|
latency_changed ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -671,8 +673,10 @@ PluginInsert::deactivate ()
|
||||||
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
||||||
(*i)->deactivate ();
|
(*i)->deactivate ();
|
||||||
}
|
}
|
||||||
if (_plugin_signal_latency != signal_latency ()) {
|
|
||||||
_plugin_signal_latency = signal_latency ();
|
const samplecnt_t l = effective_latency ();
|
||||||
|
if (_plugin_signal_latency != l) {
|
||||||
|
_plugin_signal_latency = l;
|
||||||
latency_changed ();
|
latency_changed ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,8 +1067,9 @@ PluginInsert::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_plugin_signal_latency != signal_latency ()) {
|
const samplecnt_t l = effective_latency ();
|
||||||
_plugin_signal_latency = signal_latency ();
|
if (_plugin_signal_latency != l) {
|
||||||
|
_plugin_signal_latency = l;
|
||||||
latency_changed ();
|
latency_changed ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2906,11 +2911,7 @@ PluginInsert::signal_latency() const
|
||||||
if (!_pending_active) {
|
if (!_pending_active) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (_user_latency) {
|
return plugin_latency ();
|
||||||
return _user_latency;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _plugins[0]->signal_latency ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::PluginType
|
ARDOUR::PluginType
|
||||||
|
|
|
@ -79,8 +79,8 @@ PortInsert::start_latency_detection ()
|
||||||
void
|
void
|
||||||
PortInsert::stop_latency_detection ()
|
PortInsert::stop_latency_detection ()
|
||||||
{
|
{
|
||||||
_latency_flush_samples = signal_latency() + _session.engine().samples_per_cycle();
|
_latency_flush_samples = effective_latency() + _session.engine().samples_per_cycle();
|
||||||
_latency_detect = false;
|
_latency_detect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -232,11 +232,11 @@ PortInsert::signal_latency() const
|
||||||
need to take that into account too.
|
need to take that into account too.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (_measured_latency == 0) {
|
if (_measured_latency == 0) {
|
||||||
return _session.engine().samples_per_cycle() + _input->signal_latency();
|
return _session.engine().samples_per_cycle() + _input->effective_latency ();
|
||||||
} else {
|
} else {
|
||||||
return _measured_latency;
|
return _measured_latency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Caller must hold process lock */
|
/** Caller must hold process lock */
|
||||||
|
|
|
@ -146,7 +146,7 @@ Processor::state ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->set_property("user-latency", _user_latency);
|
Latent::add_state (node);
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ Processor::set_state (const XMLNode& node, int version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.get_property ("user-latency", _user_latency);
|
Latent::set_state (node, version);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -502,7 +502,7 @@ Route::process_output_buffers (BufferSet& bufs,
|
||||||
* So there can be cases where adding up all latencies may not equal _signal_latency.
|
* So there can be cases where adding up all latencies may not equal _signal_latency.
|
||||||
*/
|
*/
|
||||||
if ((*i)->active ()) {
|
if ((*i)->active ()) {
|
||||||
latency += (*i)->signal_latency ();
|
latency += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (re_inject_oob_data) {
|
if (re_inject_oob_data) {
|
||||||
|
@ -569,7 +569,7 @@ Route::bounce_process (BufferSet& buffers, samplepos_t start, samplecnt_t nframe
|
||||||
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
||||||
(*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true);
|
(*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true);
|
||||||
buffers.set_count ((*i)->output_streams());
|
buffers.set_count ((*i)->output_streams());
|
||||||
latency += (*i)->signal_latency ();
|
latency += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*i) == endpoint) {
|
if ((*i) == endpoint) {
|
||||||
|
@ -598,7 +598,7 @@ Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
||||||
latency += (*i)->signal_latency ();
|
latency += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
if ((*i) == endpoint) {
|
if ((*i) == endpoint) {
|
||||||
break;
|
break;
|
||||||
|
@ -1129,7 +1129,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_output->set_user_latency (0);
|
_output->unset_user_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_instrument_info ();
|
reset_instrument_info ();
|
||||||
|
@ -1448,7 +1448,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
_output->set_user_latency (0);
|
_output->unset_user_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!removed) {
|
if (!removed) {
|
||||||
|
@ -1576,7 +1576,7 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
|
||||||
}
|
}
|
||||||
|
|
||||||
sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
|
sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
|
||||||
_output->set_user_latency (0);
|
_output->unset_user_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_instrument_info ();
|
reset_instrument_info ();
|
||||||
|
@ -1648,7 +1648,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_output->set_user_latency (0);
|
_output->unset_user_latency ();
|
||||||
|
|
||||||
if (configure_processors_unlocked (err, &lm)) {
|
if (configure_processors_unlocked (err, &lm)) {
|
||||||
pstate.restore ();
|
pstate.restore ();
|
||||||
|
@ -4038,7 +4038,7 @@ Route::update_signal_latency (bool apply_to_delayline)
|
||||||
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
|
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
|
||||||
|
|
||||||
samplecnt_t l_in = 0;
|
samplecnt_t l_in = 0;
|
||||||
samplecnt_t l_out = _output->user_latency();
|
samplecnt_t l_out = _output->effective_latency ();
|
||||||
for (ProcessorList::reverse_iterator i = _processors.rbegin(); i != _processors.rend(); ++i) {
|
for (ProcessorList::reverse_iterator i = _processors.rbegin(); i != _processors.rend(); ++i) {
|
||||||
if (boost::shared_ptr<Send> snd = boost::dynamic_pointer_cast<Send> (*i)) {
|
if (boost::shared_ptr<Send> snd = boost::dynamic_pointer_cast<Send> (*i)) {
|
||||||
snd->set_delay_in (l_out + _output->latency());
|
snd->set_delay_in (l_out + _output->latency());
|
||||||
|
@ -4052,8 +4052,8 @@ Route::update_signal_latency (bool apply_to_delayline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(*i)->set_output_latency (l_out);
|
(*i)->set_output_latency (l_out);
|
||||||
if ((*i)->active ()) {
|
if ((*i)->active ()) { // XXX
|
||||||
l_out += (*i)->signal_latency ();
|
l_out += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4087,7 +4087,7 @@ Route::update_signal_latency (bool apply_to_delayline)
|
||||||
(*i)->set_playback_offset (_signal_latency + _output->latency ());
|
(*i)->set_playback_offset (_signal_latency + _output->latency ());
|
||||||
(*i)->set_capture_offset (_input->latency ());
|
(*i)->set_capture_offset (_input->latency ());
|
||||||
if ((*i)->active ()) {
|
if ((*i)->active ()) {
|
||||||
l_in += (*i)->signal_latency ();
|
l_in += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4644,7 +4644,7 @@ Route::set_private_port_latencies (bool playback) const
|
||||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
|
|
||||||
if ((*i)->active ()) {
|
if ((*i)->active ()) {
|
||||||
own_latency += (*i)->signal_latency ();
|
own_latency += (*i)->effective_latency ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,9 +141,6 @@ Send::signal_latency () const
|
||||||
if (!_pending_active) {
|
if (!_pending_active) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (_user_latency) {
|
|
||||||
return _user_latency;
|
|
||||||
}
|
|
||||||
if (_delay_out > _delay_in) {
|
if (_delay_out > _delay_in) {
|
||||||
return _delay_out - _delay_in;
|
return _delay_out - _delay_in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -645,10 +645,6 @@ VSTPlugin::describe_parameter (Evoral::Parameter param)
|
||||||
samplecnt_t
|
samplecnt_t
|
||||||
VSTPlugin::signal_latency () const
|
VSTPlugin::signal_latency () const
|
||||||
{
|
{
|
||||||
if (_user_latency) {
|
|
||||||
return _user_latency;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ( defined(__x86_64__) || defined(_M_X64) )
|
#if ( defined(__x86_64__) || defined(_M_X64) )
|
||||||
return *((int32_t *) (((char *) &_plugin->flags) + 24)); /* initialDelay */
|
return *((int32_t *) (((char *) &_plugin->flags) + 24)); /* initialDelay */
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -113,6 +113,7 @@ libardour_sources = [
|
||||||
'io_processor.cc',
|
'io_processor.cc',
|
||||||
'kmeterdsp.cc',
|
'kmeterdsp.cc',
|
||||||
'ladspa_plugin.cc',
|
'ladspa_plugin.cc',
|
||||||
|
'latent.cc',
|
||||||
'legatize.cc',
|
'legatize.cc',
|
||||||
'location.cc',
|
'location.cc',
|
||||||
'location_importer.cc',
|
'location_importer.cc',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user