From 66a8776f98d41ebcdd9b0413001d397ad0cb8eff Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 19 Jun 2025 13:50:37 -0600 Subject: [PATCH] fix InternalSend (and InterntalReturn) to allow fade out/MIDI mute previously, as soon as the Send is disabled, it would short-circuit ::run(), preventing the fade to zero to take effect. Now, the send will run until the effective gain reaches zero, and the return will collect data from it until it is fully deactivated. --- libs/ardour/ardour/internal_send.h | 1 + libs/ardour/internal_return.cc | 2 +- libs/ardour/internal_send.cc | 24 +++++++++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/libs/ardour/ardour/internal_send.h b/libs/ardour/ardour/internal_send.h index 7e814a3a41..a355ac22a0 100644 --- a/libs/ardour/ardour/internal_send.h +++ b/libs/ardour/ardour/internal_send.h @@ -45,6 +45,7 @@ public: bool can_support_io_configuration (const ChanCount& in, ChanCount& out); bool configure_io (ChanCount in, ChanCount out); int set_block_size (pframes_t); + bool actually_active() const { return _active; } std::shared_ptr source_route() const { return _send_from; } std::shared_ptr target_route() const { return _send_to; } diff --git a/libs/ardour/internal_return.cc b/libs/ardour/internal_return.cc index a9cfe32d38..a805f71f06 100644 --- a/libs/ardour/internal_return.cc +++ b/libs/ardour/internal_return.cc @@ -48,7 +48,7 @@ InternalReturn::run (BufferSet& bufs, samplepos_t /*start_sample*/, samplepos_t } for (auto & send : _sends) { - if (send->active () && (!send->source_route() || send->source_route()->active())) { + if ((send->active() || send->actually_active()) && (!send->source_route() || send->source_route()->active())) { bufs.merge_from (send->get_buffers(), nframes); } } diff --git a/libs/ardour/internal_send.cc b/libs/ardour/internal_send.cc index 07a1495520..8f0c077ed8 100644 --- a/libs/ardour/internal_send.cc +++ b/libs/ardour/internal_send.cc @@ -49,6 +49,8 @@ using namespace std; PBD::Signal InternalSend::CycleStart; +#define GAIN_COEFF_DELTA (1e-5) + InternalSend::InternalSend (Session& s, std::shared_ptr p, std::shared_ptr mm, @@ -213,7 +215,20 @@ InternalSend::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa { automation_run (start_sample, nframes); - if (!check_active() || !_send_to) { + /* Do not use check_active() here, because we need to continue running + * until the gain has gone to zero. + */ + + if (!_send_to) { + _meter->reset (); + return; + } + + /* main gain control: * mute & bypass/enable */ + const gain_t tgain = target_gain (); + const bool converged = fabsf (_current_gain - tgain) < GAIN_COEFF_DELTA; + + if ((tgain == GAIN_COEFF_ZERO) && converged) { _meter->reset (); return; } @@ -317,9 +332,6 @@ InternalSend::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa } } - /* main gain control: * mute & bypass/enable */ - gain_t tgain = target_gain (); - if (tgain != _current_gain) { /* target gain has changed, fade in/out */ _current_gain = Amp::apply_gain (mixbufs, _session.nominal_sample_rate (), nframes, _current_gain, tgain); @@ -353,7 +365,9 @@ InternalSend::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa _thru_delay->run (bufs, start_sample, end_sample, speed, nframes, true); - /* target will pick up our output when it is ready */ + if (converged) { + _active = _pending_active; + } } void