From 836693036a51965721fd2d86847bd8af64863158 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 13 Aug 2016 14:50:59 +0200 Subject: add RMS region normalization option --- gtk2_ardour/editor_ops.cc | 50 ++++++++++++++++++++-------- gtk2_ardour/normalize_dialog.cc | 72 ++++++++++++++++++++++++++++++++--------- gtk2_ardour/normalize_dialog.h | 11 +++++-- 3 files changed, 102 insertions(+), 31 deletions(-) diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index c208e55165..2741f66d4d 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5032,25 +5032,36 @@ Editor::normalize_region () obtain the maximum amplitude of them all. */ list max_amps; + list rms_vals; double max_amp = 0; + double max_rms = 0; + bool use_rms = dialog.constrain_rms (); + for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) { AudioRegionView const * arv = dynamic_cast (*i); - if (arv) { - dialog.descend (1.0 / regions); - double const a = arv->audio_region()->maximum_amplitude (&dialog); - - if (a == -1) { - /* the user cancelled the operation */ - return; - } + if (!arv) { + continue; + } + dialog.descend (1.0 / regions); + double const a = arv->audio_region()->maximum_amplitude (&dialog); + if (use_rms) { + double r = arv->audio_region()->rms (&dialog); + max_rms = max (max_rms, r); + rms_vals.push_back (r); + } - max_amps.push_back (a); - max_amp = max (max_amp, a); - dialog.ascend (); + if (a == -1) { + /* the user cancelled the operation */ + return; } + + max_amps.push_back (a); + max_amp = max (max_amp, a); + dialog.ascend (); } list::const_iterator a = max_amps.begin (); + list::const_iterator l = rms_vals.begin (); bool in_command = false; for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { @@ -5061,9 +5072,21 @@ Editor::normalize_region () arv->region()->clear_changes (); - double const amp = dialog.normalize_individually() ? *a : max_amp; + double amp = dialog.normalize_individually() ? *a : max_amp; + double target = dialog.target_peak (); // dB + + if (use_rms) { + double const amp_rms = dialog.normalize_individually() ? *l : max_rms; + const double t_rms = dialog.target_rms (); + const gain_t c_peak = dB_to_coefficient (target); + const gain_t c_rms = dB_to_coefficient (t_rms); + if ((amp_rms / c_rms) > (amp / c_peak)) { + amp = amp_rms; + target = t_rms; + } + } - arv->audio_region()->normalize (amp, dialog.target ()); + arv->audio_region()->normalize (amp, target); if (!in_command) { begin_reversible_command (_("normalize")); @@ -5072,6 +5095,7 @@ Editor::normalize_region () _session->add_command (new StatefulDiffCommand (arv->region())); ++a; + ++l; } if (in_command) { diff --git a/gtk2_ardour/normalize_dialog.cc b/gtk2_ardour/normalize_dialog.cc index 85b7b0bc29..929f11c54a 100644 --- a/gtk2_ardour/normalize_dialog.cc +++ b/gtk2_ardour/normalize_dialog.cc @@ -17,6 +17,7 @@ */ +#include #include #include #include @@ -28,7 +29,9 @@ using namespace Gtk; double NormalizeDialog::_last_normalization_value = 0; +double NormalizeDialog::_last_rms_target_value = -9; bool NormalizeDialog::_last_normalize_individually = true; +bool NormalizeDialog::_last_constrain_rms = false; NormalizeDialog::NormalizeDialog (bool more_than_one) : ArdourDialog (more_than_one ? _("Normalize regions") : _("Normalize region")) @@ -36,18 +39,32 @@ NormalizeDialog::NormalizeDialog (bool more_than_one) { get_vbox()->set_spacing (12); - HBox* hbox = manage (new HBox); - hbox->set_spacing (6); - hbox->set_border_width (6); - hbox->pack_start (*manage (new Label (_("Normalize to:"))), false, false); - _spin = manage (new SpinButton (0.2, 2)); - _spin->set_range (-112, 0); - _spin->set_increments (0.1, 1); - _spin->set_value (_last_normalization_value); - _spin->set_activates_default (); - hbox->pack_start (*_spin, false, false); - hbox->pack_start (*manage (new Label (_("dBFS"))), false, false); - get_vbox()->pack_start (*hbox); + Table* tbl = manage (new Table); + tbl->set_spacings (6); + tbl->set_border_width (6); + + _spin_peak = manage (new SpinButton (0.2, 2)); + _spin_peak->set_range (-112, 0); + _spin_peak->set_increments (0.1, 1); + _spin_peak->set_value (_last_normalization_value); + _spin_peak->set_activates_default (); + + _constrain_rms = manage (new CheckButton (_("Constrain RMS to:"))); + _constrain_rms->set_active (_last_constrain_rms); + _spin_rms = manage (new SpinButton (0.2, 2)); + _spin_rms->set_range (-112, 0); + _spin_rms->set_increments (0.1, 1); + _spin_rms->set_value (_last_rms_target_value); + + tbl->attach (*manage (new Label (_("Normalize to:"), ALIGN_END)), 0, 1, 0, 1, FILL, SHRINK); + tbl->attach (*_spin_peak, 1, 2, 0, 1, SHRINK, SHRINK); + tbl->attach (*manage (new Label (_("dBFS"))), 2, 3, 0, 1, SHRINK, SHRINK); + + tbl->attach (*_constrain_rms, 0, 1, 1, 2, SHRINK, SHRINK); + tbl->attach (*_spin_rms, 1, 2, 1, 2, SHRINK, SHRINK); + tbl->attach (*manage (new Label (_("dBFS"))), 2, 3, 1, 2, SHRINK, SHRINK); + + get_vbox()->pack_start (*tbl); if (more_than_one) { RadioButtonGroup group; @@ -67,15 +84,24 @@ NormalizeDialog::NormalizeDialog (bool more_than_one) _progress_bar = manage (new ProgressBar); get_vbox()->pack_start (*_progress_bar); + update_sensitivity (); show_all (); + _progress_bar->hide (); add_button (Stock::CANCEL, RESPONSE_CANCEL); add_button (_("Normalize"), RESPONSE_ACCEPT); set_default_response (RESPONSE_ACCEPT); + _constrain_rms->signal_toggled ().connect (sigc::mem_fun (*this, &NormalizeDialog::update_sensitivity)); signal_response().connect (sigc::mem_fun (*this, &NormalizeDialog::button_clicked)); } +void +NormalizeDialog::update_sensitivity () +{ + _spin_rms->set_sensitive (constrain_rms ()); +} + bool NormalizeDialog::normalize_individually () const { @@ -86,10 +112,22 @@ NormalizeDialog::normalize_individually () const return _normalize_individually->get_active (); } +bool +NormalizeDialog::constrain_rms () const +{ + return _constrain_rms->get_active (); +} + double -NormalizeDialog::target () const +NormalizeDialog::target_peak () const { - return _spin->get_value (); + return _spin_peak->get_value (); +} + +double +NormalizeDialog::target_rms () const +{ + return _spin_rms->get_value (); } void @@ -98,7 +136,7 @@ NormalizeDialog::update_progress_gui (float p) /* Normalization is run inside the GUI thread, so we can directly * update the progress bar when notified about progress. */ - + _progress_bar->show (); _progress_bar->set_fraction (p); } @@ -106,7 +144,9 @@ int NormalizeDialog::run () { int const r = ArdourDialog::run (); - _last_normalization_value = target (); + _last_normalization_value = target_peak (); + _last_rms_target_value = target_rms (); + _last_constrain_rms = constrain_rms (); if (_normalize_individually) { _last_normalize_individually = _normalize_individually->get_active (); } diff --git a/gtk2_ardour/normalize_dialog.h b/gtk2_ardour/normalize_dialog.h index 71ca030416..53b9e71b37 100644 --- a/gtk2_ardour/normalize_dialog.h +++ b/gtk2_ardour/normalize_dialog.h @@ -32,17 +32,24 @@ public: NormalizeDialog (bool); bool normalize_individually () const; - double target () const; + bool constrain_rms () const; + double target_peak () const; + double target_rms () const; int run (); private: void update_progress_gui (float); void button_clicked (int); + void update_sensitivity (); Gtk::RadioButton* _normalize_individually; - Gtk::SpinButton* _spin; + Gtk::CheckButton* _constrain_rms; + Gtk::SpinButton* _spin_peak; + Gtk::SpinButton* _spin_rms; Gtk::ProgressBar* _progress_bar; static double _last_normalization_value; + static double _last_rms_target_value; static bool _last_normalize_individually; + static bool _last_constrain_rms; }; -- cgit v1.2.3