summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2016-05-02 15:28:16 +0200
committerRobin Gareus <robin@gareus.org>2016-05-02 15:44:13 +0200
commitd01cb7910faddbf13b7190ceca990a2cafb71f95 (patch)
tree1d246b6590538ff70621fc28e42445eaa39d4816 /libs
parent7547f02c07875ba053e1c095e542f85291d7af5f (diff)
Add loudness normalization to Export Format & Graph
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/export_format_manager.h5
-rw-r--r--libs/ardour/ardour/export_format_specification.h15
-rw-r--r--libs/ardour/ardour/export_graph_builder.h5
-rw-r--r--libs/ardour/export_format_manager.cc25
-rw-r--r--libs/ardour/export_format_specification.cc61
-rw-r--r--libs/ardour/export_graph_builder.cc30
6 files changed, 124 insertions, 17 deletions
diff --git a/libs/ardour/ardour/export_format_manager.h b/libs/ardour/ardour/export_format_manager.h
index fff97299e5..5a78708efb 100644
--- a/libs/ardour/ardour/export_format_manager.h
+++ b/libs/ardour/ardour/export_format_manager.h
@@ -109,7 +109,10 @@ class LIBARDOUR_API ExportFormatManager : public PBD::ScopedConnectionList
void select_trim_end (bool value);
void select_silence_end (AnyTime const & time);
void select_normalize (bool value);
- void select_normalize_target (float value);
+ void select_normalize_loudness (bool value);
+ void select_normalize_dbfs (float value);
+ void select_normalize_lufs (float value);
+ void select_normalize_dbtp (float value);
void select_tagging (bool tag);
private:
diff --git a/libs/ardour/ardour/export_format_specification.h b/libs/ardour/ardour/export_format_specification.h
index 89ce0e5168..d473d20234 100644
--- a/libs/ardour/ardour/export_format_specification.h
+++ b/libs/ardour/ardour/export_format_specification.h
@@ -91,7 +91,10 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
void set_trim_beginning (bool value) { _trim_beginning = value; }
void set_trim_end (bool value) { _trim_end = value; }
void set_normalize (bool value) { _normalize = value; }
- void set_normalize_target (float value) { _normalize_target = value; }
+ void set_normalize_loudness (bool value) { _normalize_loudness = value; }
+ void set_normalize_dbfs (float value) { _normalize_dbfs = value; }
+ void set_normalize_lufs (float value) { _normalize_lufs = value; }
+ void set_normalize_dbtp (float value) { _normalize_dbtp = value; }
void set_tag (bool tag_it) { _tag = tag_it; }
void set_with_cue (bool yn) { _with_cue = yn; }
@@ -157,7 +160,10 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
bool trim_beginning () const { return _trim_beginning; }
bool trim_end () const { return _trim_end; }
bool normalize () const { return _normalize; }
- float normalize_target () const { return _normalize_target; }
+ bool normalize_loudness () const { return _normalize_loudness; }
+ float normalize_dbfs () const { return _normalize_dbfs; }
+ float normalize_lufs () const { return _normalize_lufs; }
+ float normalize_dbtp () const { return _normalize_dbtp; }
bool with_toc() const { return _with_toc; }
bool with_cue() const { return _with_cue; }
bool with_mp4chaps() const { return _with_mp4chaps; }
@@ -211,7 +217,10 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
Time _silence_end;
bool _normalize;
- float _normalize_target;
+ bool _normalize_loudness;
+ float _normalize_dbfs;
+ float _normalize_lufs;
+ float _normalize_dbtp;
bool _with_toc;
bool _with_cue;
bool _with_mp4chaps;
diff --git a/libs/ardour/ardour/export_graph_builder.h b/libs/ardour/ardour/export_graph_builder.h
index 0a9912e43e..df02c9eb57 100644
--- a/libs/ardour/ardour/export_graph_builder.h
+++ b/libs/ardour/ardour/export_graph_builder.h
@@ -32,6 +32,7 @@
namespace AudioGrapher {
class SampleRateConverter;
class PeakReader;
+ class LoudnessReader;
class Normalizer;
class Analyser;
template <typename T> class Chunker;
@@ -160,6 +161,7 @@ class LIBARDOUR_API ExportGraphBuilder
private:
typedef boost::shared_ptr<AudioGrapher::PeakReader> PeakReaderPtr;
+ typedef boost::shared_ptr<AudioGrapher::LoudnessReader> LoudnessReaderPtr;
typedef boost::shared_ptr<AudioGrapher::Normalizer> NormalizerPtr;
typedef boost::shared_ptr<AudioGrapher::TmpFile<Sample> > TmpFilePtr;
typedef boost::shared_ptr<AudioGrapher::Threader<Sample> > ThreaderPtr;
@@ -171,12 +173,13 @@ class LIBARDOUR_API ExportGraphBuilder
FileSpec config;
framecnt_t max_frames_out;
-
+ bool use_loudness;
BufferPtr buffer;
PeakReaderPtr peak_reader;
TmpFilePtr tmp_file;
NormalizerPtr normalizer;
ThreaderPtr threader;
+ LoudnessReaderPtr loudness_reader;
boost::ptr_list<SFC> children;
PBD::ScopedConnection post_processing_connection;
diff --git a/libs/ardour/export_format_manager.cc b/libs/ardour/export_format_manager.cc
index f87a08686f..6554412273 100644
--- a/libs/ardour/export_format_manager.cc
+++ b/libs/ardour/export_format_manager.cc
@@ -343,9 +343,30 @@ ExportFormatManager::select_normalize (bool value)
}
void
-ExportFormatManager::select_normalize_target (float value)
+ExportFormatManager::select_normalize_loudness (bool value)
{
- current_selection->set_normalize_target (value);
+ current_selection->set_normalize_loudness (value);
+ check_for_description_change ();
+}
+
+void
+ExportFormatManager::select_normalize_dbfs (float value)
+{
+ current_selection->set_normalize_dbfs (value);
+ check_for_description_change ();
+}
+
+void
+ExportFormatManager::select_normalize_lufs (float value)
+{
+ current_selection->set_normalize_lufs (value);
+ check_for_description_change ();
+}
+
+void
+ExportFormatManager::select_normalize_dbtp (float value)
+{
+ current_selection->set_normalize_dbtp (value);
check_for_description_change ();
}
diff --git a/libs/ardour/export_format_specification.cc b/libs/ardour/export_format_specification.cc
index fd85c322d6..6b0e2f237f 100644
--- a/libs/ardour/export_format_specification.cc
+++ b/libs/ardour/export_format_specification.cc
@@ -167,7 +167,10 @@ ExportFormatSpecification::ExportFormatSpecification (Session & s)
, _silence_end (s)
, _normalize (false)
- , _normalize_target (GAIN_COEFF_UNITY)
+ , _normalize_loudness (false)
+ , _normalize_dbfs (GAIN_COEFF_UNITY)
+ , _normalize_lufs (-23)
+ , _normalize_dbtp (-1)
, _with_toc (false)
, _with_cue (false)
, _with_mp4chaps (false)
@@ -184,9 +187,30 @@ ExportFormatSpecification::ExportFormatSpecification (Session & s)
ExportFormatSpecification::ExportFormatSpecification (Session & s, XMLNode const & state)
: session (s)
+
+ , has_sample_format (false)
+ , supports_tagging (false)
+ , _has_broadcast_info (false)
+ , _channel_limit (0)
+ , _dither_type (D_None)
+ , _src_quality (SRC_SincBest)
+ , _tag (true)
+
+ , _trim_beginning (false)
, _silence_beginning (s)
+ , _trim_end (false)
, _silence_end (s)
+
+ , _normalize (false)
+ , _normalize_loudness (false)
+ , _normalize_dbfs (GAIN_COEFF_UNITY)
+ , _normalize_lufs (-23)
+ , _normalize_dbtp (-1)
+ , _with_toc (false)
+ , _with_cue (false)
+ , _with_mp4chaps (false)
, _soundcloud_upload (false)
+ , _command ("")
, _analyse (true)
{
_silence_beginning.type = Time::Timecode;
@@ -228,7 +252,10 @@ ExportFormatSpecification::ExportFormatSpecification (ExportFormatSpecification
set_trim_beginning (other.trim_beginning());
set_trim_end (other.trim_end());
set_normalize (other.normalize());
- set_normalize_target (other.normalize_target());
+ set_normalize_loudness (other.normalize_loudness());
+ set_normalize_dbfs (other.normalize_dbfs());
+ set_normalize_lufs (other.normalize_lufs());
+ set_normalize_dbtp (other.normalize_dbtp());
set_tag (other.tag());
@@ -281,7 +308,10 @@ ExportFormatSpecification::get_state ()
node = processing->add_child ("Normalize");
node->add_property ("enabled", normalize() ? "true" : "false");
- node->add_property ("target", to_string (normalize_target(), std::dec));
+ node->add_property ("loudness", normalize_loudness() ? "yes" : "no");
+ node->add_property ("dbfs", to_string (normalize_dbfs(), std::dec));
+ node->add_property ("lufs", to_string (normalize_lufs(), std::dec));
+ node->add_property ("dbtp", to_string (normalize_dbtp(), std::dec));
XMLNode * silence = processing->add_child ("Silence");
XMLNode * start = silence->add_child ("Start");
@@ -407,8 +437,25 @@ ExportFormatSpecification::set_state (const XMLNode & root)
_normalize = (!prop->value().compare ("true"));
}
+ // old formats before ~ 4.7-930ish
if ((prop = child->property ("target"))) {
- _normalize_target = atof (prop->value());
+ _normalize_dbfs = atof (prop->value());
+ }
+
+ if ((prop = child->property ("loudness"))) {
+ _normalize_loudness = string_is_affirmative (prop->value());
+ }
+
+ if ((prop = child->property ("dbfs"))) {
+ _normalize_dbfs = atof (prop->value());
+ }
+
+ if ((prop = child->property ("lufs"))) {
+ _normalize_lufs = atof (prop->value());
+ }
+
+ if ((prop = child->property ("dbtp"))) {
+ _normalize_dbtp = atof (prop->value());
}
}
@@ -556,7 +603,11 @@ ExportFormatSpecification::description (bool include_name)
list<string> components;
if (_normalize) {
- components.push_back (_("normalize"));
+ if (_normalize_loudness) {
+ components.push_back (_("normalize loudness"));
+ } else {
+ components.push_back (_("normalize peak"));
+ }
}
if (_trim_beginning && _trim_end) {
diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc
index 349c11ddbb..a78c983f0f 100644
--- a/libs/ardour/export_graph_builder.cc
+++ b/libs/ardour/export_graph_builder.cc
@@ -30,6 +30,7 @@
#include "audiographer/general/normalizer.h"
#include "audiographer/general/analyser.h"
#include "audiographer/general/peak_reader.h"
+#include "audiographer/general/loudness_reader.h"
#include "audiographer/general/sample_format_converter.h"
#include "audiographer/general/sr_converter.h"
#include "audiographer/general/silence_trimmer.h"
@@ -405,8 +406,9 @@ ExportGraphBuilder::SFC::operator== (FileSpec const & other_config) const
/* Normalizer */
-ExportGraphBuilder::Normalizer::Normalizer (ExportGraphBuilder & parent, FileSpec const & new_config, framecnt_t /*max_frames*/)
+ExportGraphBuilder::Normalizer::Normalizer (ExportGraphBuilder & parent, FileSpec const & new_config, framecnt_t max_frames)
: parent (parent)
+ , use_loudness (false)
{
std::string tmpfile_path = parent.session.session_directory().export_path();
tmpfile_path = Glib::build_filename(tmpfile_path, "XXXXXX");
@@ -417,10 +419,12 @@ ExportGraphBuilder::Normalizer::Normalizer (ExportGraphBuilder & parent, FileSpe
config = new_config;
uint32_t const channels = config.channel_config->get_n_chans();
max_frames_out = 4086 - (4086 % channels); // TODO good chunk size
+ use_loudness = config.format->normalize_loudness ();
buffer.reset (new AllocatingProcessContext<Sample> (max_frames_out, channels));
peak_reader.reset (new PeakReader ());
- normalizer.reset (new AudioGrapher::Normalizer (config.format->normalize_target()));
+ loudness_reader.reset (new LoudnessReader (config.format->sample_rate(), channels, max_frames));
+ normalizer.reset (new AudioGrapher::Normalizer (use_loudness ? 0.0 : config.format->normalize_dbfs()));
threader.reset (new Threader<Sample> (parent.thread_pool));
normalizer->alloc_buffer (max_frames_out);
@@ -433,12 +437,19 @@ ExportGraphBuilder::Normalizer::Normalizer (ExportGraphBuilder & parent, FileSpe
add_child (new_config);
- peak_reader->add_output (tmp_file);
+ if (use_loudness) {
+ loudness_reader->add_output (tmp_file);
+ } else {
+ peak_reader->add_output (tmp_file);
+ }
}
ExportGraphBuilder::FloatSinkPtr
ExportGraphBuilder::Normalizer::sink ()
{
+ if (use_loudness) {
+ return loudness_reader;
+ }
return peak_reader;
}
@@ -471,7 +482,11 @@ bool
ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
{
return config.format->normalize() == other_config.format->normalize() &&
- config.format->normalize_target() == other_config.format->normalize_target();
+ (
+ (!config.format->normalize_loudness () && config.format->normalize_dbfs() == other_config.format->normalize_dbfs())
+ ||
+ (config.format->normalize_loudness () /* lufs/dbtp is a result option, not an instantaion option */)
+ );
}
unsigned
@@ -491,7 +506,12 @@ ExportGraphBuilder::Normalizer::process()
void
ExportGraphBuilder::Normalizer::start_post_processing()
{
- const float gain = normalizer->set_peak (peak_reader->get_peak());
+ float gain;
+ if (use_loudness) {
+ gain = normalizer->set_peak (loudness_reader->get_peak (config.format->normalize_lufs (), config.format->normalize_dbtp ()));
+ } else {
+ gain = normalizer->set_peak (peak_reader->get_peak());
+ }
for (boost::ptr_list<SFC>::iterator i = children.begin(); i != children.end(); ++i) {
(*i).set_peak (gain);
}