Consolidate send/delivery gain control

This moves the _amp from send to delivery (which already
applies gain for the master-bus normalization). This generalizes
the use of a gain stage for use in port-inserts.
This commit is contained in:
Robin Gareus 2022-10-11 00:25:26 +02:00
parent e665d456c3
commit f3423b8a77
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
8 changed files with 100 additions and 66 deletions

View File

@ -33,6 +33,7 @@
namespace ARDOUR {
class Amp;
class BufferSet;
class IO;
class MuteMaster;
@ -78,6 +79,9 @@ public:
bool can_support_io_configuration (const ChanCount& in, ChanCount& out);
bool configure_io (ChanCount in, ChanCount out);
void activate ();
void deactivate ();
void run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool);
/* supplemental method used with MIDI */
@ -101,8 +105,10 @@ public:
boost::shared_ptr<PannerShell> panner_shell() const { return _panshell; }
boost::shared_ptr<Panner> panner() const;
void add_gain (boost::shared_ptr<GainControl> gc) {
_gain_control = gc;
void set_gain_control (boost::shared_ptr<GainControl> gc);
void set_polarity_control (boost::shared_ptr<AutomationControl> ac) {
_polarity_control = ac;
}
void unpan ();
@ -113,10 +119,18 @@ public:
uint32_t pans_required() const { return _configured_input.n_audio(); }
virtual uint32_t pan_outs() const;
boost::shared_ptr<GainControl> gain_control () const {
return _gain_control;
}
boost::shared_ptr<AutomationControl> polarity_control () const {
return _polarity_control;
}
boost::shared_ptr<Amp> amp() const {
return _amp;
}
protected:
XMLNode& state () const;
@ -124,15 +138,16 @@ protected:
BufferSet* _output_buffers;
gain_t _current_gain;
boost::shared_ptr<PannerShell> _panshell;
boost::shared_ptr<AutomationControl> _polarity_control;
boost::shared_ptr<Amp> _amp;
gain_t target_gain ();
private:
bool _no_outs_cuz_we_no_monitor;
boost::shared_ptr<MuteMaster> _mute_master;
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<MuteMaster> _mute_master;
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<AutomationControl> _polarity_control;
static bool panners_legal;
static PBD::Signal0<void> PannersLegal;

View File

@ -33,7 +33,6 @@
namespace ARDOUR {
class PeakMeter;
class Amp;
class GainControl;
class DelayLine;
@ -73,9 +72,7 @@ public:
bool display_to_user() const;
bool is_foldback () const { return _role == Foldback; }
boost::shared_ptr<Amp> amp() const { return _amp; }
boost::shared_ptr<PeakMeter> meter() const { return _meter; }
boost::shared_ptr<GainControl> gain_control() const { return _gain_control; }
bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; }
@ -117,8 +114,6 @@ protected:
XMLNode& state () const;
bool _metering;
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<DelayLine> _send_delay;
boost::shared_ptr<DelayLine> _thru_delay;

View File

@ -187,6 +187,18 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out)
return false;
}
void
Delivery::set_gain_control (boost::shared_ptr<GainControl> gc) {
if (gc) {
_gain_control = gc;
_amp.reset (new Amp (_session, _("Fader"), _gain_control, true));
_amp->configure_io (_configured_input, _configured_output);
} else {
_amp.reset ();
_gain_control = gc;
}
}
/** Caller must hold process lock */
bool
Delivery::configure_io (ChanCount in, ChanCount out)
@ -233,11 +245,15 @@ Delivery::configure_io (ChanCount in, ChanCount out)
reset_panner ();
if (_amp) {
return _amp->configure_io (in, out);
}
return true;
}
void
Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double /*speed*/, pframes_t nframes, bool result_required)
Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required)
{
assert (_output);
@ -272,11 +288,11 @@ Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample
_current_gain = Amp::apply_gain (bufs, _session.nominal_sample_rate(), nframes, _current_gain, tgain);
} else if (tgain < GAIN_COEFF_SMALL) {
} else if (fabsf (tgain) < GAIN_COEFF_SMALL) {
/* we were quiet last time, and we're still supposed to be quiet.
Silence the outputs, and make sure the buffers are quiet too,
*/
* Silence the outputs, and make sure the buffers are quiet too,
*/
_output->silence (nframes);
if (result_required) {
@ -297,6 +313,13 @@ Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample
Amp::apply_simple_gain (bufs, nframes, speed_quietning, false);
}
/* gain control/automation */
if (_amp) {
_amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
_amp->setup_gain_automation (start_sample, end_sample, nframes);
_amp->run (bufs, start_sample, end_sample, speed, nframes, true);
}
// Panning
if (_panshell && !_panshell->bypassed() && _panshell->panner()) {
@ -376,6 +399,11 @@ Delivery::state () const
node.add_child_nocopy (_panshell->unlinked_pannable()->get_state ());
}
}
/* Note: _gain_control state is saved by the owner,
* mainly for backwards compatibility reasons, but also because
* the gain-control may be owned by Route e.g. LAN _volume_control
*/
if (_polarity_control) {
node.add_child_nocopy (_polarity_control->get_state());
}
@ -588,10 +616,6 @@ Delivery::target_gain ()
gain_t desired_gain = _mute_master->mute_gain_at (mp);
if (_gain_control) {
desired_gain *= _gain_control->get_value();
}
if (_role == Listen && _session.monitor_out() && !_session.listening()) {
/* nobody is soloed, and this delivery is a listen-send to the
@ -609,6 +633,24 @@ Delivery::target_gain ()
return desired_gain;
}
void
Delivery::activate ()
{
if (_amp) {
_amp->activate ();
}
Processor::activate ();
}
void
Delivery::deactivate ()
{
if (_amp) {
_amp->deactivate ();
}
Processor::deactivate ();
}
void
Delivery::no_outs_cuz_we_no_monitor (bool yn)
{

View File

@ -140,10 +140,10 @@ InternalSend::init_gain ()
{
if (_role == Listen) {
/* send to monitor bus is always at unity */
_gain_control->set_value (GAIN_COEFF_UNITY, PBD::Controllable::NoGroup);
gain_control ()->set_value (GAIN_COEFF_UNITY, PBD::Controllable::NoGroup);
} else {
/* aux sends start at -inf dB */
_gain_control->set_value (GAIN_COEFF_ZERO, PBD::Controllable::NoGroup);
gain_control ()->set_value (GAIN_COEFF_ZERO, PBD::Controllable::NoGroup);
}
}
@ -331,7 +331,7 @@ InternalSend::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa
/* consider metering */
if (_metering) {
if (_amp->gain_control ()->get_value () == GAIN_COEFF_ZERO) {
if (gain_control ()->get_value () == GAIN_COEFF_ZERO) {
_meter->reset ();
} else {
_meter->run (mixbufs, start_sample, end_sample, speed, nframes, true);

View File

@ -266,7 +266,7 @@ Route::init ()
if (is_master()) {
_volume_control.reset (new GainControl (_session, MainOutVolume));
_volume_control->set_flag (Controllable::NotAutomatable);
_main_outs->add_gain (_volume_control);
_main_outs->set_gain_control (_volume_control);
_volume.reset (new Amp (_session, X_("LAN Amp"), _volume_control, false));
_volume->set_display_to_user (false);
_volume->deactivate ();
@ -2770,11 +2770,11 @@ Route::set_state (const XMLNode& node, int version)
if (_volume_applies_to_output) {
_volume->deactivate ();
_volume->set_display_to_user (false);
main_outs()->add_gain (_volume_control);
main_outs()->set_gain_control (_volume_control);
} else {
_volume->set_display_to_user (true);
_volume->activate ();
main_outs()->add_gain (boost::shared_ptr<GainControl> ());
main_outs()->set_gain_control (boost::shared_ptr<GainControl> ());
}
}
@ -4792,7 +4792,7 @@ Route::set_volume_applies_to_output (bool en)
if (en) {
_volume->deactivate ();
_volume->set_display_to_user (false);
main_outs()->add_gain (_volume_control);
main_outs()->set_gain_control (_volume_control);
{
/* remove hidden processor */
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
@ -4803,7 +4803,7 @@ Route::set_volume_applies_to_output (bool en)
_volume->set_display_to_user (true);
add_processor (_volume, PostFader, NULL, true);
_volume->activate ();
main_outs()->add_gain (boost::shared_ptr<GainControl> ());
main_outs()->set_gain_control (boost::shared_ptr<GainControl> ());
}
_volume_applies_to_output = en;
_session.set_dirty ();

View File

@ -98,11 +98,11 @@ Send::Send (Session& s, boost::shared_ptr<Pannable> p, boost::shared_ptr<MuteMas
//boost_debug_shared_ptr_mark_interesting (this, "send");
boost::shared_ptr<AutomationList> gl (new AutomationList (Evoral::Parameter (BusSendLevel), time_domain()));
_gain_control = boost::shared_ptr<GainControl> (new GainControl (_session, Evoral::Parameter(BusSendLevel), gl));
_gain_control->set_flag (Controllable::InlineControl);
add_control (_gain_control);
set_gain_control (boost::shared_ptr<GainControl> (new GainControl (_session, Evoral::Parameter(BusSendLevel), gl)));
gain_control ()->set_flag (Controllable::InlineControl);
add_control (gain_control ());
_amp.reset (new Amp (_session, _("Fader"), _gain_control, true));
_meter.reset (new PeakMeter (_session, name()));
_send_delay.reset (new DelayLine (_session, "Send-" + name()));
@ -110,11 +110,8 @@ Send::Send (Session& s, boost::shared_ptr<Pannable> p, boost::shared_ptr<MuteMas
if (_role == Delivery::Aux || _role == Delivery::Send) {
_polarity_control = boost::shared_ptr<AutomationControl> (new AutomationControl (_session, PhaseAutomation, ParameterDescriptor (PhaseAutomation),
boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(PhaseAutomation), time_domain())),
"polarity-invert"));
//_polarity_control->set_flag (Controllable::InlineControl);
add_control (_polarity_control);
set_polarity_control (boost::shared_ptr<AutomationControl> (new AutomationControl (_session, PhaseAutomation, ParameterDescriptor (PhaseAutomation), boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(PhaseAutomation), time_domain())), "polarity-invert")));
add_control (polarity_control ());
}
if (panner_shell()) {
@ -134,20 +131,18 @@ Send::~Send ()
void
Send::activate ()
{
_amp->activate ();
_meter->activate ();
Processor::activate ();
Delivery::activate ();
}
void
Send::deactivate ()
{
_amp->deactivate ();
_meter->deactivate ();
_meter->reset ();
Processor::deactivate ();
Delivery::deactivate ();
}
samplecnt_t
@ -257,22 +252,16 @@ Send::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, do
sendbufs.read_from (bufs, nframes);
assert(sendbufs.count() == bufs.count());
/* gain control */
_amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
_amp->setup_gain_automation (start_sample, end_sample, nframes);
_amp->run (sendbufs, start_sample, end_sample, speed, nframes, true);
_send_delay->run (sendbufs, start_sample, end_sample, speed, nframes, true);
/* deliver to outputs */
/* deliver to outputs (and apply gain) */
Delivery::run (sendbufs, start_sample, end_sample, speed, nframes, true);
/* consider metering */
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
if (gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run (*_output_buffers, start_sample, end_sample, speed, nframes, true);
@ -297,7 +286,7 @@ Send::state () const
node.set_property ("selfdestruct", _remove_on_disconnect);
node.add_child_nocopy (_gain_control->get_state());
node.add_child_nocopy (gain_control ()->get_state());
return node;
}
@ -317,7 +306,7 @@ Send::set_state (const XMLNode& node, int version)
/* old versions had a single Controllable only, and it was
* not always a "gaincontrol"
*/
_gain_control->set_state (*i, version);
gain_control()->set_state (*i, version);
break;
}
@ -326,7 +315,7 @@ Send::set_state (const XMLNode& node, int version)
continue;
}
if (control_name == "gaincontrol" /* gain_control_name (BusSendLevel) */) {
_gain_control->set_state (*i, version);
gain_control ()->set_state (*i, version);
break;
}
}
@ -347,8 +336,8 @@ Send::set_state (const XMLNode& node, int version)
XMLNode* gain_node;
nn = processor;
if ((gain_node = nn->child (Controllable::xml_node_name.c_str ())) != 0) {
_gain_control->set_state (*gain_node, version);
_gain_control->set_flags (Controllable::InlineControl);
gain_control ()->set_state (*gain_node, version);
gain_control ()->set_flags (Controllable::InlineControl);
}
}
}
@ -385,7 +374,7 @@ Send::set_state (const XMLNode& node, int version)
}
XMLNode xn (**i);
xn.set_property ("automation-id", EventTypeMap::instance().to_symbol(Evoral::Parameter (BusSendLevel)));
_gain_control->alist()->set_state (xn, version);
gain_control()->alist()->set_state (xn, version);
break;
}
}
@ -508,11 +497,7 @@ Send::configure_io (ChanCount in, ChanCount out)
ChanCount send_count = in;
send_count.set(DataType::AUDIO, pan_outs());
if (!_amp->configure_io (in, out)) {
return false;
}
if (!Processor::configure_io (in, out)) {
if (!Delivery::configure_io (in, out)) {
return false;
}

View File

@ -3390,7 +3390,7 @@ Session::globally_set_send_gains_to_zero (boost::shared_ptr<Route> dest)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) {
s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO, Controllable::NoGroup);
s->gain_control()->set_value (GAIN_COEFF_ZERO, Controllable::NoGroup);
}
}
}
@ -3403,7 +3403,7 @@ Session::globally_set_send_gains_to_unity (boost::shared_ptr<Route> dest)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) {
s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
s->gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
}
}
}
@ -3416,7 +3416,7 @@ Session::globally_set_send_gains_from_track(boost::shared_ptr<Route> dest)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) {
s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value(), Controllable::NoGroup);
s->gain_control()->set_value ((*i)->gain_control()->get_value(), Controllable::NoGroup);
}
}
}

View File

@ -3255,8 +3255,7 @@ OSC::route_get_sends(lo_message msg) {
lo_message_add_int32(reply, get_sid(isend->target_route(), get_address(msg)));
lo_message_add_string(reply, isend->name().c_str());
lo_message_add_int32(reply, i);
boost::shared_ptr<Amp> a = isend->amp();
lo_message_add_float(reply, a->gain_control()->internal_to_interface (a->gain_control()->get_value()));
lo_message_add_float(reply, isend->gain_control()->internal_to_interface (isend->gain_control()->get_value()));
lo_message_add_int32(reply, p->active() ? 1 : 0);
}
}
@ -3312,12 +3311,10 @@ OSC::route_get_receives(lo_message msg) {
boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (p);
if (isend) {
if( isend->target_route()->id() == r->id()){
boost::shared_ptr<Amp> a = isend->amp();
lo_message_add_int32(reply, get_sid(tr, get_address(msg)));
lo_message_add_string(reply, tr->name().c_str());
lo_message_add_int32(reply, j);
lo_message_add_float(reply, a->gain_control()->internal_to_interface (a->gain_control()->get_value()));
lo_message_add_float(reply, isend->gain_control()->internal_to_interface (isend->gain_control()->get_value()));
lo_message_add_int32(reply, p->active() ? 1 : 0);
}
}