diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc index 064ea7034a..ec37bf052c 100644 --- a/gtk2_ardour/editor_export_audio.cc +++ b/gtk2_ardour/editor_export_audio.cc @@ -127,7 +127,7 @@ Editor::measure_master_loudness (bool range_selection) float prev_gain = _session->master_volume()->get_value(); _session->master_volume ()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup); - LoudnessDialog ld (_session, ar); + LoudnessDialog ld (_session, ar, range_selection); if (ld.run () == RESPONSE_APPLY) { _session->master_volume ()->set_value (dB_to_coefficient (ld.gain_db ()), Controllable::NoGroup); diff --git a/gtk2_ardour/loudness_dialog.cc b/gtk2_ardour/loudness_dialog.cc index 36747db2b3..d7d40e3c4d 100644 --- a/gtk2_ardour/loudness_dialog.cc +++ b/gtk2_ardour/loudness_dialog.cc @@ -30,6 +30,8 @@ #include "ardour/export_status.h" #include "ardour/export_timespan.h" +#include "widgets/ardour_spacer.h" + #include "export_report.h" #include "loudness_dialog.h" @@ -37,80 +39,134 @@ using namespace Gtk; using namespace ARDOUR; +using namespace ArdourWidgets; -LoudnessDialog::LoudnessDialog (Session* s, AudioRange const& ar) +LoudnessDialog::LoudnessDialog (Session* s, AudioRange const& ar, bool as) : ArdourDialog (_("Loudness Mate")) , _session (s) , _range (ar) , _status (s->get_export_status ()) - , _report_button (_("Show")) + , _autostart (as) + , _rt_analysis_button (_("Realtime"), ArdourButton::led_default_elements, true) + , _start_analysis_button (_("Analyze")) + , _show_report_button (_("Show Detailed Report")) , _dbfs_adjustment ( 0.00, -90.00, 0.00, 0.1, 0.2) , _dbtp_adjustment ( -1.0, -90.00, 0.00, 0.1, 0.2) - , _lufs_adjustment (-23.0, -90.00, 0.00, 0.1, 1.0) + , _lufs_i_adjustment (-23.0, -90.00, 0.00, 0.1, 1.0) + , _lufs_s_adjustment (-20.0, -90.00, 0.00, 0.1, 1.0) + , _lufs_m_adjustment (-17.0, -90.00, 0.00, 0.1, 1.0) , _dbfs_spinbutton (_dbfs_adjustment, 0.1, 1) , _dbtp_spinbutton (_dbtp_adjustment, 0.1, 1) - , _lufs_spinbutton (_lufs_adjustment, 0.1, 1) + , _lufs_i_spinbutton (_lufs_i_adjustment, 0.1, 1) + , _lufs_s_spinbutton (_lufs_s_adjustment, 0.1, 1) + , _lufs_m_spinbutton (_lufs_m_adjustment, 0.1, 1) , _gain (0) { - Gtk::Label* l; - Gtk::Table* t = manage (new Table (8, 3, false)); + _start_analysis_button.set_name ("generic button"); + _rt_analysis_button.set_name ("generic button"); + _show_report_button.set_name ("generic button"); + + Label* l; + Table* t = manage (new Table (8, 3, false)); t->set_spacings (4); - l = manage (new Label (_("Measured"), Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER)); - l->set_use_markup (true); - t->attach (*l, 1, 2, 0, 1); - l = manage (new Label (_("Target"), Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER)); - l->set_use_markup (true); - t->attach (*l, 2, 3, 0, 1); - l = manage (new Label (_("Digital Peak:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, 1, 2); - l = manage (new Label (_("Analog Peak:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Analysis Results"), ALIGN_LEFT)); + l->set_use_markup (true); + t->attach (*l, 0, 1, 0, 1); + t->attach (_show_report_button, 1, 4, 0, 1); + + l = manage (new Label (_("Measured"), ALIGN_CENTER)); + l->set_use_markup (true); + t->attach (*l, 1, 2, 1, 2); + l = manage (new Label (_("Target"), ALIGN_CENTER)); + l->set_use_markup (true); + t->attach (*l, 2, 3, 1, 2); + l = manage (new Label (_("Delta"), ALIGN_CENTER)); + l->set_use_markup (true); + t->attach (*l, 3, 4, 1, 2); + + l = manage (new Label (_("Peak:"), ALIGN_LEFT)); t->attach (*l, 0, 1, 2, 3); - l = manage (new Label (_("Integrated Loudness:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("True Peak:"), ALIGN_LEFT)); t->attach (*l, 0, 1, 3, 4); - l = manage (new Label (_("Max. Short Loudness:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Integrated Loudness:"), ALIGN_LEFT)); t->attach (*l, 0, 1, 4, 5); - l = manage (new Label (_("Max. Momentary Loudness:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Max. Short Loudness:"), ALIGN_LEFT)); t->attach (*l, 0, 1, 5, 6); - l = manage (new Label (_("Detailed Report:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Max. Momentary Loudness:"), ALIGN_LEFT)); t->attach (*l, 0, 1, 6, 7); - l = manage (new Label (_("Suggested Gain:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, 7, 8); + l = manage (new Label (_("Suggested Gain:"), ALIGN_LEFT)); + t->attach (*l, 0, 1, 8, 9); - t->attach (_dbfs_label, 1, 2, 1, 2); - t->attach (_dbtp_label, 1, 2, 2, 3); - t->attach (_lufs_integrated_label, 1, 2, 3, 4); - t->attach (_lufs_short_label, 1, 2, 4, 5); - t->attach (_lufs_momentary_label, 1, 2, 5, 6); - t->attach (_report_button, 1, 2, 6, 7); - t->attach (_gain_label, 1, 2, 7, 8); + t->attach (_dbfs_label, 1, 2, 2, 3); + t->attach (_dbtp_label, 1, 2, 3, 4); + t->attach (_lufs_i_label, 1, 2, 4, 5); + t->attach (_lufs_s_label, 1, 2, 5, 6); + t->attach (_lufs_m_label, 1, 2, 6, 7); - t->attach (_dbfs_spinbutton, 2, 3, 1, 2); - t->attach (_dbtp_spinbutton, 2, 3, 2, 3); - t->attach (_lufs_spinbutton, 2, 3, 3, 4); + t->attach (_dbfs_spinbutton, 2, 3, 2, 3); + t->attach (_dbtp_spinbutton, 2, 3, 3, 4); + t->attach (_lufs_i_spinbutton, 2, 3, 4, 5); + t->attach (_lufs_s_spinbutton, 2, 3, 5, 6); + t->attach (_lufs_m_spinbutton, 2, 3, 6, 7); - _report_button.set_name ("generic button"); + t->attach (_delta_dbfs_label, 3, 4, 2, 3); + t->attach (_delta_dbtp_label, 3, 4, 3, 4); + t->attach (_delta_lufs_i_label, 3, 4, 4, 5); + t->attach (_delta_lufs_s_label, 3, 4, 5, 6); + t->attach (_delta_lufs_m_label, 3, 4, 6, 7); + + ArdourHSpacer* spc = manage (new ArdourHSpacer (1.0)); + t->attach (*spc , 1, 4, 7, 8); + t->attach (_gain_label, 3, 4, 8, 9); _result_box.pack_start (*t, false, false, 6); _progress_box.pack_start (_progress_bar, false, false, 6); + t = manage (new Table (2, 3, false)); + t->set_spacings (4); + l = manage (new Label ()); + l->set_line_wrap (); + l->set_markup (_( + "Loudness Analysis\n\n" + "This allows to analyze the loudness of of the signal at the master-bus " + "output of the complete session, as it would be exported.\n" + "The result an be used to interactively normalize the session's loudnless level " + "(as opposed to automatical normalization during export).\n" + "By default a faster than realtime export is is used to asses the loudness of the " + "session. If any outboard gear is used, a realtime export is available, to " + "play at normal speed.\n" + )); + t->attach (*l, 1, 4, 1, 2, EXPAND|FILL, EXPAND|FILL, 0, 8); + l = manage (new Label ("")); + t->attach (*l, 1, 2, 2, 3); + t->attach (_rt_analysis_button, 2, 3, 2, 3, FILL, SHRINK); + t->attach (_start_analysis_button, 3, 4, 2, 3, FILL, SHRINK); + _setup_box.pack_start (*t, false, false, 6); + + get_vbox()->pack_start (_setup_box); get_vbox()->pack_start (_progress_box); get_vbox()->pack_start (_result_box); get_vbox()->set_size_request(400,-1); - _ok_button = add_button (Gtk::Stock::APPLY, RESPONSE_APPLY); - _cancel_button = add_button (Gtk::Stock::CANCEL, RESPONSE_CANCEL); + _ok_button = add_button (Stock::APPLY, RESPONSE_APPLY); + _cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL); _cancel_button->signal_clicked().connect (sigc::mem_fun (this, &LoudnessDialog::cancel_analysis)); _dbfs_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); _dbtp_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); - _lufs_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); - _report_button.signal_clicked.connect (mem_fun (*this, &LoudnessDialog::display_report)); + _lufs_i_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); + _lufs_s_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); + _lufs_m_spinbutton.signal_value_changed().connect (mem_fun (*this, &LoudnessDialog::calculate_gain)); + _show_report_button.signal_clicked.connect (mem_fun (*this, &LoudnessDialog::display_report)); + _start_analysis_button.signal_clicked.connect (mem_fun (*this, &LoudnessDialog::start_analysis)); _ok_button->set_sensitive (false); - _report_button.set_sensitive (false); + _show_report_button.set_sensitive (false); show_all_children (); + _result_box.hide (); + _progress_box.hide (); } void @@ -121,6 +177,16 @@ LoudnessDialog::cancel_analysis () } } +void +LoudnessDialog::start_analysis () +{ + if (0 == analyze ()) { + display_results (); + } else { + _setup_box.show (); + } +} + bool LoudnessDialog::on_delete_event (GdkEventAny*) { @@ -131,23 +197,14 @@ LoudnessDialog::on_delete_event (GdkEventAny*) int LoudnessDialog::run () { -#if 1 - // TODO: consider interactive analysis "start" button, - // after settings, e.g. realtime export, IO select - show (); - switch (analyze ()) { - case 0: - /* OK */ + if (_autostart) { + show (); + if (0 == analyze ()) { display_results (); - break; - case 1: - /* aborted */ - return RESPONSE_CANCEL; - default: - // TODO show an ArdourMessageDialog here or in parent Editor::analyze_range_export + } else { return RESPONSE_CANCEL; + } } -#endif int const r = ArdourDialog::run (); cancel_analysis (); @@ -166,18 +223,11 @@ LoudnessDialog::progress_timeout () int LoudnessDialog::analyze () { - /* add master outs as default */ - IO* master_out = _session->master_out()->output().get(); - if (!master_out) { - return -1; - } - if (master_out->n_ports().n_audio() != 2) { - return -2; - } - - if (_range.start >= _range.end) { - return -3; - } + /* These are ensured in Editor::measure_master_loudness () */ + assert (_session->master_out()); + assert (_session->master_out()->output()); + assert (_session->master_out()->output()->n_ports().n_audio() == 2); + assert (_range.start < _range.end); ExportTimespanPtr tsp = _session->get_export_handler()->add_timespan(); @@ -196,12 +246,13 @@ LoudnessDialog::analyze () fmp->set_analyse (true); /* setup range */ - // TODO: consider multiple ranges tsp->set_range (_range.start, _range.end); tsp->set_range_id ("selection"); - tsp->set_realtime (false); + tsp->set_realtime (_rt_analysis_button.get_active ()); + tsp->set_name ("master"); /* setup channels, use master out */ + IO* master_out = _session->master_out()->output().get(); for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) { PortExportChannel * channel = new PortExportChannel (); channel->add_port (master_out->audio (n)); @@ -216,6 +267,14 @@ LoudnessDialog::analyze () _session->get_export_handler()->do_export(); /* show progress */ + _setup_box.hide (); + _progress_box.show_all (); + + /* shrink window height (setup box) */ + Gtk::Requisition wr; + get_size (wr.width, wr.height); + resize (wr.width, 60); + sigc::connection progress_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &LoudnessDialog::progress_timeout), 100); while (_status->running ()) { @@ -236,8 +295,10 @@ LoudnessDialog::analyze () void LoudnessDialog::display_report () { + hide (); ExportReport er ("Export Loudness Report", _status->result_map); er.run(); + show (); } void @@ -247,33 +308,45 @@ LoudnessDialog::display_results () assert (ar.size () == 1); ExportAnalysisPtr p = ar.begin()->second; - _dbfs = accurate_coefficient_to_dB (p->peak); - _dbtp = accurate_coefficient_to_dB (p->truepeak); - _lufs = p->integrated_loudness; + _dbfs = accurate_coefficient_to_dB (p->peak); + _dbtp = accurate_coefficient_to_dB (p->truepeak); + _lufs_i = p->integrated_loudness; + _lufs_s = p->max_loudness_short; + _lufs_m = p->max_loudness_momentary; _dbfs_label.set_text (string_compose (_("%1 dBFS"), std::setprecision (1), std::fixed, _dbfs)); _dbtp_label.set_text (string_compose (_("%1 dBTP"), std::setprecision (1), std::fixed, _dbtp)); - _lufs_integrated_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, _lufs)); - _lufs_short_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, p->max_loudness_short)); - _lufs_momentary_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, p->max_loudness_momentary)); + _lufs_i_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, _lufs_i)); + _lufs_s_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, _lufs_s)); + _lufs_m_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, _lufs_m)); calculate_gain (); _result_box.show_all (); _ok_button->set_sensitive (true); - _report_button.set_sensitive (true); + _show_report_button.set_sensitive (true); } void LoudnessDialog::calculate_gain () { - float dbfs = _dbfs_spinbutton.get_value(); - float dbtp = _dbtp_spinbutton.get_value(); - float lufs = _lufs_spinbutton.get_value(); + float dbfs = _dbfs_spinbutton.get_value(); + float dbtp = _dbtp_spinbutton.get_value(); + float lufs_i = _lufs_i_spinbutton.get_value(); + float lufs_s = _lufs_s_spinbutton.get_value(); + float lufs_m = _lufs_m_spinbutton.get_value(); _gain = dbfs - _dbfs; _gain = std::min (_gain, dbtp - _dbtp); - _gain = std::min (_gain, lufs - _lufs); + _gain = std::min (_gain, lufs_i - _lufs_i); + _gain = std::min (_gain, lufs_s - _lufs_s); + _gain = std::min (_gain, lufs_m - _lufs_m); + + _delta_dbfs_label.set_text (string_compose (_("%1 dB"), std::setprecision (2), std::fixed, dbfs - _dbfs)); + _delta_dbtp_label.set_text (string_compose (_("%1 dB"), std::setprecision (2), std::fixed, dbtp - _dbtp)); + _delta_lufs_i_label.set_text (string_compose (_("%1 LU"), std::setprecision (2), std::fixed, lufs_i - _lufs_i)); + _delta_lufs_s_label.set_text (string_compose (_("%1 LU"), std::setprecision (2), std::fixed, lufs_s - _lufs_s)); + _delta_lufs_m_label.set_text (string_compose (_("%1 LU"), std::setprecision (2), std::fixed, lufs_m - _lufs_m)); _gain_label.set_text (string_compose (_("%1 dB"), std::setprecision (2), std::fixed, _gain)); } diff --git a/gtk2_ardour/loudness_dialog.h b/gtk2_ardour/loudness_dialog.h index 994de72a72..4aec71373f 100644 --- a/gtk2_ardour/loudness_dialog.h +++ b/gtk2_ardour/loudness_dialog.h @@ -36,7 +36,7 @@ namespace ARDOUR { class LoudnessDialog : public ArdourDialog { public: - LoudnessDialog (ARDOUR::Session*, ARDOUR::AudioRange const&); + LoudnessDialog (ARDOUR::Session*, ARDOUR::AudioRange const&, bool); int run (); float gain_db () const { return _gain; } @@ -45,6 +45,7 @@ protected: private: int analyze (); + void start_analysis (); void cancel_analysis (); gint progress_timeout (); void display_results (); @@ -54,7 +55,9 @@ private: ARDOUR::Session* _session; ARDOUR::AudioRange const& _range; boost::shared_ptr _status; + bool _autostart; + Gtk::VBox _setup_box; Gtk::VBox _progress_box; Gtk::VBox _result_box; Gtk::ProgressBar _progress_bar; @@ -63,23 +66,39 @@ private: Gtk::Label _dbfs_label; Gtk::Label _dbtp_label; - Gtk::Label _lufs_integrated_label; - Gtk::Label _lufs_short_label; - Gtk::Label _lufs_momentary_label; + Gtk::Label _lufs_i_label; + Gtk::Label _lufs_s_label; + Gtk::Label _lufs_m_label; + + Gtk::Label _delta_dbfs_label; + Gtk::Label _delta_dbtp_label; + Gtk::Label _delta_lufs_i_label; + Gtk::Label _delta_lufs_s_label; + Gtk::Label _delta_lufs_m_label; + + Gtk::Label _gain_label; - ArdourWidgets::ArdourButton _report_button; + ArdourWidgets::ArdourButton _rt_analysis_button; + ArdourWidgets::ArdourButton _start_analysis_button; + ArdourWidgets::ArdourButton _show_report_button; Gtk::Adjustment _dbfs_adjustment; Gtk::Adjustment _dbtp_adjustment; - Gtk::Adjustment _lufs_adjustment; + Gtk::Adjustment _lufs_i_adjustment; + Gtk::Adjustment _lufs_s_adjustment; + Gtk::Adjustment _lufs_m_adjustment; Gtk::SpinButton _dbfs_spinbutton; Gtk::SpinButton _dbtp_spinbutton; - Gtk::SpinButton _lufs_spinbutton; + Gtk::SpinButton _lufs_i_spinbutton; + Gtk::SpinButton _lufs_s_spinbutton; + Gtk::SpinButton _lufs_m_spinbutton; float _dbfs; float _dbtp; - float _lufs; + float _lufs_i; + float _lufs_s; + float _lufs_m; float _gain; };