stereo waveform, prepare spectrum faceplate
[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 Analyser::Analyser (float sample_rate, unsigned int channels, framecnt_t bufsize, framecnt_t n_samples)
25         : _ebur128_plugin (0)
26         , _sample_rate (sample_rate)
27         , _channels (channels)
28         , _bufsize (bufsize / channels)
29         , _n_samples (n_samples)
30         , _pos (0)
31 {
32         assert (bufsize % channels == 0);
33         //printf ("NEW ANALYSER %p r:%.1f c:%d f:%ld l%ld\n", this, sample_rate, channels, bufsize, n_samples);
34         if (channels > 0 && channels <= 2) {
35                 using namespace Vamp::HostExt;
36                 PluginLoader* loader (PluginLoader::getInstance ());
37                 _ebur128_plugin = loader->loadPlugin ("libardourvampplugins:ebur128", sample_rate, PluginLoader::ADAPT_ALL_SAFE);
38                 assert (_ebur128_plugin);
39                 _ebur128_plugin->reset ();
40                 _ebur128_plugin->initialise (channels, _bufsize, _bufsize);
41         }
42         _bufs[0] = (float*) malloc (sizeof (float) * _bufsize);
43         _bufs[1] = (float*) malloc (sizeof (float) * _bufsize);
44
45         const size_t peaks = sizeof (_result.peaks) / sizeof (ARDOUR::PeakData::PeakDatum) / 4;
46         _spp = ceil ((_n_samples + 1.f) / (float) peaks);
47
48         const size_t swh = sizeof (_result.spectrum) / sizeof (float);
49         const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
50         const size_t width = swh / height;
51         _fpp = ceil ((_n_samples + 1.f) / (float) width);
52
53         _fft_data_size   = _bufsize / 2;
54         _fft_freq_per_bin = sample_rate / _fft_data_size / 2.f;
55
56         _fft_data_in  = (float *) fftwf_malloc (sizeof (float) * _bufsize);
57         _fft_data_out = (float *) fftwf_malloc (sizeof (float) * _bufsize);
58         _fft_power    = (float *) malloc (sizeof (float) * _fft_data_size);
59
60         for (uint32_t i = 0; i < _fft_data_size; ++i) {
61                 _fft_power[i] = 0;
62         }
63         for (uint32_t i = 0; i < _bufsize; ++i) {
64                 _fft_data_out[i] = 0;
65         }
66
67         const float nyquist = (sample_rate * .5);
68 #if 0 // linear
69 #define YPOS(FREQ) ceil (height * (1.0 - FREQ / nyquist))
70 #else
71 #define YPOS(FREQ) ceil (height * (1 - logf (1.f + .1f * _fft_data_size * FREQ / nyquist) / logf (1.f + .1f * _fft_data_size)))
72 #endif
73
74         _result.freq[0] = YPOS (50);
75         _result.freq[1] = YPOS (100);
76         _result.freq[2] = YPOS (500);
77         _result.freq[3] = YPOS (1000);
78         _result.freq[4] = YPOS (5000);
79         _result.freq[5] = YPOS (10000);
80
81         _fft_plan = fftwf_plan_r2r_1d (_bufsize, _fft_data_in, _fft_data_out, FFTW_R2HC, FFTW_MEASURE);
82
83         _hann_window = (float *) malloc (sizeof (float) * _bufsize);
84         double sum = 0.0;
85
86         for (uint32_t i = 0; i < _bufsize; ++i) {
87                 _hann_window[i] = 0.5f - (0.5f * (float) cos (2.0f * M_PI * (float)i / (float)(_bufsize)));
88                 sum += _hann_window[i];
89         }
90         const double isum = 2.0 / sum;
91         for (uint32_t i = 0; i < _bufsize; ++i) {
92                 _hann_window[i] *= isum;
93         }
94
95         if (channels == 2) {
96                 _result.n_channels = 2;
97         } else {
98                 _result.n_channels = 1;
99         }
100 }
101
102 Analyser::~Analyser ()
103 {
104         delete _ebur128_plugin;
105         free (_bufs[0]);
106         free (_bufs[1]);
107         fftwf_destroy_plan (_fft_plan);
108         fftwf_free (_fft_data_in);
109         fftwf_free (_fft_data_out);
110         free (_fft_power);
111         free (_hann_window);
112 }
113
114 void
115 Analyser::process (ProcessContext<float> const & c)
116 {
117         framecnt_t n_samples = c.frames () / c.channels ();
118         assert (c.frames () % c.channels () == 0);
119         assert (n_samples <= _bufsize);
120         //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, c.frames (), n_samples, c.channels ());
121         float const * d = c.data ();
122         framecnt_t s;
123         for (s = 0; s < n_samples; ++s) {
124                 _fft_data_in[s] = 0;
125                 const framecnt_t pk = (_pos + s) / _spp;
126                 for (unsigned int c = 0; c < _channels; ++c) {
127                         const float v = *d;
128                         _bufs[c][s] = v;
129                         const unsigned int cc = c % _result.n_channels; // TODO optimize
130                         if (_result.peaks[cc][pk].min > v) { _result.peaks[cc][pk].min = *d; }
131                         if (_result.peaks[cc][pk].max < v) { _result.peaks[cc][pk].max = *d; }
132                         _fft_data_in[s] += v * _hann_window[s] / (float) _channels;
133                         ++d;
134                 }
135         }
136
137         for (; s < _bufsize; ++s) {
138                 _fft_data_in[s] = 0;
139                 for (unsigned int c = 0; c < _channels; ++c) {
140                         _bufs[c][s] = 0.f;
141                 }
142         }
143
144         if (_ebur128_plugin) {
145                 _ebur128_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
146         }
147
148         fftwf_execute (_fft_plan);
149
150         _fft_power[0] = _fft_data_out[0] * _fft_data_out[0];
151 #define FRe (_fft_data_out[i])
152 #define FIm (_fft_data_out[_bufsize - i])
153         for (uint32_t i = 1; i < _fft_data_size - 1; ++i) {
154                 _fft_power[i] = (FRe * FRe) + (FIm * FIm);
155         }
156 #undef FRe
157 #undef FIm
158
159         const size_t height = sizeof (_result.spectrum[0]) / sizeof (float);
160         const framecnt_t x0 = _pos / _fpp;
161         framecnt_t x1 = (_pos + n_samples) / _fpp;
162         if (x0 == x1) x1 = x0 + 1;
163         const float range = 80; // dB
164
165         for (uint32_t i = 1; i < _fft_data_size - 1; ++i) {
166                 const float level = fft_power_at_bin (i, i);
167                 if (level < -range) continue;
168                 const float pk = level > 0.0 ? 1.0 : (range + level) / range;
169 #if 0 // linear
170                 const uint32_t y0 = height - ceil (i * (float) height / _fft_data_size);
171                 uint32_t y1= height - ceil (i * (float) height / _fft_data_size);
172 #else // logscale
173                 const uint32_t y0 = height - ceilf (height * logf (1.f + .1f * i) / logf (1.f + .1f * _fft_data_size));
174                 uint32_t y1 = height - ceilf (height * logf (1.f + .1f * (i + 1.f)) / logf (1.f + .1f * _fft_data_size));
175 #endif
176                 if (y0 == y1 && y0 > 0) y1 = y0 - 1;
177                 for (int x = x0; x < x1; ++x) {
178                         for (uint32_t y = y0; y > y1; --y) {
179                                 if (_result.spectrum[x][y] < pk) { _result.spectrum[x][y] = pk; }
180                         }
181                 }
182         }
183
184         _pos += n_samples;
185
186         /* pass audio audio through */
187         ListedSource<float>::output (c);
188 }
189
190 ARDOUR::ExportAnalysisPtr
191 Analyser::result ()
192 {
193         //printf ("PROCESSED %ld / %ld samples\n", _pos, _n_samples);
194         if (_pos == 0) {
195                 return ARDOUR::ExportAnalysisPtr ();
196         }
197         if (_ebur128_plugin) {
198                 Vamp::Plugin::FeatureSet features = _ebur128_plugin->getRemainingFeatures ();
199                 if (!features.empty () && features.size () == 3) {
200                         _result.loudness = features[0][0].values[0];
201                         _result.loudness_range = features[1][0].values[0];
202                         assert (features[2][0].values.size () == 540);
203                         for (int i = 0; i < 540; ++i) {
204                                 _result.loudness_hist[i] = features[2][0].values[i];
205                                 if (_result.loudness_hist[i] > _result.loudness_hist_max) {
206                                         _result.loudness_hist_max = _result.loudness_hist[i]; }
207                         }
208                         _result.have_loudness = true;
209                 }
210         }
211         return ARDOUR::ExportAnalysisPtr (new ARDOUR::ExportAnalysis (_result));
212 }
213
214 float
215 Analyser::fft_power_at_bin (const uint32_t b, const float norm) const
216 {
217         const float a = _fft_power[b] * norm;
218         return a > 1e-12 ? 10.0 * fast_log10 (a) : -INFINITY;
219 }