From c1d98ca3c8ddf16deb50285c6278fd1f0821623e Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 4 Apr 2021 01:11:55 +0200 Subject: [PATCH] Export analysis: log loudness / time --- libs/ardour/ardour/export_analysis.h | 20 ++++++++++++++++++ libs/audiographer/src/general/analyser.cc | 25 ++++++++++++++++++++++- libs/vamp-plugins/EBUr128.cpp | 23 +++++++++++++++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/libs/ardour/ardour/export_analysis.h b/libs/ardour/ardour/export_analysis.h index c13e61c79e..7fc9b8fc58 100644 --- a/libs/ardour/ardour/export_analysis.h +++ b/libs/ardour/ardour/export_analysis.h @@ -38,15 +38,25 @@ namespace ARDOUR { , max_loudness_momentary (0) , loudness_hist_max (0) , have_loudness (false) + , have_lufs_graph (false) , have_dbtp (false) , norm_gain_factor (1.0) , normalized (false) , n_channels (1) + , n_samples (0) { memset (peaks, 0, sizeof(peaks)); memset (spectrum, 0, sizeof(spectrum)); memset (loudness_hist, 0, sizeof(loudness_hist)); memset (freq, 0, sizeof(freq)); + assert (sizeof(lgraph_i) == sizeof(lgraph_s)); + assert (sizeof(lgraph_i) == sizeof(lgraph_m)); + for (size_t i = 0; i < sizeof(lgraph_i) / sizeof (float); ++i) { + /* d compare to ebu_r128_proc.cc */ + lgraph_i [i] = -200; + lgraph_s [i] = -200; + lgraph_m [i] = -200; + } } ExportAnalysis (const ExportAnalysis& other) @@ -58,10 +68,12 @@ namespace ARDOUR { , max_loudness_momentary (other.max_loudness_momentary) , loudness_hist_max (other.loudness_hist_max) , have_loudness (other.have_loudness) + , have_lufs_graph (other.have_lufs_graph) , have_dbtp (other.have_dbtp) , norm_gain_factor (other.norm_gain_factor) , normalized (other.normalized) , n_channels (other.n_channels) + , n_samples (other.n_samples) { truepeakpos[0] = other.truepeakpos[0]; truepeakpos[1] = other.truepeakpos[1]; @@ -69,6 +81,9 @@ namespace ARDOUR { memcpy (spectrum, other.spectrum, sizeof(spectrum)); memcpy (loudness_hist, other.loudness_hist, sizeof(loudness_hist)); memcpy (freq, other.freq, sizeof(freq)); + memcpy (lgraph_i, other.lgraph_i, sizeof(lgraph_i)); + memcpy (lgraph_s, other.lgraph_s, sizeof(lgraph_s)); + memcpy (lgraph_m, other.lgraph_m, sizeof(lgraph_m)); } float peak; @@ -80,15 +95,20 @@ namespace ARDOUR { int loudness_hist[540]; int loudness_hist_max; bool have_loudness; + bool have_lufs_graph; bool have_dbtp; float norm_gain_factor; bool normalized; uint32_t n_channels; + uint32_t n_samples; uint32_t freq[6]; // y-pos, 50, 100, 500, 1k, 5k, 10k [Hz] PeakData peaks[2][800]; float spectrum[800][200]; + float lgraph_i[800]; + float lgraph_s[800]; + float lgraph_m[800]; std::set truepeakpos[2]; // bins with >= -1dBTB }; diff --git a/libs/audiographer/src/general/analyser.cc b/libs/audiographer/src/general/analyser.cc index 5c30726727..73f3422f95 100644 --- a/libs/audiographer/src/general/analyser.cc +++ b/libs/audiographer/src/general/analyser.cc @@ -123,6 +123,7 @@ Analyser::process (ProcessContext const & ctx) for (s = 0; s < n_samples; ++s) { _fft_data_in[s] = 0; const samplecnt_t pbin = (_pos + s) / _spp; + assert (pbin >= 0 && pbin < (sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4)); for (unsigned int c = 0; c < _channels; ++c) { const float v = *d; if (fabsf(v) > _result.peak) { _result.peak = fabsf(v); } @@ -145,7 +146,18 @@ Analyser::process (ProcessContext const & ctx) } if (_ebur_plugin) { - _ebur_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate)); + Vamp::Plugin::FeatureSet features = _ebur_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate)); + if (!features.empty ()) { + const samplecnt_t p0 = _pos / _spp; + const samplecnt_t p1 = (_pos + n_samples -1) / _spp; + for (samplecnt_t p = p0; p <= p1; ++p) { + assert (p >= 0 && p < (sizeof (_result.lgraph_i) / sizeof(float))); + _result.lgraph_i[p] = features[0][0].values[0]; + _result.lgraph_s[p] = features[0][1].values[0]; + _result.lgraph_m[p] = features[0][2].values[0]; + } + _result.have_lufs_graph = true; + } } float const * const data = ctx.data (); @@ -208,6 +220,8 @@ Analyser::result () return ARDOUR::ExportAnalysisPtr (); } + _result.n_samples = _pos; + if (_pos + 1 < _n_samples) { // crude re-bin (silence stripped version) const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4; @@ -229,6 +243,15 @@ Analyser::result () _result.spectrum[b][y] = _result.spectrum[sb][y]; } } + + /* re-scale loudnes graphs */ + const size_t lw = sizeof (_result.lgraph_i) / sizeof (float); + for (samplecnt_t b = lw - 1; b > 0; --b) { + const samplecnt_t sb = b * _pos / _n_samples; + _result.lgraph_i[b] = _result.lgraph_i[sb]; + _result.lgraph_s[b] = _result.lgraph_s[sb]; + _result.lgraph_m[b] = _result.lgraph_m[sb]; + } } if (_ebur_plugin) { diff --git a/libs/vamp-plugins/EBUr128.cpp b/libs/vamp-plugins/EBUr128.cpp index a6df378c4c..c8b538c771 100644 --- a/libs/vamp-plugins/EBUr128.cpp +++ b/libs/vamp-plugins/EBUr128.cpp @@ -107,8 +107,9 @@ VampEBUr128::getOutputDescriptors () const OutputList list; OutputDescriptor zc; + zc.identifier = "loundless"; - zc.name = "Integrated loudness"; + zc.name = "Loudness"; zc.description = "Loudness (integrated, short, momentary)"; zc.unit = "LUFS"; zc.hasFixedBinCount = true; @@ -157,7 +158,25 @@ VampEBUr128::process (const float* const* inputBuffers, ebu.integr_start (); // noop if already started ebu.process (m_stepSize, inputBuffers); - return FeatureSet (); + FeatureSet returnFeatures; + + Feature loudness_integrated; + loudness_integrated.hasTimestamp = false; + loudness_integrated.values.push_back (ebu.integrated ()); + + Feature loudness_short; + loudness_short.hasTimestamp = false; + loudness_short.values.push_back (ebu.loudness_S ()); + + Feature loudness_momentary; + loudness_momentary.hasTimestamp = false; + loudness_momentary.values.push_back (ebu.loudness_M ()); + + returnFeatures[0].push_back (loudness_integrated); + returnFeatures[0].push_back (loudness_short); + returnFeatures[0].push_back (loudness_momentary); + + return returnFeatures; } VampEBUr128::FeatureSet