Initial prototype for session loudness #8318
This commit is contained in:
@@ -1975,6 +1975,9 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
|
||||
edit_items.push_back (MenuElem (_("Bounce Range to Source List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
|
||||
edit_items.push_back (MenuElem (_("Bounce Range to Source List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
|
||||
edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
|
||||
#ifndef NDEBUG // debug builds only, so far
|
||||
edit_items.push_back (MenuElem (_("Export Analyze Range..."), sigc::mem_fun(*this, &Editor::analyze_range_export)));
|
||||
#endif
|
||||
if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
|
||||
edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
|
||||
}
|
||||
|
||||
@@ -308,6 +308,7 @@ public:
|
||||
void export_selection ();
|
||||
void export_range ();
|
||||
void export_region ();
|
||||
void analyze_range_export ();
|
||||
|
||||
bool process_midi_export_dialog (MidiExportDialog& dialog, boost::shared_ptr<ARDOUR::MidiRegion> midi_region);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "ardour/audioplaylist.h"
|
||||
#include "ardour/audioregion.h"
|
||||
#include "ardour/chan_count.h"
|
||||
#include "ardour/lua_api.h"
|
||||
#include "ardour/midi_region.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/session_directory.h"
|
||||
@@ -50,6 +51,7 @@
|
||||
#include "audio_time_axis.h"
|
||||
#include "editor.h"
|
||||
#include "export_dialog.h"
|
||||
#include "loudness_dialog.h"
|
||||
#include "midi_export_dialog.h"
|
||||
#include "midi_region_view.h"
|
||||
#include "public_editor.h"
|
||||
@@ -88,6 +90,22 @@ Editor::export_selection ()
|
||||
dialog.run();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::analyze_range_export ()
|
||||
{
|
||||
LoudnessDialog ld (_session, get_selection().time);
|
||||
|
||||
if (ld.run () == RESPONSE_APPLY) {
|
||||
// TODO lookup if already present, perhaps even use a special-cased gain plugin
|
||||
// if plugin is present, use relative gain (and disable automation..)
|
||||
boost::shared_ptr<Processor> proc = LuaAPI::new_luaproc (_session, "a-Amplifier");
|
||||
assert (proc);
|
||||
assert (_session->master_out());
|
||||
LuaAPI::set_processor_param (proc, 0, ld.gain ());
|
||||
_session->master_out()->add_processor_by_index (proc, -1, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::export_range ()
|
||||
{
|
||||
|
||||
265
gtk2_ardour/loudness_dialog.cc
Normal file
265
gtk2_ardour/loudness_dialog.cc
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/stock.h>
|
||||
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/dB.h"
|
||||
|
||||
#include "ardour/export_channel_configuration.h"
|
||||
#include "ardour/export_filename.h"
|
||||
#include "ardour/export_format_base.h"
|
||||
#include "ardour/export_format_specification.h"
|
||||
#include "ardour/export_handler.h"
|
||||
#include "ardour/export_status.h"
|
||||
#include "ardour/export_timespan.h"
|
||||
|
||||
#include "export_report.h"
|
||||
#include "loudness_dialog.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace Gtk;
|
||||
using namespace ARDOUR;
|
||||
|
||||
LoudnessDialog::LoudnessDialog (Session* s, TimeSelection const& ts)
|
||||
: ArdourDialog (_("Loudness Mate"))
|
||||
, _session (s)
|
||||
, _time (ts)
|
||||
, _status (s->get_export_status ())
|
||||
, _report_button (_("Show"))
|
||||
, _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)
|
||||
, _dbfs_spinbutton (_dbfs_adjustment, 0.1, 1)
|
||||
, _dbtp_spinbutton (_dbtp_adjustment, 0.1, 1)
|
||||
, _lufs_spinbutton (_lufs_adjustment, 0.1, 1)
|
||||
, _gain (0)
|
||||
{
|
||||
Gtk::Label* l;
|
||||
Gtk::Table* t = manage (new Table (5, 3, false));
|
||||
t->set_spacings (4);
|
||||
l = manage (new Label (_("Digital Peak:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
t->attach (*l, 0, 1, 0, 1);
|
||||
l = manage (new Label (_("Analog Peak:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
t->attach (*l, 0, 1, 1, 2);
|
||||
l = manage (new Label (_("Loudness:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
t->attach (*l, 0, 1, 2, 3);
|
||||
l = manage (new Label (_("Detailed Report:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
t->attach (*l, 0, 1, 3, 4);
|
||||
l = manage (new Label (_("Suggested Gain:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
|
||||
t->attach (*l, 0, 1, 4, 5);
|
||||
|
||||
t->attach (_dbfs_label, 1, 2, 0, 1);
|
||||
t->attach (_dbtp_label, 1, 2, 1, 2);
|
||||
t->attach (_lufs_label, 1, 2, 2, 3);
|
||||
t->attach (_report_button, 1, 2, 3, 4);
|
||||
|
||||
t->attach (_dbfs_spinbutton, 2, 3, 0, 1);
|
||||
t->attach (_dbtp_spinbutton, 2, 3, 1, 2);
|
||||
t->attach (_lufs_spinbutton, 2, 3, 2, 3);
|
||||
|
||||
t->attach (_gain_label, 1, 2, 4, 5);
|
||||
|
||||
_report_button.set_name ("generic button");
|
||||
|
||||
_result_box.pack_start (*t, false, false, 6);
|
||||
_progress_box.pack_start (_progress_bar, false, false, 6);
|
||||
|
||||
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);
|
||||
|
||||
_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));
|
||||
|
||||
_ok_button->set_sensitive (false);
|
||||
_report_button.set_sensitive (false);
|
||||
show_all_children ();
|
||||
_result_box.hide ();
|
||||
}
|
||||
|
||||
void
|
||||
LoudnessDialog::cancel_analysis ()
|
||||
{
|
||||
if (_status->running ()) {
|
||||
_status->abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LoudnessDialog::on_delete_event (GdkEventAny*)
|
||||
{
|
||||
cancel_analysis ();
|
||||
return true;
|
||||
}
|
||||
|
||||
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 */
|
||||
display_results ();
|
||||
break;
|
||||
case 1:
|
||||
/* aborted */
|
||||
return RESPONSE_CANCEL;
|
||||
default:
|
||||
// TODO show an ArdourMessageDialog here or in parent Editor::analyze_range_export
|
||||
return RESPONSE_CANCEL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int const r = ArdourDialog::run ();
|
||||
cancel_analysis ();
|
||||
return r;
|
||||
}
|
||||
|
||||
gint
|
||||
LoudnessDialog::progress_timeout ()
|
||||
{
|
||||
float progress = ((float) _status->processed_samples_current_timespan) / _status->total_samples_current_timespan;
|
||||
_progress_bar.set_text ("Analyzing");
|
||||
_progress_bar.set_fraction (progress);
|
||||
return true;
|
||||
}
|
||||
|
||||
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 (_time.empty()) {
|
||||
// use whole session ?!
|
||||
return -3;
|
||||
}
|
||||
|
||||
ExportTimespanPtr tsp = _session->get_export_handler()->add_timespan();
|
||||
|
||||
boost::shared_ptr<ExportChannelConfiguration> ccp = _session->get_export_handler()->add_channel_config();
|
||||
boost::shared_ptr<ARDOUR::ExportFilename> fnp = _session->get_export_handler()->add_filename();
|
||||
boost::shared_ptr<ExportFormatSpecification> fmp = _session->get_export_handler()->add_format();
|
||||
|
||||
/* setup format */
|
||||
fmp->set_tag (false);
|
||||
fmp->set_sample_format (ExportFormatBase::SF_Float);
|
||||
fmp->set_sample_rate (ExportFormatBase::SR_Session);
|
||||
fmp->set_format_id (ExportFormatBase::F_None);
|
||||
fmp->set_type (ExportFormatBase::T_None);
|
||||
fmp->set_extension ("wav");
|
||||
fmp->set_soundcloud_upload (false);
|
||||
fmp->set_analyse (true);
|
||||
|
||||
/* setup range */
|
||||
// TODO: consider multiple ranges
|
||||
tsp->set_range (_time.front().start, _time.front().end);
|
||||
tsp->set_range_id ("selection");
|
||||
tsp->set_realtime (false);
|
||||
|
||||
/* setup channels, use master out */
|
||||
for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) {
|
||||
PortExportChannel * channel = new PortExportChannel ();
|
||||
channel->add_port (master_out->audio (n));
|
||||
ExportChannelPtr chan_ptr (channel);
|
||||
ccp->register_channel (chan_ptr);
|
||||
}
|
||||
|
||||
/* do audio export */
|
||||
boost::shared_ptr<AudioGrapher::BroadcastInfo> b;
|
||||
_session->get_export_handler()->reset ();
|
||||
_session->get_export_handler()->add_export_config (tsp, ccp, fmp, fnp, b);
|
||||
_session->get_export_handler()->do_export();
|
||||
|
||||
/* show progress */
|
||||
sigc::connection progress_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &LoudnessDialog::progress_timeout), 100);
|
||||
|
||||
while (_status->running ()) {
|
||||
if (gtk_events_pending()) {
|
||||
gtk_main_iteration ();
|
||||
} else {
|
||||
Glib::usleep (10000);
|
||||
}
|
||||
}
|
||||
progress_connection.disconnect();
|
||||
_progress_box.hide_all ();
|
||||
|
||||
/* done */
|
||||
_status->finish (TRS_UI);
|
||||
return _status->aborted() ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
LoudnessDialog::display_report ()
|
||||
{
|
||||
ExportReport er ("Export Loudness Report", _status->result_map);
|
||||
er.run();
|
||||
}
|
||||
|
||||
void
|
||||
LoudnessDialog::display_results ()
|
||||
{
|
||||
AnalysisResults const& ar (_status->result_map);
|
||||
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->loudness;
|
||||
|
||||
_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_label.set_text (string_compose (_("%1 LUFS"), std::setprecision (1), std::fixed, _lufs));
|
||||
|
||||
calculate_gain ();
|
||||
|
||||
_result_box.show_all ();
|
||||
_ok_button->set_sensitive (true);
|
||||
_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();
|
||||
|
||||
_gain = dbfs - _dbfs;
|
||||
_gain = std::min (_gain, dbtp - _dbtp);
|
||||
_gain = std::min (_gain, lufs - _lufs);
|
||||
|
||||
_gain_label.set_text (string_compose (_("%1 dB"), std::setprecision (2), std::fixed, _gain));
|
||||
}
|
||||
83
gtk2_ardour/loudness_dialog.h
Normal file
83
gtk2_ardour/loudness_dialog.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/progressbar.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/table.h>
|
||||
|
||||
#include "widgets/ardour_button.h"
|
||||
|
||||
#include "ardour_dialog.h"
|
||||
#include "progress_reporter.h"
|
||||
#include "time_selection.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class ExportStatus;
|
||||
class Session;
|
||||
}
|
||||
|
||||
class LoudnessDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
LoudnessDialog (ARDOUR::Session*, TimeSelection const&);
|
||||
int run ();
|
||||
float gain () const { return _gain; }
|
||||
|
||||
protected:
|
||||
bool on_delete_event (GdkEventAny*);
|
||||
|
||||
private:
|
||||
int analyze ();
|
||||
void cancel_analysis ();
|
||||
gint progress_timeout ();
|
||||
void display_results ();
|
||||
void display_report ();
|
||||
void calculate_gain ();
|
||||
|
||||
ARDOUR::Session* _session;
|
||||
TimeSelection const& _time;
|
||||
boost::shared_ptr<ARDOUR::ExportStatus> _status;
|
||||
|
||||
Gtk::VBox _progress_box;
|
||||
Gtk::VBox _result_box;
|
||||
Gtk::ProgressBar _progress_bar;
|
||||
Gtk::Button* _ok_button;
|
||||
Gtk::Button* _cancel_button;
|
||||
|
||||
Gtk::Label _dbfs_label;
|
||||
Gtk::Label _dbtp_label;
|
||||
Gtk::Label _lufs_label;
|
||||
Gtk::Label _gain_label;
|
||||
|
||||
ArdourWidgets::ArdourButton _report_button;
|
||||
|
||||
Gtk::Adjustment _dbfs_adjustment;
|
||||
Gtk::Adjustment _dbtp_adjustment;
|
||||
Gtk::Adjustment _lufs_adjustment;
|
||||
|
||||
Gtk::SpinButton _dbfs_spinbutton;
|
||||
Gtk::SpinButton _dbtp_spinbutton;
|
||||
Gtk::SpinButton _lufs_spinbutton;
|
||||
|
||||
float _dbfs;
|
||||
float _dbtp;
|
||||
float _lufs;
|
||||
float _gain;
|
||||
};
|
||||
@@ -138,6 +138,7 @@ gtk2_ardour_sources = [
|
||||
'led.cc',
|
||||
'level_meter.cc',
|
||||
'location_ui.cc',
|
||||
'loudness_dialog.cc',
|
||||
'lua_script_manager.cc',
|
||||
'luadialog.cc',
|
||||
'luainstance.cc',
|
||||
|
||||
Reference in New Issue
Block a user