Make Analyzer UI require instance-access
[calf.git] / src / analyzer.cpp
blobfd42188f23d8ed43f0acd8b3e5087d57b52a3edd
1 /* Calf Analyzer FFT Library
2 * Copyright (C) 2007-2013 Krzysztof Foltman, Markus Schmidt,
3 * Christian Holschuh and others
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #include <cairo/cairo.h>
22 #include <limits.h>
23 #include <memory.h>
24 #include <math.h>
25 #include <calf/giface.h>
26 #include <calf/analyzer.h>
27 #include <calf/modules_dev.h>
28 #include <sys/time.h>
29 #include <calf/utils.h>
31 using namespace dsp;
32 using namespace calf_plugins;
34 #define sinc(x) (!x) ? 1 : sin(M_PI * x)/(M_PI * x);
35 #define RGBAtoINT(r, g, b, a) ((uint32_t)(r * 255) << 24) + ((uint32_t)(g * 255) << 16) + ((uint32_t)(b * 255) << 8) + (uint32_t)(a * 255)
37 analyzer::analyzer() {
38 _accuracy = -1;
39 _acc = -1;
40 _scale = -1;
41 _mode = -1;
42 _post = -1;
43 _hold = -1;
44 _smooth = -1;
45 _resolution = -1.f;
46 _offset = -1.f;
47 _freeze = -1;
48 _view = -1;
49 _windowing = -1;
50 _speed = -1;
51 fpos = 0;
52 _draw_upper = 0;
53 sanitize = true;
54 recreate_plan = true;
56 spline_buffer = (int*) calloc(200, sizeof(int));
58 fft_buffer = (float*) calloc(max_fft_buffer_size, sizeof(float));
60 fft_inL = (float*) calloc(max_fft_cache_size, sizeof(float));
61 fft_outL = (float*) calloc(max_fft_cache_size, sizeof(float));
62 fft_inR = (float*) calloc(max_fft_cache_size, sizeof(float));
63 fft_outR = (float*) calloc(max_fft_cache_size, sizeof(float));
65 fft_smoothL = (float*) calloc(max_fft_cache_size, sizeof(float));
66 fft_smoothR = (float*) calloc(max_fft_cache_size, sizeof(float));
68 fft_deltaL = (float*) calloc(max_fft_cache_size, sizeof(float));
69 fft_deltaR = (float*) calloc(max_fft_cache_size, sizeof(float));
71 fft_holdL = (float*) calloc(max_fft_cache_size, sizeof(float));
72 fft_holdR = (float*) calloc(max_fft_cache_size, sizeof(float));
74 fft_freezeL = (float*) calloc(max_fft_cache_size, sizeof(float));
75 fft_freezeR = (float*) calloc(max_fft_cache_size, sizeof(float));
77 analyzer_phase_drawn = 0;
79 analyzer::~analyzer()
81 free(fft_freezeR);
82 free(fft_freezeL);
83 free(fft_holdR);
84 free(fft_holdL);
85 free(fft_deltaR);
86 free(fft_deltaL);
87 free(fft_smoothR);
88 free(fft_smoothL);
89 free(fft_outR);
90 free(fft_outL);
91 free(fft_inR);
92 free(fft_inL);
93 free(spline_buffer);
95 void analyzer::set_sample_rate(uint32_t sr) {
96 srate = sr;
99 void analyzer::set_params(float resolution, float offset, int accuracy, int hold, int smoothing, int mode, int scale, int post, int speed, int windowing, int view, int freeze)
101 _speed = speed;
102 _windowing = windowing;
103 _freeze = freeze;
104 _view = view;
106 if(accuracy != _acc) {
107 _accuracy = 1 << (7 + (int)accuracy);
108 _acc = accuracy;
109 recreate_plan = true;
111 if(hold != _hold) {
112 _hold = hold;
113 sanitize = true;
115 if(smoothing != _smooth) {
116 _smooth = smoothing;
117 sanitize = true;
119 if (mode != _mode) {
120 _mode = mode;
121 sanitize = true;
122 redraw_graph = true;
124 if(scale != _scale) {
125 _scale = scale;
126 sanitize = true;
128 if(post != _post) {
129 _post = post;
130 sanitize = true;
132 if(resolution != _resolution || offset != _offset) {
133 _resolution = resolution;
134 _offset = offset;
135 redraw_graph = true;
138 void analyzer::process(float L, float R) {
139 fft_buffer[fpos] = L;
140 fft_buffer[fpos + 1] = R;
141 fpos += 2;
142 fpos %= (max_fft_buffer_size - 2);
145 bool analyzer::do_fft(int subindex, int points) const
147 if (recreate_plan) {
148 lintrans = -1;
149 recreate_plan = false;
150 sanitize = true;
152 if (sanitize) {
153 // null the overall buffer
154 dsp::zero(fft_inL, max_fft_cache_size);
155 dsp::zero(fft_inR, max_fft_cache_size);
156 dsp::zero(fft_outL, max_fft_cache_size);
157 dsp::zero(fft_outR, max_fft_cache_size);
158 dsp::zero(fft_holdL, max_fft_cache_size);
159 dsp::zero(fft_holdR, max_fft_cache_size);
160 dsp::zero(fft_smoothL, max_fft_cache_size);
161 dsp::zero(fft_smoothR, max_fft_cache_size);
162 dsp::zero(fft_deltaL, max_fft_cache_size);
163 dsp::zero(fft_deltaR, max_fft_cache_size);
164 dsp::zero(spline_buffer, 200);
165 analyzer_phase_drawn = 0;
166 sanitize = false;
169 bool fftdone = false; // if fft was renewed, this one is set to true
170 int __speed = 16 - (int)_speed;
171 if(_mode == 5 and _smooth) {
172 // there's no falling for difference mode, only smoothing
173 _smooth = 2;
175 if(_mode > 5 and _mode < 11) {
176 // there's no smoothing for spectralizer mode
177 //_smooth = 0;
180 if(subindex == 0) {
181 // #####################################################################
182 // We are doing FFT here, so we first have to setup fft-buffers from
183 // the main buffer and we use this cycle for filling other buffers
184 // like smoothing, delta and hold
185 // #####################################################################
186 if(!((int)analyzer_phase_drawn % __speed)) {
187 // seems we have to do a fft, so let's read the latest data from the
188 // buffer to send it to fft afterwards
189 // we want to remember old fft_out values for smoothing as well
190 // and we fill the hold buffer in this (extra) cycle
191 for(int i = 0; i < _accuracy; i++) {
192 // go to the right position back in time according to accuracy
193 // settings and cycling in the main buffer
194 int _fpos = (fpos - _accuracy * 2 \
195 + (i * 2)) % max_fft_buffer_size;
196 if(_fpos < 0)
197 _fpos = max_fft_buffer_size + _fpos;
198 float L = fft_buffer[_fpos];
199 float R = fft_buffer[_fpos + 1];
200 float win = 0.54 - 0.46 * cos(2 * M_PI * i / _accuracy);
201 L *= win;
202 R *= win;
204 // #######################################
205 // Do some windowing functions on the
206 // buffer
207 // #######################################
208 int _m = 2;
209 float _f = 1.f;
210 float _a, a0, a1, a2, a3;
211 switch(_windowing) {
212 case 0:
213 default:
214 // Linear
215 _f = 1.f;
216 break;
217 case 1:
218 // Hamming
219 _f = 0.54 + 0.46 * cos(2 * M_PI * (i - 2 / points));
220 break;
221 case 2:
222 // von Hann
223 _f = 0.5 * (1 + cos(2 * M_PI * (i - 2 / points)));
224 break;
225 case 3:
226 // Blackman
227 _a = 0.16;
228 a0 = 1.f - _a / 2.f;
229 a1 = 0.5;
230 a2 = _a / 2.f;
231 _f = a0 + a1 * cos((2.f * M_PI * i) / points - 1) + \
232 a2 * cos((4.f * M_PI * i) / points - 1);
233 break;
234 case 4:
235 // Blackman-Harris
236 a0 = 0.35875;
237 a1 = 0.48829;
238 a2 = 0.14128;
239 a3 = 0.01168;
240 _f = a0 - a1 * cos((2.f * M_PI * i) / points - 1) + \
241 a2 * cos((4.f * M_PI * i) / points - 1) - \
242 a3 * cos((6.f * M_PI * i) / points - 1);
243 break;
244 case 5:
245 // Blackman-Nuttall
246 a0 = 0.3653819;
247 a1 = 0.4891775;
248 a2 = 0.1365995;
249 a3 = 0.0106411;
250 _f = a0 - a1 * cos((2.f * M_PI * i) / points - 1) + \
251 a2 * cos((4.f * M_PI * i) / points - 1) - \
252 a3 * cos((6.f * M_PI * i) / points - 1);
253 break;
254 case 6:
255 // Sine
256 _f = sin((M_PI * i) / (points - 1));
257 break;
258 case 7:
259 // Lanczos
260 _f = sinc((2.f * i) / (points - 1) - 1);
261 break;
262 case 8:
263 // Gauß
264 _a = 2.718281828459045;
265 _f = pow(_a, -0.5f * pow((i - (points - 1) / 2) / (0.4 * (points - 1) / 2.f), 2));
266 break;
267 case 9:
268 // Bartlett
269 _f = (2.f / (points - 1)) * (((points - 1) / 2.f) - \
270 fabs(i - ((points - 1) / 2.f)));
271 break;
272 case 10:
273 // Triangular
274 _f = (2.f / points) * ((2.f / points) - fabs(i - ((points - 1) / 2.f)));
275 break;
276 case 11:
277 // Bartlett-Hann
278 a0 = 0.62;
279 a1 = 0.48;
280 a2 = 0.38;
281 _f = a0 - a1 * fabs((i / (points - 1)) - 0.5) - \
282 a2 * cos((2 * M_PI * i) / (points - 1));
283 break;
285 L *= _f;
286 if(_mode > _m)
287 R *= _f;
289 // perhaps we need to compute two FFT's, so store left and right
290 // channel in case we need only one FFT, the left channel is
291 // used as 'standard'"
292 float valL;
293 float valR;
295 switch(_mode) {
296 default:
297 // left channel (mode 1)
298 // or both channels (mode 3, 4, 5, 7, 9, 10)
299 valL = L;
300 valR = R;
301 break;
302 case 0:
303 case 6:
304 // average (mode 0)
305 valL = (L + R) / 2;
306 valR = (L + R) / 2;
307 break;
308 case 2:
309 case 8:
310 // right channel (mode 2)
311 valL = R;
312 valR = L;
313 break;
315 // store values in analyzer buffer
316 fft_inL[i] = valL;
317 fft_inR[i] = valR;
319 // fill smoothing & falling buffer
320 if(_smooth == 2) {
321 fft_smoothL[i] = fft_outL[i];
322 fft_smoothR[i] = fft_outR[i];
324 if(_smooth == 1) {
325 if(fft_smoothL[i] < fabs(fft_outL[i])) {
326 fft_smoothL[i] = fabs(fft_outL[i]);
327 fft_deltaL[i] = 1.f;
329 if(fft_smoothR[i] < fabs(fft_outR[i])) {
330 fft_smoothR[i] = fabs(fft_outR[i]);
331 fft_deltaR[i] = 1.f;
335 // fill hold buffer with last out values
336 // before fft is recalced
337 if(fabs(fft_outL[i]) > fft_holdL[i])
338 fft_holdL[i] = fabs(fft_outL[i]);
339 if(fabs(fft_outR[i]) > fft_holdR[i])
340 fft_holdR[i] = fabs(fft_outR[i]);
343 // run fft
344 // this takes our latest buffer and returns an array with
345 // non-normalized
346 fft.execute_r2r(_acc + 7, fft_inL, fft_outL, fft_temp, false);
347 //run fft for for right channel too. it is needed for stereo image
348 //and stereo difference modes
349 if(_mode >= 3) {
350 fft.execute_r2r(_acc + 7, fft_inR, fft_outR, fft_temp, false);
352 // ...and set some values for later use
353 analyzer_phase_drawn = 0;
354 fftdone = true;
356 analyzer_phase_drawn ++;
358 return fftdone;
361 void analyzer::draw(int subindex, float *data, int points, bool fftdone) const
363 double freq; // here the frequency of the actual drawn pixel gets stored
364 int iter = 0; // this is the pixel we have been drawing the last box/bar/line
365 int _iter = 1; // this is the next pixel we want to draw a box/bar/line
366 int _last = -1; // used for mode 10 (parallel spectralizer) to prevent overwriting real values with INFINITY
367 float posneg = 1;
368 int __speed = 16 - (int)_speed;
369 if (lintrans < 0) {
370 // accuracy was changed so we have to recalc linear transition
371 int _lintrans = (int)((float)points * log((20.f + 2.f * \
372 (float)srate / (float)_accuracy) / 20.f) / log(1000.f));
373 lintrans = (int)(_lintrans + points % _lintrans / \
374 floor(points / _lintrans)) / 2; // / 4 was added to see finer bars but breaks low end
376 for (int i = 0; i <= points; i++)
378 // #####################################################################
379 // Real business starts here. We will cycle through all pixels in
380 // x-direction of the line-graph and decide what to show
381 // #####################################################################
382 // cycle through the points to draw
383 // we need to know the exact frequency at this pixel
384 freq = 20.f * pow (1000.f, (float)i / points);
386 // we need to know the last drawn value over the time
387 float lastoutL = 0.f;
388 float lastoutR = 0.f;
390 // let's see how many pixels we may want to skip until the drawing
391 // function has to draw a bar/box/line
392 if(_scale or _view == 2) {
393 // we have linear view enabled or we want to see tit... erm curves
394 if((i % lintrans == 0 and points - i > lintrans) or i == points - 1) {
395 _iter = std::max(1, (int)floor(freq * \
396 (float)_accuracy / (float)srate));
398 } else {
399 // we have logarithmic view enabled
400 _iter = std::max(1, (int)floor(freq * (float)_accuracy / (float)srate));
402 if(_iter > iter) {
403 // we are flipping one step further in drawing
404 if(fftdone and i) {
405 // ################################
406 // Manipulate the fft_out values
407 // according to the post processing
408 // ################################
409 int n = 0;
410 float var1L = 0.f; // used later for denoising peaks
411 float var1R = 0.f;
412 float diff_fft;
413 switch(_mode) {
414 default:
415 // all normal modes
416 posneg = 1;
417 // only if we don't see difference mode
418 switch(_post) {
419 case 0:
420 // Analyzer Normalized - nothing to do
421 break;
422 case 1:
423 // Analyzer Additive - cycle through skipped values and
424 // add them
425 // if fft was renewed, recalc the absolute values if
426 // frequencies are skipped
427 for(int j = iter + 1; j < _iter; j++) {
428 fft_outL[_iter] += fabs(fft_outL[j]);
429 fft_outR[_iter] += fabs(fft_outR[j]);
431 fft_outL[_iter] /= (_iter - iter);
432 fft_outR[_iter] /= (_iter - iter);
433 break;
434 case 2:
435 // Analyzer Additive - cycle through skipped values and
436 // add them
437 // if fft was renewed, recalc the absolute values if
438 // frequencies are skipped
439 for(int j = iter + 1; j < _iter; j++) {
440 fft_outL[_iter] += fabs(fft_outL[j]);
441 fft_outR[_iter] += fabs(fft_outR[j]);
443 break;
444 case 3:
445 // Analyzer Denoised Peaks - filter out unwanted noise
446 for(int k = 0; k < std::max(10 , std::min(400 ,\
447 (int)(2.f*(float)((_iter - iter))))); k++) {
448 //collect amplitudes in the environment of _iter to
449 //be able to erase them from signal and leave just
450 //the peaks
451 if(_iter - k > 0) {
452 var1L += fabs(fft_outL[_iter - k]);
453 n++;
455 if(k != 0) var1L += fabs(fft_outL[_iter + k]);
456 else if(i) var1L += fabs(lastoutL);
457 else var1L += fabs(fft_outL[_iter]);
458 if(_mode == 3 or _mode == 4) {
459 if(_iter - k > 0) {
460 var1R += fabs(fft_outR[_iter - k]);
461 n++;
463 if(k != 0) var1R += fabs(fft_outR[_iter + k]);
464 else if(i) var1R += fabs(lastoutR);
465 else var1R += fabs(fft_outR[_iter]);
467 n++;
469 //do not forget fft_out[_iter] for the next time
470 lastoutL = fft_outL[_iter];
471 //pumping up actual signal an erase surrounding
472 // sounds
473 fft_outL[_iter] = 0.25f * std::max(n * 0.6f * \
474 fabs(fft_outL[_iter]) - var1L , 1e-20);
475 if(_mode == 3 or _mode == 4) {
476 // do the same with R channel if needed
477 lastoutR = fft_outR[_iter];
478 fft_outR[_iter] = 0.25f * std::max(n * \
479 0.6f * fabs(fft_outR[_iter]) - var1R , 1e-20);
481 break;
483 break;
484 case 5:
485 // Stereo Difference - draw the difference between left
486 // and right channel if fft was renewed, recalc the
487 // absolute values in left and right if frequencies are
488 // skipped.
489 // this is additive mode - no other mode is available
490 //for(int j = iter + 1; j < _iter; j++) {
491 // fft_outL[_iter] += fabs(fft_outL[j]);
492 // fft_outR[_iter] += fabs(fft_outR[j]);
494 //calculate difference between left an right channel
495 diff_fft = fabs(fft_outL[_iter]) - fabs(fft_outR[_iter]);
496 posneg = fabs(diff_fft) / diff_fft;
497 //fft_outL[_iter] = diff_fft / _accuracy;
498 break;
501 iter = _iter;
502 // #######################################
503 // Calculate transitions for falling and
504 // smooting and fill delta buffers if fft
505 // was done above
506 // #######################################
507 if(subindex == 0) {
508 float _fdelta = 0.91;
509 float _ffactor = 2000.f;
511 if(_mode > 5 and _mode < 11) {
512 _fdelta = .99f;
513 _ffactor = 50.f;
515 if(_smooth == 2) {
516 // smoothing
517 if(fftdone) {
518 // rebuild delta values after fft was done
519 if(_mode < 5 or _mode > 5) {
520 fft_deltaL[iter] = pow(fabs(fft_outL[iter]) / fabs(fft_smoothL[iter]), 1.f / __speed);
521 } else {
522 fft_deltaL[iter] = (posneg * fabs(fft_outL[iter]) - fft_smoothL[iter]) / __speed;
524 } else {
525 // change fft_smooth according to delta
526 if(_mode < 5 or _mode > 5) {
527 fft_smoothL[iter] *= fft_deltaL[iter];
528 } else {
529 fft_smoothL[iter] += fft_deltaL[iter];
532 } else if(_smooth == 1) {
533 // falling
534 if(fftdone) {
535 // rebuild delta values after fft was done
536 //fft_deltaL[iter] = _fdelta;
538 // change fft_smooth according to delta
539 fft_smoothL[iter] *= fft_deltaL[iter];
541 if(fft_deltaL[iter] > _fdelta) {
542 fft_deltaL[iter] *= 1.f - (16.f - __speed) / _ffactor;
546 if((_mode > 2 and _mode < 5) or (_mode > 8 and _mode < 11)) {
547 // we need right buffers, too for stereo image and
548 // stereo analyzer
549 if(_smooth == 2) {
550 // smoothing
551 if(fftdone) {
552 // rebuild delta values after fft was done
553 if(_mode < 5) {
554 fft_deltaR[iter] = pow(fabs(fft_outR[iter]) / fabs(fft_smoothR[iter]), 1.f / __speed);
555 } else {
556 fft_deltaR[iter] = (posneg * fabs(fft_outR[iter]) - fft_smoothR[iter]) / __speed;
558 } else {
559 // change fft_smooth according to delta
560 if(_mode < 5) {
561 fft_smoothR[iter] *= fft_deltaR[iter];
562 } else {
563 fft_smoothR[iter] += fft_deltaR[iter];
566 } else if(_smooth == 1) {
567 // falling
568 if(fftdone) {
569 // rebuild delta values after fft was done
570 //fft_deltaR[iter] = _fdelta;
572 // change fft_smooth according to delta
573 fft_smoothR[iter] *= fft_deltaR[iter];
574 if(fft_deltaR[iter] > _fdelta)
575 fft_deltaR[iter] *= 1.f - (16.f - __speed) / _ffactor;
579 // #######################################
580 // Choose the L and R value from the right
581 // buffer according to view settings
582 // #######################################
583 float valL = 0.f;
584 float valR = 0.f;
585 if (_freeze) {
586 // freeze enabled
587 valL = fft_freezeL[iter];
588 valR = fft_freezeR[iter];
589 } else if ((subindex == 1 and _mode < 3) \
590 or subindex > 1 \
591 or (_mode > 5 and _hold)) {
592 // we draw the hold buffer
593 valL = fft_holdL[iter];
594 valR = fft_holdR[iter];
595 } else {
596 // we draw normally (no freeze)
597 switch(_smooth) {
598 case 0:
599 // off
600 valL = fft_outL[iter];
601 valR = fft_outR[iter];
602 break;
603 case 1:
604 // falling
605 valL = fft_smoothL[iter];
606 valR = fft_smoothR[iter];
607 break;
608 case 2:
609 // smoothing
610 valL = fft_smoothL[iter];
611 valR = fft_smoothR[iter];
612 break;
614 // fill freeze buffer
615 fft_freezeL[iter] = valL;
616 fft_freezeR[iter] = valR;
618 if(_view < 2) {
619 // #####################################
620 // send values back to painting function
621 // according to mode setting but only if
622 // we are drawing lines or boxes
623 // #####################################
624 float tmp;
625 int pos1, pos2;
626 switch(_mode) {
627 case 3:
628 case 9:
629 // stereo analyzer/spectralizer
630 if(subindex == 0 or subindex == 2) {
631 data[i] = dB_grid(fabs(valL) / _accuracy * 2.f + 1e-20, _resolution, _offset);
632 } else {
633 data[i] = dB_grid(fabs(valR) / _accuracy * 2.f + 1e-20, _resolution, _offset);
635 break;
636 case 4:
637 // we want to draw Stereo Image
638 if(subindex == 0 or subindex == 2) {
639 // Left channel signal
640 tmp = dB_grid(fabs(valL) / _accuracy * 2.f + 1e-20, _resolution, _offset);
641 //only signals above the middle are interesting
642 data[i] = tmp < 0 ? 0 : tmp;
643 } else if (subindex == 1 or subindex == 3) {
644 // Right channel signal
645 tmp = dB_grid(fabs(valR) / _accuracy * 2.f + 1e-20, _resolution, _offset);
646 //only signals above the middle are interesting. after cutting away
647 //the unneeded stuff, the curve is flipped vertical at the middle.
648 if(tmp < 0) tmp = 0;
649 data[i] = -1.f * tmp;
651 break;
652 case 5:
653 // We want to draw Stereo Difference
654 if(i) {
655 tmp = dB_grid(fabs((fabs(valL) - fabs(valR))) / _accuracy * 2.f + 1e-20, _resolution, 1.f / _offset);
656 //only show differences above a threshhold which results from the db_grid-calculation
657 if (tmp < 0) tmp=0;
658 //bring right signals below the middle
659 tmp *= fabs(valL) < fabs(valR) ? -1.f : 1.f;
660 data[i] = tmp;
662 else data[i] = 0.f;
663 break;
664 case 10:
665 // spectralizer parallel
666 pos1 = i / 2;
667 pos2 = points / 2 + pos1;
668 data[pos1] = dB_grid(fabs(valL) / _accuracy * 2.f + 1e-20, _resolution, _offset);
669 data[pos2] = dB_grid(fabs(valR) / _accuracy * 2.f + 1e-20, _resolution, _offset);
670 _last = pos1;
671 break;
672 default:
673 // normal analyzer behavior
674 data[i] = dB_grid(fabs(valL) / _accuracy * 2.f + 1e-20, _resolution, _offset);
675 break;
679 else if(_view == 2) {
680 // we have to draw splines, so we draw every x-pixel according to
681 // the pre-generated fft_splinesL and fft_splinesR buffers
682 data[i] = INFINITY;
684 // int _splinepos = -1;
685 // *mode=0;
687 // for (int i = 0; i<=points; i++) {
688 // if (subindex == 1 and i == spline_buffer[_splinepos]) _splinepos++;
690 // freq = 20.f * pow (1000.f, (float)i / points); //1000=20000/20
691 // float a0,b0,c0,d0,a1,b1,c1,d1,a2,b2,c2,d2;
693 // if(((i % lintrans == 0 and points - i > lintrans) or i == points - 1 ) and subindex == 0) {
695 // _iter = std::max(1, (int)floor(freq * (float)_accuracy / (float)srate));
696 // //printf("_iter %3d\n",_iter);
697 // }
698 // if(_iter > iter and subindex == 0)
699 // {
700 // _splinepos++;
701 // spline_buffer[_splinepos] = _iter;
702 // //printf("_splinepos: %3d - lintrans: %3d\n", _splinepos,lintrans);
703 // if(fftdone and i and subindex == 0)
704 // {
705 // // if fft was renewed, recalc the absolute values if frequencies
706 // // are skipped
707 // for(int j = iter + 1; j < _iter; j++) {
708 // fft_out[_iter] += fabs(fft_out[j]);
709 // }
710 // }
711 // }
713 // if(fftdone and subindex == 1 and _splinepos >= 0 and (_splinepos % 3 == 0 or _splinepos == 0))
714 // {
715 // float mleft, mright, y0, y1, y2, y3, y4;
717 // //jetzt spline interpolation
718 // y0 = dB_grid(fft_out[spline_buffer[_splinepos]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
719 // y1 = dB_grid(fft_out[spline_buffer[_splinepos + 1]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
720 // y2 = dB_grid(fft_out[spline_buffer[_splinepos + 2]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
721 // y3 = dB_grid(fft_out[spline_buffer[_splinepos + 3]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
722 // y4 = dB_grid(fft_out[spline_buffer[_splinepos + 4]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
723 // mleft = y1 - y0;
724 // mright = y4 - y3;
725 // printf("y-werte %3d, %3d, %3d, %3d, %3d\n",y0,y1,y2,y3,y4);
726 // a0 = (-3*y3+15*y2-44*y1+32*y0+mright+22*mleft)/34;
727 // b0 = -(-3*y3+15*y2-78*y1+66*y0+mright+56*mleft)/34;
728 // c0 = mleft;
729 // d0 = y0;
730 // a1 = -(-15*y3+41*y2-50*y1+24*y0+5*mright+8*mleft)/34;
731 // b1 = (-6*y3+30*y2-54*y1+30*y0+2*mright+10*mleft)/17;
732 // c1 = -(3*y3-15*y2-24*y1+36*y0-mright+12*mleft)/34;
733 // d1 = y1;
734 // a2 = (-25*y3+40*y2-21*y1+6*y0+14*mright+2*mleft)/17;
735 // b2 = -(-33*y3+63*y2-42*y1+12*y0+11*mright+4*mleft)/17;
736 // c2 = (9*y3+6*y2-21*y1+6*y0-3*mright+2*mleft)/17;
737 // d2 = y2;
738 // }
739 // iter = _iter;
742 // if(i > spline_buffer[_splinepos] and i <= spline_buffer[_splinepos + 1] and _splinepos >= 0 and subindex == 1)
743 // {
744 // data[i] = a0 * pow(i / lintrans - _splinepos, 3) + b0 * pow(i / lintrans - _splinepos, 2) + c0 * (i / lintrans - _splinepos) + d0;
745 // printf("1.spline\n");
746 // }
747 // if(i > spline_buffer[_splinepos + 1] and i <= spline_buffer[_splinepos + 2] and _splinepos >= 0 and subindex == 1)
748 // {
749 // printf("2.spline\n");
750 // data[i] = a1 * pow(i / lintrans - _splinepos, 3) + b1 * pow(i / lintrans - _splinepos, 2) + c1 * (i / lintrans - _splinepos) + d1;
751 // }
752 // if(i > spline_buffer[_splinepos + 2] and i <= spline_buffer[_splinepos + 3] and _splinepos >= 0 and subindex == 1)
753 // {
754 // printf("3.spline\n");
755 // data[i] = a2 * pow(i / lintrans - _splinepos, 3) + b2 * pow(i / lintrans - _splinepos, 2) + c2 * (i / lintrans - _splinepos) + d2;
756 // }
757 // if(subindex==1) printf("data[i] %3d _splinepos %2d\n", data[i], _splinepos);
758 // if (subindex == 0)
759 // {
760 // data[i] = INFINITY;
761 // } else data[i] = dB_grid(i/200, pow(64, _level), 0.5f);
763 // }
766 else {
767 if (_mode != 10)
768 data[i] = INFINITY;
769 else if (_last != i / 2) {
770 data[i / 2] = INFINITY;
771 data[points / 2 + i / 2] = INFINITY;
777 bool analyzer::get_graph(int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
779 if (!phase)
780 return false;
782 if ((subindex == 1 and !_hold and _mode < 3) \
783 or (subindex > 1 and _mode < 3) \
784 or (subindex == 2 and !_hold and (_mode == 3 or _mode == 4)) \
785 or (subindex == 4 and (_mode == 3 or _mode == 4)) \
786 or (subindex == 1 and _mode == 5) \
787 or _mode > 5 \
789 // stop drawing when all curves have been drawn according to the mode
790 // and hold settings
791 return false;
793 bool fftdone = false;
794 if (!subindex)
795 fftdone = do_fft(subindex, points);
796 draw(subindex, data, points, fftdone);
798 // #############################
799 // choose a drawing mode between
800 // boxes, lines and bars
801 // #############################
803 // modes:
804 // 0: left
805 // 1: right
806 // 2: average
807 // 3: stereo
808 // 4: image
809 // 5: difference
811 // views:
812 // 0: bars
813 // 1: lines
814 // 2: cubic splines
816 // *modes to set:
817 // 0: lines
818 // 1: blob
819 // 2: bars
820 // 3: boxes (little things on the values position
821 // 4: centered bars (0dB is centered in y direction)
823 if (_mode > 3 and _mode < 6) {
824 // centered viewing modes like stereo image and stereo difference
825 if(!_view) {
826 // boxes
827 if(subindex > 1) {
828 // boxes (hold)
829 *mode = 3;
830 } else {
831 // bars (signal)
832 *mode = 4;
834 } else {
835 // lines
836 *mode = 0;
838 } else if(!_view) {
839 // bars
840 if((subindex == 0 and _mode < 3) or (subindex <= 1 and _mode == 3)) {
841 // draw bars
842 *mode = 2;
843 } else {
844 // draw boxes
845 *mode = 3;
847 } else {
848 // draw lines
849 *mode = 0;
851 // ###################################
852 // colorize the curves/boxes according
853 // to the chosen display settings
854 // ###################################
856 // change alpha (or color) for hold lines or stereo modes
857 if((subindex == 1 and _mode < 3) or (subindex > 1 and _mode == 4)) {
858 // subtle hold line on left, right, average or stereo image
859 context->set_source_rgba(0.15, 0.2, 0.0, 0.2);
861 if(subindex == 0 and _mode == 3) {
862 // left channel in stereo analyzer
863 context->set_source_rgba(0.25, 0.10, 0.0, 0.33);
865 if(subindex == 1 and _mode == 3) {
866 // right channel in stereo analyzer
867 context->set_source_rgba(0.05, 0.25, 0.0, 0.33);
869 if(subindex == 2 and _mode == 3) {
870 // left hold in stereo analyzer
871 context->set_source_rgba(0.45, 0.30, 0.2, 0.2);
873 if(subindex == 3 and _mode == 3) {
874 // right hold in stereo analyzer
875 context->set_source_rgba(0.25, 0.45, 0.2, 0.2);
878 context->set_line_width(0.75);
879 return true;
882 bool analyzer::get_moving(int subindex, int &direction, float *data, int x, int y, int &offset, uint32_t &color) const
884 if ((subindex and _mode != 9) or subindex > 1)
885 return false;
886 bool fftdone = false;
887 if (!subindex)
888 fftdone = do_fft(subindex, x);
889 draw(subindex, data, x, fftdone);
890 direction = LG_MOVING_UP;
891 offset = 0;
892 if (_mode == 9 and subindex) {
893 color = RGBAtoINT(0.35, 0.1, 0, 0.4);
894 } else if (_mode == 9) {
895 color = RGBAtoINT(0.15, 0.35, 0, 0.4);
897 return true;
900 bool analyzer::get_gridline(int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
902 if (phase)
903 return false;
904 redraw_graph = false;
905 float gain;
906 int sub = subindex + (_draw_upper % 2) - 1;
907 static const double dash[] = {2.0};
908 switch (_mode) {
909 case 0:
910 case 1:
911 case 2:
912 case 3:
913 default:
914 return get_freq_gridline(subindex, pos, vertical, legend, context, true, _resolution, _offset);
915 case 4:
916 // stereo image
917 if(subindex < 28)
918 return get_freq_gridline(subindex, pos, vertical, legend, context, true);
919 else {
920 subindex -= 28;
922 gain = _draw_upper > 0 ? 1.f / (1 << (subindex - _draw_upper))
923 : 1.f / (1 << subindex);
924 pos = dB_grid(gain, _resolution, _offset);
925 if (_draw_upper > 0)
926 pos *= -1;
928 context->set_dash(dash, 1);
929 if ((!(subindex & 1) and !_draw_upper)
930 or ((sub & 1) and _draw_upper > 0)) {
931 // add a label and make the lines straight
932 std::stringstream ss;
933 ss << (subindex - std::max(0, _draw_upper)) * -6 << " dB";
934 legend = ss.str();
935 context->set_dash(dash, 0);
938 if (pos < 0 and !_draw_upper) {
939 // start drawing the lower end
940 _draw_upper = subindex;
941 pos = -2;
943 if (_draw_upper < 0) {
944 // end the drawing of the grid
945 _draw_upper = 0;
946 return false;
948 if (pos > 0 and _draw_upper > 0) {
949 // center line
950 _draw_upper = -1;
951 pos = 0;
952 context->set_dash(dash, 0);
954 else if (subindex)
955 context->set_source_rgba(0, 0, 0, 0.1);
956 vertical = false;
957 return true;
958 case 5:
959 // stereo difference
960 if(subindex < 28)
961 return get_freq_gridline(subindex, pos, vertical, legend, context, true);
962 else
963 subindex -= 28;
965 gain = _draw_upper > 0 ? 1.0 / (1 << (subindex - _draw_upper))
966 : (1 << subindex);
967 pos = dB_grid(gain, _resolution, 0);
969 context->set_dash(dash, 1);
970 if ((!(subindex & 1) and !_draw_upper)
971 or ((subindex & 1) and _draw_upper)) {
972 std::stringstream ss;
973 ss << (subindex - std::max(0, _draw_upper)) * 6 - 72 << " dB";
974 legend = ss.str();
975 context->set_dash(dash, 0);
978 if (pos > 1 and !_draw_upper and (subindex & 1)) {
979 _draw_upper = subindex;
981 if (pos < -1 and _draw_upper) {
982 _draw_upper = 0;
983 return false;
986 if (subindex)
987 context->set_source_rgba(0, 0, 0, 0.1);
988 vertical = false;
989 return true;
990 case 6:
991 case 7:
992 case 8:
993 case 9:
994 if (subindex < 28) {
995 vertical = true;
996 if (subindex == 9) legend = "100 Hz";
997 if (subindex == 18) legend = "1 kHz";
998 if (subindex == 27) legend = "10 kHz";
1000 float freq = subindex_to_freq(subindex);
1001 pos = log(freq / 20.0) / log(1000);
1003 if (!legend.empty()) {
1004 context->set_source_rgba(0, 0, 0, 0.33);
1005 } else {
1006 context->set_source_rgba(0, 0, 0, 0.2);
1008 return true;
1010 return false;
1011 case 10:
1012 //if (!subindex) {
1013 //cairo_t *ctx = context->context;
1014 //cairo_set_source_rgb(ctx, 0.35, 0.4, 0.2);
1015 //cairo_select_font_face(ctx, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
1016 //cairo_set_font_size(ctx, 20);
1017 //cairo_move_to (ctx, context->size_x / 2 - 20, 40);
1018 //cairo_show_text (ctx, "L");
1019 //cairo_move_to (ctx, context->size_x / 2 + 12, 40);
1020 //cairo_show_text (ctx, "R");
1022 if (subindex < 56) {
1023 vertical = true;
1024 if (subindex == 9 or subindex == 36) legend = "100 Hz";
1025 if (subindex == 18 or subindex == 45) legend = "1 kHz";
1026 if (subindex == 27 or subindex == 54) legend = "10 kHz";
1028 float freq = subindex_to_freq(subindex - (subindex > 27 ? 27 : 0));
1029 pos = log(freq / 20.0) / log(1000) / 2 + (subindex > 27 ? 0.5 : 0);
1030 if (!legend.empty() and subindex != 28) {
1031 context->set_source_rgba(0, 0, 0, 0.33);
1032 } else if (subindex != 28) {
1033 context->set_source_rgba(0, 0, 0, 0.2);
1035 return true;
1037 return false;
1039 return false;
1042 bool analyzer::get_layers(int generation, unsigned int &layers) const
1044 if (_mode > 5 and _mode < 11)
1045 layers = LG_REALTIME_MOVING;
1046 else
1047 layers = LG_REALTIME_GRAPH;
1048 layers |= ((!generation or redraw_graph) ? LG_CACHE_GRID : 0);
1049 return true;