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
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
8 changed files with 100 additions and 66 deletions

View file

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

View file

@ -33,7 +33,6 @@
namespace ARDOUR { namespace ARDOUR {
class PeakMeter; class PeakMeter;
class Amp;
class GainControl; class GainControl;
class DelayLine; class DelayLine;
@ -73,9 +72,7 @@ public:
bool display_to_user() const; bool display_to_user() const;
bool is_foldback () const { return _role == Foldback; } 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<PeakMeter> meter() const { return _meter; }
boost::shared_ptr<GainControl> gain_control() const { return _gain_control; }
bool metering() const { return _metering; } bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; } void set_metering (bool yn) { _metering = yn; }
@ -117,8 +114,6 @@ protected:
XMLNode& state () const; XMLNode& state () const;
bool _metering; bool _metering;
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter; boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<DelayLine> _send_delay; boost::shared_ptr<DelayLine> _send_delay;
boost::shared_ptr<DelayLine> _thru_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; 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 */ /** Caller must hold process lock */
bool bool
Delivery::configure_io (ChanCount in, ChanCount out) Delivery::configure_io (ChanCount in, ChanCount out)
@ -233,11 +245,15 @@ Delivery::configure_io (ChanCount in, ChanCount out)
reset_panner (); reset_panner ();
if (_amp) {
return _amp->configure_io (in, out);
}
return true; return true;
} }
void 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); 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); _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. /* 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); _output->silence (nframes);
if (result_required) { 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); 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 // Panning
if (_panshell && !_panshell->bypassed() && _panshell->panner()) { if (_panshell && !_panshell->bypassed() && _panshell->panner()) {
@ -376,6 +399,11 @@ Delivery::state () const
node.add_child_nocopy (_panshell->unlinked_pannable()->get_state ()); 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) { if (_polarity_control) {
node.add_child_nocopy (_polarity_control->get_state()); 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); 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()) { if (_role == Listen && _session.monitor_out() && !_session.listening()) {
/* nobody is soloed, and this delivery is a listen-send to the /* nobody is soloed, and this delivery is a listen-send to the
@ -609,6 +633,24 @@ Delivery::target_gain ()
return desired_gain; return desired_gain;
} }
void
Delivery::activate ()
{
if (_amp) {
_amp->activate ();
}
Processor::activate ();
}
void
Delivery::deactivate ()
{
if (_amp) {
_amp->deactivate ();
}
Processor::deactivate ();
}
void void
Delivery::no_outs_cuz_we_no_monitor (bool yn) Delivery::no_outs_cuz_we_no_monitor (bool yn)
{ {

View file

@ -140,10 +140,10 @@ InternalSend::init_gain ()
{ {
if (_role == Listen) { if (_role == Listen) {
/* send to monitor bus is always at unity */ /* 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 { } else {
/* aux sends start at -inf dB */ /* 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 */ /* consider metering */
if (_metering) { if (_metering) {
if (_amp->gain_control ()->get_value () == GAIN_COEFF_ZERO) { if (gain_control ()->get_value () == GAIN_COEFF_ZERO) {
_meter->reset (); _meter->reset ();
} else { } else {
_meter->run (mixbufs, start_sample, end_sample, speed, nframes, true); _meter->run (mixbufs, start_sample, end_sample, speed, nframes, true);

View file

@ -266,7 +266,7 @@ Route::init ()
if (is_master()) { if (is_master()) {
_volume_control.reset (new GainControl (_session, MainOutVolume)); _volume_control.reset (new GainControl (_session, MainOutVolume));
_volume_control->set_flag (Controllable::NotAutomatable); _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.reset (new Amp (_session, X_("LAN Amp"), _volume_control, false));
_volume->set_display_to_user (false); _volume->set_display_to_user (false);
_volume->deactivate (); _volume->deactivate ();
@ -2770,11 +2770,11 @@ Route::set_state (const XMLNode& node, int version)
if (_volume_applies_to_output) { if (_volume_applies_to_output) {
_volume->deactivate (); _volume->deactivate ();
_volume->set_display_to_user (false); _volume->set_display_to_user (false);
main_outs()->add_gain (_volume_control); main_outs()->set_gain_control (_volume_control);
} else { } else {
_volume->set_display_to_user (true); _volume->set_display_to_user (true);
_volume->activate (); _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) { if (en) {
_volume->deactivate (); _volume->deactivate ();
_volume->set_display_to_user (false); _volume->set_display_to_user (false);
main_outs()->add_gain (_volume_control); main_outs()->set_gain_control (_volume_control);
{ {
/* remove hidden processor */ /* remove hidden processor */
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); 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); _volume->set_display_to_user (true);
add_processor (_volume, PostFader, NULL, true); add_processor (_volume, PostFader, NULL, true);
_volume->activate (); _volume->activate ();
main_outs()->add_gain (boost::shared_ptr<GainControl> ()); main_outs()->set_gain_control (boost::shared_ptr<GainControl> ());
} }
_volume_applies_to_output = en; _volume_applies_to_output = en;
_session.set_dirty (); _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_debug_shared_ptr_mark_interesting (this, "send");
boost::shared_ptr<AutomationList> gl (new AutomationList (Evoral::Parameter (BusSendLevel), time_domain())); 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)); set_gain_control (boost::shared_ptr<GainControl> (new GainControl (_session, Evoral::Parameter(BusSendLevel), gl)));
_gain_control->set_flag (Controllable::InlineControl);
add_control (_gain_control); 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())); _meter.reset (new PeakMeter (_session, name()));
_send_delay.reset (new DelayLine (_session, "Send-" + 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) { if (_role == Delivery::Aux || _role == Delivery::Send) {
_polarity_control = boost::shared_ptr<AutomationControl> (new AutomationControl (_session, PhaseAutomation, ParameterDescriptor (PhaseAutomation), 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")));
boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(PhaseAutomation), time_domain())), add_control (polarity_control ());
"polarity-invert"));
//_polarity_control->set_flag (Controllable::InlineControl);
add_control (_polarity_control);
} }
if (panner_shell()) { if (panner_shell()) {
@ -134,20 +131,18 @@ Send::~Send ()
void void
Send::activate () Send::activate ()
{ {
_amp->activate ();
_meter->activate (); _meter->activate ();
Processor::activate (); Delivery::activate ();
} }
void void
Send::deactivate () Send::deactivate ()
{ {
_amp->deactivate ();
_meter->deactivate (); _meter->deactivate ();
_meter->reset (); _meter->reset ();
Processor::deactivate (); Delivery::deactivate ();
} }
samplecnt_t samplecnt_t
@ -257,22 +252,16 @@ Send::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, do
sendbufs.read_from (bufs, nframes); sendbufs.read_from (bufs, nframes);
assert(sendbufs.count() == bufs.count()); 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); _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); Delivery::run (sendbufs, start_sample, end_sample, speed, nframes, true);
/* consider metering */ /* consider metering */
if (_metering) { if (_metering) {
if (_amp->gain_control()->get_value() == 0) { if (gain_control()->get_value() == 0) {
_meter->reset(); _meter->reset();
} else { } else {
_meter->run (*_output_buffers, start_sample, end_sample, speed, nframes, true); _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.set_property ("selfdestruct", _remove_on_disconnect);
node.add_child_nocopy (_gain_control->get_state()); node.add_child_nocopy (gain_control ()->get_state());
return node; return node;
} }
@ -317,7 +306,7 @@ Send::set_state (const XMLNode& node, int version)
/* old versions had a single Controllable only, and it was /* old versions had a single Controllable only, and it was
* not always a "gaincontrol" * not always a "gaincontrol"
*/ */
_gain_control->set_state (*i, version); gain_control()->set_state (*i, version);
break; break;
} }
@ -326,7 +315,7 @@ Send::set_state (const XMLNode& node, int version)
continue; continue;
} }
if (control_name == "gaincontrol" /* gain_control_name (BusSendLevel) */) { if (control_name == "gaincontrol" /* gain_control_name (BusSendLevel) */) {
_gain_control->set_state (*i, version); gain_control ()->set_state (*i, version);
break; break;
} }
} }
@ -347,8 +336,8 @@ Send::set_state (const XMLNode& node, int version)
XMLNode* gain_node; XMLNode* gain_node;
nn = processor; nn = processor;
if ((gain_node = nn->child (Controllable::xml_node_name.c_str ())) != 0) { if ((gain_node = nn->child (Controllable::xml_node_name.c_str ())) != 0) {
_gain_control->set_state (*gain_node, version); gain_control ()->set_state (*gain_node, version);
_gain_control->set_flags (Controllable::InlineControl); gain_control ()->set_flags (Controllable::InlineControl);
} }
} }
} }
@ -385,7 +374,7 @@ Send::set_state (const XMLNode& node, int version)
} }
XMLNode xn (**i); XMLNode xn (**i);
xn.set_property ("automation-id", EventTypeMap::instance().to_symbol(Evoral::Parameter (BusSendLevel))); 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; break;
} }
} }
@ -508,11 +497,7 @@ Send::configure_io (ChanCount in, ChanCount out)
ChanCount send_count = in; ChanCount send_count = in;
send_count.set(DataType::AUDIO, pan_outs()); send_count.set(DataType::AUDIO, pan_outs());
if (!_amp->configure_io (in, out)) { if (!Delivery::configure_io (in, out)) {
return false;
}
if (!Processor::configure_io (in, out)) {
return false; 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) { 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) { 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((s = (*i)->internal_send_for (dest)) != 0) { 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_int32(reply, get_sid(isend->target_route(), get_address(msg)));
lo_message_add_string(reply, isend->name().c_str()); lo_message_add_string(reply, isend->name().c_str());
lo_message_add_int32(reply, i); lo_message_add_int32(reply, i);
boost::shared_ptr<Amp> a = isend->amp(); lo_message_add_float(reply, isend->gain_control()->internal_to_interface (isend->gain_control()->get_value()));
lo_message_add_float(reply, a->gain_control()->internal_to_interface (a->gain_control()->get_value()));
lo_message_add_int32(reply, p->active() ? 1 : 0); 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); boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (p);
if (isend) { if (isend) {
if( isend->target_route()->id() == r->id()){ 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_int32(reply, get_sid(tr, get_address(msg)));
lo_message_add_string(reply, tr->name().c_str()); lo_message_add_string(reply, tr->name().c_str());
lo_message_add_int32(reply, j); 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); lo_message_add_int32(reply, p->active() ? 1 : 0);
} }
} }