prepare loudness normalization
[ardour.git] / libs / audiographer / src / general / analyser.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include "audiographer/general/analyser.h"
20 #include "pbd/fastlog.h"
21
22 using namespace AudioGrapher;
23
24 const float Analyser::fft_range_db (120); // dB
25
26 Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize, framecnt_t n_samples)
27         : LoudnessReader (sample_rate, channels, bufsize)
28         , _n_samples (n_samples)
29         , _pos (0)
30 {
31         //printf ("NEW ANALYSER %p r:%.1f c:%d f:%ld l%ld\n", this, sample_rate, channels, bufsize, n_samples);
32         assert (bufsize % channels == 0);
33         assert (bufsize > 1);
34         assert (_bufsize > 0);
35
36
37
38         const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
39         _spp = ceil ((_n_samples + 2.f) / (float) peaks);
40
41         const size_t swh = sizeof (_result.spectrum) / sizeof (float);
42         const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
43         const size_t width = swh / height;
44         _fpp = ceil ((_n_samples + 2.f) / (float) width);
45
46         _fft_data_size   = _bufsize / 2;
47         _fft_freq_per_bin = sample_rate / _fft_data_size / 2.f;
48
49         _fft_data_in  = (float *) fftwf_malloc (sizeof (float) * _bufsize);
50         _fft_data_out = (float *) fftwf_malloc (sizeof (float) * _bufsize);
51         _fft_power    = (float *) malloc (sizeof (float) * _fft_data_size);
52
53         for (uint32_t i = 0; i < _fft_data_size; ++i) {
54                 _fft_power[i] = 0;
55         }
56         for (uint32_t i = 0; i < _bufsize; ++i) {
57                 _fft_data_out[i] = 0;
58         }
59
60         const float nyquist = (sample_rate * .5);
61 #if 0 // linear
62 #define YPOS(FREQ) rint (height * (1.0 - FREQ / nyquist))
63 #else
64 #define YPOS(FREQ) rint (height * (1 - logf (1.f + .1f * _fft_data_size * FREQ / nyquist) / logf (1.f + .1f * _fft_data_size)))
65 #endif
66
67         _result.freq[0] = YPOS (50);
68         _result.freq[1] = YPOS (100);
69         _result.freq[2] = YPOS (500);
70         _result.freq[3] = YPOS (1000);
71         _result.freq[4] = YPOS (5000);
72         _result.freq[5] = YPOS (10000);
73
74         _fft_plan = fftwf_plan_r2r_1d (_bufsize, _fft_data_in, _fft_data_out, FFTW_R2HC, FFTW_MEASURE);
75
76         _hann_window = (float *) malloc (sizeof (float) * _bufsize);
77         double sum = 0.0;
78
79         for (uint32_t i = 0; i < _bufsize; ++i) {
80                 _hann_window[i] = 0.5f - (0.5f * (float) cos (2.0f * M_PI * (float)i / (float)(_bufsize)));
81                 sum += _hann_window[i];
82         }
83         const double isum = 2.0 / sum;
84         for (uint32_t i = 0; i < _bufsize; ++i) {
85                 _hann_window[i] *= isum;
86         }
87
88         if (channels == 2) {
89                 _result.n_channels = 2;
90         } else {
91                 _result.n_channels = 1;
92         }
93 }
94
95 Analyser::~Analyser ()
96 {
97         fftwf_destroy_plan (_fft_plan);
98         fftwf_free (_fft_data_in);
99         fftwf_free (_fft_data_out);
100         free (_fft_power);
101         free (_hann_window);
102 }
103
104 void
105 Analyser::process (ProcessContext<float> const & ctx)
106 {
107         const framecnt_t n_samples = ctx.frames () / ctx.channels ();
108         assert (ctx.channels () == _channels);
109         assert (ctx.frames () % ctx.channels () == 0);
110         assert (n_samples <= _bufsize);
111         //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, ctx.frames (), n_samples, ctx.channels ());
112
113         // allow 1 sample slack for resampling
114         if (_pos + n_samples > _n_samples + 1) {
115                 _pos += n_samples;
116                 ListedSource<float>::output (ctx);
117                 return;
118         }
119
120         float const * d = ctx.data ();
121         framecnt_t s;
122         const unsigned cmask = _result.n_channels - 1; // [0, 1]
123         for (s = 0; s < n_samples; ++s) {
124                 _fft_data_in[s] = 0;
125                 const framecnt_t pbin = (_pos + s) / _spp;
126                 for (unsigned int c = 0; c < _channels; ++c) {
127                         const float v = *d;
128                         if (fabsf(v) > _result.peak) { _result.peak = fabsf(v); }
129                         if (c < _result.n_channels) {
130                                 _bufs[c][s] = v;
131                         }
132                         const unsigned int cc = c & cmask;
133                         if (_result.peaks[cc][pbin].min > v) { _result.peaks[cc][pbin].min = *d; }
134                         if (_result.peaks[cc][pbin].max < v) { _result.peaks[cc][pbin].max = *d; }
135                         _fft_data_in[s] += v * _hann_window[s] / (float) _channels;
136                         ++d;
137                 }
138         }
139
140         for (; s < _bufsize; ++s) {
141                 _fft_data_in[s] = 0;
142                 for (unsigned int c = 0; c < _result.n_channels; ++c) {
143                         _bufs[c][s] = 0.f;
144                 }
145         }
146
147         if (_ebur_plugin) {
148                 _ebur_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
149         }
150
151         float const * const data = ctx.data ();
152         for (unsigned int c = 0; c < _channels; ++c) {
153                 if (!_dbtp_plugin[c]) { continue; }
154                 for (s = 0; s < n_samples; ++s) {
155                         _bufs[0][s] = data[s * _channels + c];
156                 }
157                 _dbtp_plugin[c]->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
158         }
159
160         fftwf_execute (_fft_plan);
161
162         _fft_power[0] = _fft_data_out[0] * _fft_data_out[0];
163 #define FRe (_fft_data_out[i])
164 #define FIm (_fft_data_out[_bufsize - i])
165         for (uint32_t i = 1; i < _fft_data_size - 1; ++i) {
166                 _fft_power[i] = (FRe * FRe) + (FIm * FIm);
167         }
168 #undef FRe
169 #undef FIm
170
171         const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
172         const framecnt_t x0 = _pos / _fpp;
173         framecnt_t x1 = (_pos + n_samples) / _fpp;
174         if (x0 == x1) x1 = x0 + 1;
175
176         for (uint32_t i = 0; i < _fft_data_size - 1; ++i) {
177                 const float level = fft_power_at_bin (i, i);
178                 if (level < -fft_range_db) continue;
179                 const float pk = level > 0.0 ? 1.0 : (fft_range_db + level) / fft_range_db;
180 #if 0 // linear
181                 const uint32_t y0 = floor (i * (float) height / _fft_data_size);
182                 uint32_t y1 = ceil ((i + 1.0) * (float) height / _fft_data_size);
183 #else // logscale
184                 const uint32_t y0 = floor (height * logf (1.f + .1f * i) / logf (1.f + .1f * _fft_data_size));
185                 uint32_t y1 = ceilf (height * logf (1.f + .1f * (i + 1.f)) / logf (1.f + .1f * _fft_data_size));
186 #endif
187                 assert (y0 < height);
188                 assert (y1 > 0 && y1 <= height);
189                 if (y0 == y1) y1 = y0 + 1;
190                 for (int x = x0; x < x1; ++x) {
191                         for (uint32_t y = y0; y < y1 && y < height; ++y) {
192                                 uint32_t yy = height - 1 - y;
193                                 if (_result.spectrum[x][yy] < pk) { _result.spectrum[x][yy] = pk; }
194                         }
195                 }
196         }
197
198         _pos += n_samples;
199
200         /* pass audio audio through */
201         ListedSource<float>::output (ctx);
202 }
203
204 ARDOUR::ExportAnalysisPtr
205 Analyser::result ()
206 {
207         //printf ("PROCESSED %ld / %ld samples\n", _pos, _n_samples);
208         if (_pos == 0 || _pos > _n_samples + 1) {
209                 return ARDOUR::ExportAnalysisPtr ();
210         }
211
212         if (_pos + 1 < _n_samples) {
213                 // crude re-bin (silence stripped version)
214                 const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
215                 for (framecnt_t b = peaks - 1; b > 0; --b) {
216                         for (unsigned int c = 0; c < _result.n_channels; ++c) {
217                                 const framecnt_t sb = b * _pos / _n_samples;
218                                 _result.peaks[c][b].min = _result.peaks[c][sb].min;
219                                 _result.peaks[c][b].max = _result.peaks[c][sb].max;
220                         }
221                 }
222
223                 const size_t swh = sizeof (_result.spectrum) / sizeof (float);
224                 const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
225                 const size_t width = swh / height;
226                 for (framecnt_t b = width - 1; b > 0; --b) {
227                         // TODO round down to prev _fft_data_size bin
228                         const framecnt_t sb = b * _pos / _n_samples;
229                         for (unsigned int y = 0; y < height; ++y) {
230                                 _result.spectrum[b][y] = _result.spectrum[sb][y];
231                         }
232                 }
233         }
234
235         if (_ebur_plugin) {
236                 Vamp::Plugin::FeatureSet features = _ebur_plugin->getRemainingFeatures ();
237                 if (!features.empty () && features.size () == 3) {
238                         _result.loudness = features[0][0].values[0];
239                         _result.loudness_range = features[1][0].values[0];
240                         assert (features[2][0].values.size () == 540);
241                         for (int i = 0; i < 540; ++i) {
242                                 _result.loudness_hist[i] = features[2][0].values[i];
243                                 if (_result.loudness_hist[i] > _result.loudness_hist_max) {
244                                         _result.loudness_hist_max = _result.loudness_hist[i]; }
245                         }
246                         _result.have_loudness = true;
247                 }
248         }
249
250         const unsigned cmask = _result.n_channels - 1; // [0, 1]
251         for (unsigned int c = 0; c < _channels; ++c) {
252                 if (!_dbtp_plugin[c]) { continue; }
253                 Vamp::Plugin::FeatureSet features = _dbtp_plugin[c]->getRemainingFeatures ();
254                 if (!features.empty () && features.size () == 2) {
255                         _result.have_dbtp = true;
256                         float p = features[0][0].values[0];
257                         if (p > _result.truepeak) { _result.truepeak = p; }
258
259                         for (std::vector<float>::const_iterator i = features[1][0].values.begin();
260                                         i != features[1][0].values.end(); ++i) {
261                                 const framecnt_t pk = (*i) / _spp;
262                                 const unsigned int cc = c & cmask;
263                                 _result.truepeakpos[cc].insert (pk);
264                         }
265                 }
266         }
267
268         return ARDOUR::ExportAnalysisPtr (new ARDOUR::ExportAnalysis (_result));
269 }
270
271 float
272 Analyser::fft_power_at_bin (const uint32_t b, const float norm) const
273 {
274         const float a = _fft_power[b] * norm;
275         return a > 1e-12 ? 10.0 * fast_log10 (a) : -INFINITY;
276 }