Analysis: 1 sample slack (for resampling rounding)
[ardour.git] / libs / audiographer / src / general / analyser.cc
index d969095b0847c0c1281115a665ab128902033e06..ec47b13b32343496d35e95ea1e43b2580476166e 100644 (file)
 
 #include "audiographer/general/analyser.h"
 #include "pbd/fastlog.h"
+#include "pbd/compose.h"
+#include "ardour/debug.h"
 
 using namespace AudioGrapher;
 
+const float Analyser::fft_range_db (120); // dB
+
 Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize, framecnt_t n_samples)
        : _ebur128_plugin (0)
        , _dbtp_plugin (0)
@@ -30,9 +34,11 @@ Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize
        , _n_samples (n_samples)
        , _pos (0)
 {
+       DEBUG_TRACE (PBD::DEBUG::ExportAnalysis, string_compose ("Analyser r:%1 c:%2 f:%3 d:%4\n", sample_rate, channels, bufsize, n_samples));
+
        assert (bufsize % channels == 0);
        assert (bufsize > 1);
-       //printf ("NEW ANALYSER %p r:%.1f c:%d f:%ld l%ld\n", this, sample_rate, channels, bufsize, n_samples);
+
        if (channels > 0 && channels <= 2) {
                using namespace Vamp::HostExt;
                PluginLoader* loader (PluginLoader::getInstance ());
@@ -40,7 +46,6 @@ Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize
                assert (_ebur128_plugin);
                _ebur128_plugin->reset ();
                if (!_ebur128_plugin->initialise (channels, _bufsize, _bufsize)) {
-                       printf ("FAILED TO INITIALIZE EBUR128\n");
                        delete _ebur128_plugin;
                        _ebur128_plugin = 0;
                }
@@ -54,7 +59,6 @@ Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize
                assert (_dbtp_plugin[c]);
                _dbtp_plugin[c]->reset ();
                if (!_dbtp_plugin[c]->initialise (1, _bufsize, _bufsize)) {
-                       printf ("FAILED TO INITIALIZE DBTP %d\n", c);
                        delete _dbtp_plugin[c];
                        _dbtp_plugin[c] = 0;
                }
@@ -64,12 +68,12 @@ Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize
        _bufs[1] = (float*) malloc (sizeof (float) * _bufsize);
 
        const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
-       _spp = ceil ((_n_samples + 1.f) / (float) peaks);
+       _spp = ceil ((_n_samples + 2.f) / (float) peaks);
 
        const size_t swh = sizeof (_result.spectrum) / sizeof (float);
        const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
        const size_t width = swh / height;
-       _fpp = ceil ((_n_samples + 1.f) / (float) width);
+       _fpp = ceil ((_n_samples + 2.f) / (float) width);
 
        _fft_data_size   = _bufsize / 2;
        _fft_freq_per_bin = sample_rate / _fft_data_size / 2.f;
@@ -137,25 +141,34 @@ Analyser::~Analyser ()
 }
 
 void
-Analyser::process (ProcessContext<float> const & c)
+Analyser::process (ProcessContext<float> const & ctx)
 {
-       framecnt_t n_samples = c.frames () / c.channels ();
-       assert (c.frames () % c.channels () == 0);
+       const framecnt_t n_samples = ctx.frames () / ctx.channels ();
+       assert (ctx.channels () == _channels);
+       assert (ctx.frames () % ctx.channels () == 0);
        assert (n_samples <= _bufsize);
-       //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, c.frames (), n_samples, c.channels ());
-       float const * d = c.data ();
+       //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, ctx.frames (), n_samples, ctx.channels ());
+
+       // allow 1 sample slack for resampling
+       if (_pos + n_samples > _n_samples + 1) {
+               _pos += n_samples;
+               ListedSource<float>::output (ctx);
+               return;
+       }
+
+       float const * d = ctx.data ();
        framecnt_t s;
        const unsigned cmask = _result.n_channels - 1; // [0, 1]
        for (s = 0; s < n_samples; ++s) {
                _fft_data_in[s] = 0;
-               const framecnt_t pk = (_pos + s) / _spp;
+               const framecnt_t pbin = (_pos + s) / _spp;
                for (unsigned int c = 0; c < _channels; ++c) {
                        const float v = *d;
                        if (fabsf(v) > _result.peak) { _result.peak = fabsf(v); }
                        _bufs[c][s] = v;
                        const unsigned int cc = c & cmask;
-                       if (_result.peaks[cc][pk].min > v) { _result.peaks[cc][pk].min = *d; }
-                       if (_result.peaks[cc][pk].max < v) { _result.peaks[cc][pk].max = *d; }
+                       if (_result.peaks[cc][pbin].min > v) { _result.peaks[cc][pbin].min = *d; }
+                       if (_result.peaks[cc][pbin].max < v) { _result.peaks[cc][pbin].max = *d; }
                        _fft_data_in[s] += v * _hann_window[s] / (float) _channels;
                        ++d;
                }
@@ -172,7 +185,7 @@ Analyser::process (ProcessContext<float> const & c)
                _ebur128_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
        }
 
-       float const * const data = c.data ();
+       float const * const data = ctx.data ();
        for (unsigned int c = 0; c < _channels; ++c) {
                if (!_dbtp_plugin[c]) { continue; }
                for (s = 0; s < n_samples; ++s) {
@@ -196,12 +209,11 @@ Analyser::process (ProcessContext<float> const & c)
        const framecnt_t x0 = _pos / _fpp;
        framecnt_t x1 = (_pos + n_samples) / _fpp;
        if (x0 == x1) x1 = x0 + 1;
-       const float range = 80; // dB
 
        for (uint32_t i = 0; i < _fft_data_size - 1; ++i) {
                const float level = fft_power_at_bin (i, i);
-               if (level < -range) continue;
-               const float pk = level > 0.0 ? 1.0 : (range + level) / range;
+               if (level < -fft_range_db) continue;
+               const float pk = level > 0.0 ? 1.0 : (fft_range_db + level) / fft_range_db;
 #if 0 // linear
                const uint32_t y0 = floor (i * (float) height / _fft_data_size);
                uint32_t y1 = ceil ((i + 1.0) * (float) height / _fft_data_size);
@@ -223,16 +235,18 @@ Analyser::process (ProcessContext<float> const & c)
        _pos += n_samples;
 
        /* pass audio audio through */
-       ListedSource<float>::output (c);
+       ListedSource<float>::output (ctx);
 }
 
 ARDOUR::ExportAnalysisPtr
 Analyser::result ()
 {
-       //printf ("PROCESSED %ld / %ld samples\n", _pos, _n_samples);
-       if (_pos == 0) {
+       DEBUG_TRACE (PBD::DEBUG::ExportAnalysis, string_compose ("Processed %1 / %2 samples\n", _pos, _n_samples));
+       if (_pos == 0 || ::llabs (_pos -_n_samples) > 1) {
+               printf("NO ANAL\n");
                return ARDOUR::ExportAnalysisPtr ();
        }
+
        if (_ebur128_plugin) {
                Vamp::Plugin::FeatureSet features = _ebur128_plugin->getRemainingFeatures ();
                if (!features.empty () && features.size () == 3) {