From 5a9fde4a0bc0369bee7f84ba5c00f32a0aaac4f3 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 20 Jul 2021 01:31:48 +0200 Subject: [PATCH] Region loudness normalization/analysis #8777 --- libs/ardour/analysis_graph.cc | 21 +++++++++++++++++-- libs/ardour/ardour/analysis_graph.h | 6 +++++- libs/ardour/ardour/audioregion.h | 2 ++ libs/ardour/audioregion.cc | 32 +++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/libs/ardour/analysis_graph.cc b/libs/ardour/analysis_graph.cc index df204a46e3..4e0b5f01f8 100644 --- a/libs/ardour/analysis_graph.cc +++ b/libs/ardour/analysis_graph.cc @@ -18,6 +18,7 @@ #include "ardour/analysis_graph.h" +#include "ardour/progress.h" #include "ardour/route.h" #include "ardour/session.h" @@ -54,7 +55,13 @@ AnalysisGraph::~AnalysisGraph () } void -AnalysisGraph::analyze_region (boost::shared_ptr region) +AnalysisGraph::analyze_region (boost::shared_ptr region, bool raw) +{ + analyze_region (region.get(), raw, (ARDOUR::Progress*)0); +} + +void +AnalysisGraph::analyze_region (AudioRegion const* region, bool raw, ARDOUR::Progress* p) { int n_channels = region->n_channels(); if (n_channels == 0 || n_channels > _max_chunksize) { @@ -81,7 +88,11 @@ AnalysisGraph::analyze_region (boost::shared_ptr region) samplecnt_t n = 0; for (unsigned int channel = 0; channel < region->n_channels(); ++channel) { memset (_buf, 0, chunk * sizeof (Sample)); - n = region->read_at (_buf, _mixbuf, _gainbuf, region->position() + x, chunk, channel); + if (raw) { + n = region->read_raw_internal (_buf, region->start() + x, chunk, channel); + } else { + n = region->read_at (_buf, _mixbuf, _gainbuf, region->position() + x, chunk, channel); + } ConstProcessContext context (_buf, n, 1); if (n < _max_chunksize) { context().set_flag (ProcessContext::EndOfInput); @@ -99,6 +110,12 @@ AnalysisGraph::analyze_region (boost::shared_ptr region) if (_canceled) { return; } + if (p) { + p->set_progress (_samples_read / (float) _samples_end); + if (p->cancelled ()) { + return; + } + } } _results.insert (std::make_pair (region->name(), analyser->result ())); } diff --git a/libs/ardour/ardour/analysis_graph.h b/libs/ardour/ardour/analysis_graph.h index 71fc02aed4..3651763fff 100644 --- a/libs/ardour/ardour/analysis_graph.h +++ b/libs/ardour/ardour/analysis_graph.h @@ -38,12 +38,16 @@ namespace AudioGrapher { } namespace ARDOUR { + class Progress; + class LIBARDOUR_API AnalysisGraph { public: AnalysisGraph (ARDOUR::Session*); ~AnalysisGraph (); - void analyze_region (boost::shared_ptr); + void analyze_region (ARDOUR::AudioRegion const*, bool raw = false, ARDOUR::Progress* = 0); + void analyze_region (boost::shared_ptr, bool raw = false); + void analyze_range (boost::shared_ptr, boost::shared_ptr, const std::list&); const AnalysisResults& results () const { return _results; } diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 6eaa37f1f4..83371abb3a 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -92,6 +92,8 @@ class LIBARDOUR_API AudioRegion : public Region */ double rms (Progress* p = 0) const; + bool loudness (float& tp, float& i, float& s, float& m, Progress* p = 0) const; + bool envelope_active () const { return _envelope_active; } bool fade_in_active () const { return _fade_in_active; } bool fade_out_active () const { return _fade_out_active; } diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index a4afb2abd2..6e663626d4 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -41,6 +41,7 @@ #include "evoral/Curve.h" +#include "ardour/analysis_graph.h" #include "ardour/audioregion.h" #include "ardour/session.h" #include "ardour/dB.h" @@ -1470,6 +1471,37 @@ AudioRegion::rms (Progress* p) const return sqrt (2. * rms / (double)(total * n_chan)); } +bool +AudioRegion::loudness (float& tp, float& i, float& s, float& m, Progress* p) const +{ + ARDOUR::AnalysisGraph ag (&_session); + tp = i = s = m = -200; + + ag.set_total_samples (_length); + ag.analyze_region (this, true, p); + + if (p && p->cancelled ()) { + return false; + } + + AnalysisResults const& ar (ag.results ()); + if (ar.size() != 1) { + return false; + } + ExportAnalysisPtr eap (ar.begin ()->second); + + if (eap->have_dbtp) { + tp = eap->truepeak; + } + if (eap->have_loudness) { + i = eap->integrated_loudness; + s = eap->max_loudness_short; + m = eap->max_loudness_momentary; + } + + return eap->have_dbtp || eap->have_loudness; +} + /** Normalize using a given maximum amplitude and target, so that region * _scale_amplitude becomes target / max_amplitude. */