From e9ff843bb12c7ca0d57551e2a03d2f13404195e1 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 27 Jul 2020 21:56:41 +0200 Subject: [PATCH] Implement master/loudness volume processor This provides for a better user-experience than using a-amp. Particularly since a-amp only has a 20dB range and can be automated. --- libs/ardour/amp.cc | 15 +++++++++- libs/ardour/ardour/route.h | 9 ++++++ libs/ardour/route.cc | 57 +++++++++++++++++++++++++++++++++--- libs/ardour/session_state.cc | 9 ++---- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc index 4731ab376a..8d418c4351 100644 --- a/libs/ardour/amp.cc +++ b/libs/ardour/amp.cc @@ -334,7 +334,20 @@ XMLNode& Amp::state () { XMLNode& node (Processor::state ()); - node.set_property("type", _gain_control->parameter().type() == GainAutomation ? "amp" : "trim"); + switch (_gain_control->parameter().type()) { + case GainAutomation: + node.set_property("type", "amp"); + break; + case TrimAutomation: + node.set_property("type", "trim"); + break; + case MainOutVolume: + node.set_property("type", "main-volume"); + break; + default: + assert (0); + break; + } node.add_child_nocopy (_gain_control->get_state()); return node; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 1d309d0970..e027990452 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -503,6 +503,12 @@ public: boost::shared_ptr volume_control() const; boost::shared_ptr phase_control() const; + void set_volume_applies_to_output (bool); + + bool volume_applies_to_output () const { + return _volume_applies_to_output; + } + /** Return the first processor that accepts has at least one MIDI input and at least one audio output. In the vast majority of cases, this @@ -687,9 +693,12 @@ protected: boost::shared_ptr _phase_control; boost::shared_ptr _amp; boost::shared_ptr _trim; + boost::shared_ptr _volume; boost::shared_ptr _meter; boost::shared_ptr _polarity; + bool _volume_applies_to_output; + boost::shared_ptr _delayline; bool is_internal_processor (boost::shared_ptr) const; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 767948c60d..41b36723be 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -125,6 +125,7 @@ Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType , _default_type (default_type) , _instrument_fanned_out (false) , _loop_location (NULL) + , _volume_applies_to_output (true) , _track_number (0) , _strict_io (false) , _in_configure_processors (false) @@ -256,9 +257,10 @@ Route::init () if (is_master()) { _volume_control.reset (new GainControl (_session, MainOutVolume)); _volume_control->set_flag (Controllable::NotAutomatable); - if (Config->get_use_master_volume ()) { - _main_outs->add_gain (_volume_control); - } + _main_outs->add_gain (_volume_control); + _volume.reset (new Amp (_session, X_("Volume Ctrl"), _volume_control, false)); + _volume->set_display_to_user (false); + _volume->deactivate (); } _main_outs->activate (); @@ -1394,7 +1396,7 @@ Route::clear_processors (Placement p) bool Route::is_internal_processor (boost::shared_ptr p) const { - if (p == _amp || p == _meter || p == _main_outs || p == _delayline || p == _trim || p == _polarity) { + if (p == _amp || p == _meter || p == _main_outs || p == _delayline || p == _trim || p == _polarity || (_volume && p == _volume)) { return true; } #ifdef MIXBUS @@ -2508,6 +2510,10 @@ Route::state (bool save_template) node->set_property (X_("default-type"), _default_type); node->set_property (X_("strict-io"), _strict_io); + if (is_master ()) { + node->set_property (X_("volume-applies-to-output"), _volume_applies_to_output); + } + node->add_child_nocopy (_presentation_info.get_state()); node->set_property (X_("active"), _active); @@ -2705,6 +2711,19 @@ Route::set_state (const XMLNode& node, int version) _initial_io_setup = false; + if (is_master ()) { + node.get_property (X_("volume-applies-to-output"), _volume_applies_to_output); + if (_volume_applies_to_output) { + _volume->deactivate (); + _volume->set_display_to_user (false); + main_outs()->add_gain (_volume_control); + } else { + _volume->set_display_to_user (true); + _volume->activate (); + main_outs()->add_gain (boost::shared_ptr ()); + } + } + set_processor_state (processor_state, version); // this looks up the internal instrument in processors @@ -3043,6 +3062,10 @@ Route::set_processor_state (const XMLNode& node, int version) } else if (prop->value() == "trim") { _trim->set_state (**niter, version); new_order.push_back (_trim); + } else if (prop->value() == "main-volume") { + assert (is_master ()); + _volume->set_state (**niter, version); + new_order.push_back (_volume); } else if (prop->value() == "meter") { _meter->set_state (**niter, version); new_order.push_back (_meter); @@ -4638,6 +4661,32 @@ Route::phase_control() const return _phase_control; } +void +Route::set_volume_applies_to_output (bool en) +{ + if (!is_master () || _volume_applies_to_output == en) { + return; + } + if (en) { + _volume->deactivate (); + _volume->set_display_to_user (false); + main_outs()->add_gain (_volume_control); + { + /* remove hidden processor */ + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + configure_processors (NULL); + } + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + } else { + _volume->set_display_to_user (true); + add_processor (_volume, PostFader, NULL, true); + _volume->activate (); + main_outs()->add_gain (boost::shared_ptr ()); + } + _volume_applies_to_output = en; + _session.set_dirty (); +} + boost::shared_ptr Route::get_control (const Evoral::Parameter& param) { diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 224bc57bf3..18bb76e464 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -4237,12 +4237,9 @@ Session::config_changed (std::string p, bool ours) last_loopend = 0; /* force locate to refill buffers with new loop boundary data */ auto_loop_changed (_locations->auto_loop_location()); } else if (p == "use-master-volume") { - if (master_volume ()) { - bool en = Config->get_use_master_volume (); - _master_out->main_outs()->add_gain (en ? master_volume () : boost::shared_ptr ()); - if (!en) { - master_volume ()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup); - } + if (master_volume () && !Config->get_use_master_volume ()) { + _master_out->set_volume_applies_to_output (true); + master_volume ()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup); } }