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.
This commit is contained in:
Robin Gareus 2020-07-27 21:56:41 +02:00
parent 5b734e819c
commit e9ff843bb1
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
4 changed files with 79 additions and 11 deletions

View File

@ -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;

View File

@ -503,6 +503,12 @@ public:
boost::shared_ptr<GainControl> volume_control() const;
boost::shared_ptr<PhaseControl> 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<PhaseControl> _phase_control;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<Amp> _trim;
boost::shared_ptr<Amp> _volume;
boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<PolarityProcessor> _polarity;
bool _volume_applies_to_output;
boost::shared_ptr<DelayLine> _delayline;
bool is_internal_processor (boost::shared_ptr<Processor>) const;

View File

@ -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<Processor> 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<GainControl> ());
}
}
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<GainControl> ());
}
_volume_applies_to_output = en;
_session.set_dirty ();
}
boost::shared_ptr<AutomationControl>
Route::get_control (const Evoral::Parameter& param)
{

View File

@ -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<GainControl> ());
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);
}
}