2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "audiographer/general/analyser.h"
20 #include "pbd/fastlog.h"
22 using namespace AudioGrapher;
24 const float Analyser::fft_range_db (120); // dB
26 Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize, framecnt_t n_samples)
29 , _sample_rate (sample_rate)
30 , _channels (channels)
31 , _bufsize (bufsize / channels)
32 , _n_samples (n_samples)
35 //printf ("NEW ANALYSER %p r:%.1f c:%d f:%ld l%ld\n", this, sample_rate, channels, bufsize, n_samples);
36 assert (bufsize % channels == 0);
38 assert (_bufsize > 0);
39 if (channels > 0 && channels <= 2) {
40 using namespace Vamp::HostExt;
41 PluginLoader* loader (PluginLoader::getInstance ());
42 _ebur128_plugin = loader->loadPlugin ("libardourvampplugins:ebur128", sample_rate, PluginLoader::ADAPT_ALL_SAFE);
43 assert (_ebur128_plugin);
44 _ebur128_plugin->reset ();
45 if (!_ebur128_plugin->initialise (channels, _bufsize, _bufsize)) {
46 delete _ebur128_plugin;
51 _dbtp_plugin = (Vamp::Plugin**) malloc (sizeof(Vamp::Plugin*) * channels);
52 for (unsigned int c = 0; c < _channels; ++c) {
53 using namespace Vamp::HostExt;
54 PluginLoader* loader (PluginLoader::getInstance ());
55 _dbtp_plugin[c] = loader->loadPlugin ("libardourvampplugins:dBTP", sample_rate, PluginLoader::ADAPT_ALL_SAFE);
56 assert (_dbtp_plugin[c]);
57 _dbtp_plugin[c]->reset ();
58 if (!_dbtp_plugin[c]->initialise (1, _bufsize, _bufsize)) {
59 delete _dbtp_plugin[c];
64 _bufs[0] = (float*) malloc (sizeof (float) * _bufsize);
65 _bufs[1] = (float*) malloc (sizeof (float) * _bufsize);
67 const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
68 _spp = ceil ((_n_samples + 2.f) / (float) peaks);
70 const size_t swh = sizeof (_result.spectrum) / sizeof (float);
71 const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
72 const size_t width = swh / height;
73 _fpp = ceil ((_n_samples + 2.f) / (float) width);
75 _fft_data_size = _bufsize / 2;
76 _fft_freq_per_bin = sample_rate / _fft_data_size / 2.f;
78 _fft_data_in = (float *) fftwf_malloc (sizeof (float) * _bufsize);
79 _fft_data_out = (float *) fftwf_malloc (sizeof (float) * _bufsize);
80 _fft_power = (float *) malloc (sizeof (float) * _fft_data_size);
82 for (uint32_t i = 0; i < _fft_data_size; ++i) {
85 for (uint32_t i = 0; i < _bufsize; ++i) {
89 const float nyquist = (sample_rate * .5);
91 #define YPOS(FREQ) rint (height * (1.0 - FREQ / nyquist))
93 #define YPOS(FREQ) rint (height * (1 - logf (1.f + .1f * _fft_data_size * FREQ / nyquist) / logf (1.f + .1f * _fft_data_size)))
96 _result.freq[0] = YPOS (50);
97 _result.freq[1] = YPOS (100);
98 _result.freq[2] = YPOS (500);
99 _result.freq[3] = YPOS (1000);
100 _result.freq[4] = YPOS (5000);
101 _result.freq[5] = YPOS (10000);
103 _fft_plan = fftwf_plan_r2r_1d (_bufsize, _fft_data_in, _fft_data_out, FFTW_R2HC, FFTW_MEASURE);
105 _hann_window = (float *) malloc (sizeof (float) * _bufsize);
108 for (uint32_t i = 0; i < _bufsize; ++i) {
109 _hann_window[i] = 0.5f - (0.5f * (float) cos (2.0f * M_PI * (float)i / (float)(_bufsize)));
110 sum += _hann_window[i];
112 const double isum = 2.0 / sum;
113 for (uint32_t i = 0; i < _bufsize; ++i) {
114 _hann_window[i] *= isum;
118 _result.n_channels = 2;
120 _result.n_channels = 1;
124 Analyser::~Analyser ()
126 delete _ebur128_plugin;
127 for (unsigned int c = 0; c < _channels; ++c) {
128 delete _dbtp_plugin[c];
133 fftwf_destroy_plan (_fft_plan);
134 fftwf_free (_fft_data_in);
135 fftwf_free (_fft_data_out);
141 Analyser::process (ProcessContext<float> const & ctx)
143 const framecnt_t n_samples = ctx.frames () / ctx.channels ();
144 assert (ctx.channels () == _channels);
145 assert (ctx.frames () % ctx.channels () == 0);
146 assert (n_samples <= _bufsize);
147 //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, ctx.frames (), n_samples, ctx.channels ());
149 // allow 1 sample slack for resampling
150 if (_pos + n_samples > _n_samples + 1) {
152 ListedSource<float>::output (ctx);
156 float const * d = ctx.data ();
158 const unsigned cmask = _result.n_channels - 1; // [0, 1]
159 for (s = 0; s < n_samples; ++s) {
161 const framecnt_t pbin = (_pos + s) / _spp;
162 for (unsigned int c = 0; c < _channels; ++c) {
164 if (fabsf(v) > _result.peak) { _result.peak = fabsf(v); }
165 if (c < _result.n_channels) {
168 const unsigned int cc = c & cmask;
169 if (_result.peaks[cc][pbin].min > v) { _result.peaks[cc][pbin].min = *d; }
170 if (_result.peaks[cc][pbin].max < v) { _result.peaks[cc][pbin].max = *d; }
171 _fft_data_in[s] += v * _hann_window[s] / (float) _channels;
176 for (; s < _bufsize; ++s) {
178 for (unsigned int c = 0; c < _result.n_channels; ++c) {
183 if (_ebur128_plugin) {
184 _ebur128_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
187 float const * const data = ctx.data ();
188 for (unsigned int c = 0; c < _channels; ++c) {
189 if (!_dbtp_plugin[c]) { continue; }
190 for (s = 0; s < n_samples; ++s) {
191 _bufs[0][s] = data[s * _channels + c];
193 _dbtp_plugin[c]->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
196 fftwf_execute (_fft_plan);
198 _fft_power[0] = _fft_data_out[0] * _fft_data_out[0];
199 #define FRe (_fft_data_out[i])
200 #define FIm (_fft_data_out[_bufsize - i])
201 for (uint32_t i = 1; i < _fft_data_size - 1; ++i) {
202 _fft_power[i] = (FRe * FRe) + (FIm * FIm);
207 const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
208 const framecnt_t x0 = _pos / _fpp;
209 framecnt_t x1 = (_pos + n_samples) / _fpp;
210 if (x0 == x1) x1 = x0 + 1;
212 for (uint32_t i = 0; i < _fft_data_size - 1; ++i) {
213 const float level = fft_power_at_bin (i, i);
214 if (level < -fft_range_db) continue;
215 const float pk = level > 0.0 ? 1.0 : (fft_range_db + level) / fft_range_db;
217 const uint32_t y0 = floor (i * (float) height / _fft_data_size);
218 uint32_t y1 = ceil ((i + 1.0) * (float) height / _fft_data_size);
220 const uint32_t y0 = floor (height * logf (1.f + .1f * i) / logf (1.f + .1f * _fft_data_size));
221 uint32_t y1 = ceilf (height * logf (1.f + .1f * (i + 1.f)) / logf (1.f + .1f * _fft_data_size));
223 assert (y0 < height);
224 assert (y1 > 0 && y1 <= height);
225 if (y0 == y1) y1 = y0 + 1;
226 for (int x = x0; x < x1; ++x) {
227 for (uint32_t y = y0; y < y1 && y < height; ++y) {
228 uint32_t yy = height - 1 - y;
229 if (_result.spectrum[x][yy] < pk) { _result.spectrum[x][yy] = pk; }
236 /* pass audio audio through */
237 ListedSource<float>::output (ctx);
240 ARDOUR::ExportAnalysisPtr
243 //printf ("PROCESSED %ld / %ld samples\n", _pos, _n_samples);
244 if (_pos == 0 || _pos > _n_samples + 1) {
245 return ARDOUR::ExportAnalysisPtr ();
248 if (_pos + 1 < _n_samples) {
249 // crude re-bin (silence stripped version)
250 const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
251 for (framecnt_t b = peaks - 1; b > 0; --b) {
252 for (unsigned int c = 0; c < _result.n_channels; ++c) {
253 const framecnt_t sb = b * _pos / _n_samples;
254 _result.peaks[c][b].min = _result.peaks[c][sb].min;
255 _result.peaks[c][b].max = _result.peaks[c][sb].max;
259 const size_t swh = sizeof (_result.spectrum) / sizeof (float);
260 const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
261 const size_t width = swh / height;
262 for (framecnt_t b = width - 1; b > 0; --b) {
263 // TODO round down to prev _fft_data_size bin
264 const framecnt_t sb = b * _pos / _n_samples;
265 for (unsigned int y = 0; y < height; ++y) {
266 _result.spectrum[b][y] = _result.spectrum[sb][y];
271 if (_ebur128_plugin) {
272 Vamp::Plugin::FeatureSet features = _ebur128_plugin->getRemainingFeatures ();
273 if (!features.empty () && features.size () == 3) {
274 _result.loudness = features[0][0].values[0];
275 _result.loudness_range = features[1][0].values[0];
276 assert (features[2][0].values.size () == 540);
277 for (int i = 0; i < 540; ++i) {
278 _result.loudness_hist[i] = features[2][0].values[i];
279 if (_result.loudness_hist[i] > _result.loudness_hist_max) {
280 _result.loudness_hist_max = _result.loudness_hist[i]; }
282 _result.have_loudness = true;
286 const unsigned cmask = _result.n_channels - 1; // [0, 1]
287 for (unsigned int c = 0; c < _channels; ++c) {
288 if (!_dbtp_plugin[c]) { continue; }
289 Vamp::Plugin::FeatureSet features = _dbtp_plugin[c]->getRemainingFeatures ();
290 if (!features.empty () && features.size () == 2) {
291 _result.have_dbtp = true;
292 float p = features[0][0].values[0];
293 if (p > _result.truepeak) { _result.truepeak = p; }
295 for (std::vector<float>::const_iterator i = features[1][0].values.begin();
296 i != features[1][0].values.end(); ++i) {
297 const framecnt_t pk = (*i) / _spp;
298 const unsigned int cc = c & cmask;
299 _result.truepeakpos[cc].insert (pk);
304 return ARDOUR::ExportAnalysisPtr (new ARDOUR::ExportAnalysis (_result));
308 Analyser::fft_power_at_bin (const uint32_t b, const float norm) const
310 const float a = _fft_power[b] * norm;
311 return a > 1e-12 ? 10.0 * fast_log10 (a) : -INFINITY;