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>
26 #include <calf/giface.h>
27 #include <calf/analyzer.h>
28 #include <calf/modules_dev.h>
30 #include <calf/utils.h>
33 using namespace calf_plugins
;
35 #define sinc(x) (!x) ? 1 : sin(M_PI * x)/(M_PI * x);
36 #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)
38 analyzer::analyzer() {
57 spline_buffer
= (int*) calloc(200, sizeof(int));
59 fft_buffer
= (float*) calloc(max_fft_buffer_size
, sizeof(float));
61 fft_inL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
62 fft_outL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
63 fft_inR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
64 fft_outR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
66 fft_smoothL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
67 fft_smoothR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
69 fft_deltaL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
70 fft_deltaR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
72 fft_holdL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
73 fft_holdR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
75 fft_freezeL
= (float*) calloc(max_fft_cache_size
, sizeof(float));
76 fft_freezeR
= (float*) calloc(max_fft_cache_size
, sizeof(float));
80 analyzer_phase_drawn
= 0;
98 fftwf_destroy_plan(fft_plan
);
102 void analyzer::set_sample_rate(uint32_t sr
) {
106 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
)
109 _windowing
= windowing
;
113 if(accuracy
!= _acc
) {
114 _accuracy
= 1 << (7 + (int)accuracy
);
116 recreate_plan
= true;
122 if(smoothing
!= _smooth
) {
131 if(scale
!= _scale
) {
139 if(resolution
!= _resolution
|| offset
!= _offset
) {
140 _resolution
= resolution
;
145 void analyzer::process(float L
, float R
) {
146 fft_buffer
[fpos
] = L
;
147 fft_buffer
[fpos
+ 1] = R
;
149 fpos
%= (max_fft_buffer_size
- 2);
152 bool analyzer::do_fft(int subindex
, int points
) const
155 // recreate fftw plan
156 if (fft_plan
) fftwf_destroy_plan (fft_plan
);
157 //fft_plan = rfftw_create_plan(_accuracy, FFTW_FORWARD, 0);
158 fft_plan
= fftwf_plan_r2r_1d(_accuracy
, NULL
, NULL
, FFTW_R2HC
, FFTW_ESTIMATE
);
160 recreate_plan
= false;
164 // null the overall buffer
165 dsp::zero(fft_inL
, max_fft_cache_size
);
166 dsp::zero(fft_inR
, max_fft_cache_size
);
167 dsp::zero(fft_outL
, max_fft_cache_size
);
168 dsp::zero(fft_outR
, max_fft_cache_size
);
169 dsp::zero(fft_holdL
, max_fft_cache_size
);
170 dsp::zero(fft_holdR
, max_fft_cache_size
);
171 dsp::zero(fft_smoothL
, max_fft_cache_size
);
172 dsp::zero(fft_smoothR
, max_fft_cache_size
);
173 dsp::zero(fft_deltaL
, max_fft_cache_size
);
174 dsp::zero(fft_deltaR
, max_fft_cache_size
);
175 dsp::zero(spline_buffer
, 200);
176 analyzer_phase_drawn
= 0;
180 bool fftdone
= false; // if fft was renewed, this one is set to true
181 int __speed
= 16 - (int)_speed
;
182 if(_mode
== 5 and _smooth
) {
183 // there's no falling for difference mode, only smoothing
186 if(_mode
> 5 and _mode
< 11) {
187 // there's no smoothing for spectralizer mode
192 // #####################################################################
193 // We are doing FFT here, so we first have to setup fft-buffers from
194 // the main buffer and we use this cycle for filling other buffers
195 // like smoothing, delta and hold
196 // #####################################################################
197 if(!((int)analyzer_phase_drawn
% __speed
)) {
198 // seems we have to do a fft, so let's read the latest data from the
199 // buffer to send it to fft afterwards
200 // we want to remember old fft_out values for smoothing as well
201 // and we fill the hold buffer in this (extra) cycle
202 for(int i
= 0; i
< _accuracy
; i
++) {
203 // go to the right position back in time according to accuracy
204 // settings and cycling in the main buffer
205 int _fpos
= (fpos
- _accuracy
* 2 \
206 + (i
* 2)) % max_fft_buffer_size
;
208 _fpos
= max_fft_buffer_size
+ _fpos
;
209 float L
= fft_buffer
[_fpos
];
210 float R
= fft_buffer
[_fpos
+ 1];
211 float win
= 0.54 - 0.46 * cos(2 * M_PI
* i
/ _accuracy
);
215 // #######################################
216 // Do some windowing functions on the
218 // #######################################
221 float _a
, a0
, a1
, a2
, a3
;
230 _f
= 0.54 + 0.46 * cos(2 * M_PI
* (i
- 2 / points
));
234 _f
= 0.5 * (1 + cos(2 * M_PI
* (i
- 2 / points
)));
242 _f
= a0
+ a1
* cos((2.f
* M_PI
* i
) / points
- 1) + \
243 a2
* cos((4.f
* M_PI
* i
) / points
- 1);
251 _f
= a0
- a1
* cos((2.f
* M_PI
* i
) / points
- 1) + \
252 a2
* cos((4.f
* M_PI
* i
) / points
- 1) - \
253 a3
* cos((6.f
* M_PI
* i
) / points
- 1);
261 _f
= a0
- a1
* cos((2.f
* M_PI
* i
) / points
- 1) + \
262 a2
* cos((4.f
* M_PI
* i
) / points
- 1) - \
263 a3
* cos((6.f
* M_PI
* i
) / points
- 1);
267 _f
= sin((M_PI
* i
) / (points
- 1));
271 _f
= sinc((2.f
* i
) / (points
- 1) - 1);
275 _a
= 2.718281828459045;
276 _f
= pow(_a
, -0.5f
* pow((i
- (points
- 1) / 2) / (0.4 * (points
- 1) / 2.f
), 2));
280 _f
= (2.f
/ (points
- 1)) * (((points
- 1) / 2.f
) - \
281 fabs(i
- ((points
- 1) / 2.f
)));
285 _f
= (2.f
/ points
) * ((2.f
/ points
) - fabs(i
- ((points
- 1) / 2.f
)));
292 _f
= a0
- a1
* fabs((i
/ (points
- 1)) - 0.5) - \
293 a2
* cos((2 * M_PI
* i
) / (points
- 1));
300 // perhaps we need to compute two FFT's, so store left and right
301 // channel in case we need only one FFT, the left channel is
302 // used as 'standard'"
308 // left channel (mode 1)
309 // or both channels (mode 3, 4, 5, 7, 9, 10)
321 // right channel (mode 2)
326 // store values in analyzer buffer
330 // fill smoothing & falling buffer
332 fft_smoothL
[i
] = fft_outL
[i
];
333 fft_smoothR
[i
] = fft_outR
[i
];
336 if(fft_smoothL
[i
] < fabs(fft_outL
[i
])) {
337 fft_smoothL
[i
] = fabs(fft_outL
[i
]);
340 if(fft_smoothR
[i
] < fabs(fft_outR
[i
])) {
341 fft_smoothR
[i
] = fabs(fft_outR
[i
]);
346 // fill hold buffer with last out values
347 // before fft is recalced
348 if(fabs(fft_outL
[i
]) > fft_holdL
[i
])
349 fft_holdL
[i
] = fabs(fft_outL
[i
]);
350 if(fabs(fft_outR
[i
]) > fft_holdR
[i
])
351 fft_holdR
[i
] = fabs(fft_outR
[i
]);
355 // this takes our latest buffer and returns an array with
358 fftwf_execute_r2r(fft_plan
, fft_inL
, fft_outL
);
359 //run fft for for right channel too. it is needed for stereo image
360 //and stereo difference modes
361 if(_mode
>= 3 and fft_plan
) {
362 fftwf_execute_r2r(fft_plan
, fft_inR
, fft_outR
);
364 // ...and set some values for later use
365 analyzer_phase_drawn
= 0;
368 analyzer_phase_drawn
++;
373 void analyzer::draw(int subindex
, float *data
, int points
, bool fftdone
) const
375 double freq
; // here the frequency of the actual drawn pixel gets stored
376 int iter
= 0; // this is the pixel we have been drawing the last box/bar/line
377 int _iter
= 1; // this is the next pixel we want to draw a box/bar/line
378 int _last
= -1; // used for mode 10 (parallel spectralizer) to prevent overwriting real values with INFINITY
380 int __speed
= 16 - (int)_speed
;
382 // accuracy was changed so we have to recalc linear transition
383 int _lintrans
= (int)((float)points
* log((20.f
+ 2.f
* \
384 (float)srate
/ (float)_accuracy
) / 20.f
) / log(1000.f
));
385 lintrans
= (int)(_lintrans
+ points
% _lintrans
/ \
386 floor(points
/ _lintrans
)) / 2; // / 4 was added to see finer bars but breaks low end
388 for (int i
= 0; i
<= points
; i
++)
390 // #####################################################################
391 // Real business starts here. We will cycle through all pixels in
392 // x-direction of the line-graph and decide what to show
393 // #####################################################################
394 // cycle through the points to draw
395 // we need to know the exact frequency at this pixel
396 freq
= 20.f
* pow (1000.f
, (float)i
/ points
);
398 // we need to know the last drawn value over the time
399 float lastoutL
= 0.f
;
400 float lastoutR
= 0.f
;
402 // let's see how many pixels we may want to skip until the drawing
403 // function has to draw a bar/box/line
404 if(_scale
or _view
== 2) {
405 // we have linear view enabled or we want to see tit... erm curves
406 if((i
% lintrans
== 0 and points
- i
> lintrans
) or i
== points
- 1) {
407 _iter
= std::max(1, (int)floor(freq
* \
408 (float)_accuracy
/ (float)srate
));
411 // we have logarithmic view enabled
412 _iter
= std::max(1, (int)floor(freq
* (float)_accuracy
/ (float)srate
));
415 // we are flipping one step further in drawing
417 // ################################
418 // Manipulate the fft_out values
419 // according to the post processing
420 // ################################
422 float var1L
= 0.f
; // used later for denoising peaks
429 // only if we don't see difference mode
432 // Analyzer Normalized - nothing to do
435 // Analyzer Additive - cycle through skipped values and
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 fft_outL
[_iter
] /= (_iter
- iter
);
444 fft_outR
[_iter
] /= (_iter
- iter
);
447 // Analyzer Additive - cycle through skipped values and
449 // if fft was renewed, recalc the absolute values if
450 // frequencies are skipped
451 for(int j
= iter
+ 1; j
< _iter
; j
++) {
452 fft_outL
[_iter
] += fabs(fft_outL
[j
]);
453 fft_outR
[_iter
] += fabs(fft_outR
[j
]);
457 // Analyzer Denoised Peaks - filter out unwanted noise
458 for(int k
= 0; k
< std::max(10 , std::min(400 ,\
459 (int)(2.f
*(float)((_iter
- iter
))))); k
++) {
460 //collect amplitudes in the environment of _iter to
461 //be able to erase them from signal and leave just
464 var1L
+= fabs(fft_outL
[_iter
- k
]);
467 if(k
!= 0) var1L
+= fabs(fft_outL
[_iter
+ k
]);
468 else if(i
) var1L
+= fabs(lastoutL
);
469 else var1L
+= fabs(fft_outL
[_iter
]);
470 if(_mode
== 3 or _mode
== 4) {
472 var1R
+= fabs(fft_outR
[_iter
- k
]);
475 if(k
!= 0) var1R
+= fabs(fft_outR
[_iter
+ k
]);
476 else if(i
) var1R
+= fabs(lastoutR
);
477 else var1R
+= fabs(fft_outR
[_iter
]);
481 //do not forget fft_out[_iter] for the next time
482 lastoutL
= fft_outL
[_iter
];
483 //pumping up actual signal an erase surrounding
485 fft_outL
[_iter
] = 0.25f
* std::max(n
* 0.6f
* \
486 fabs(fft_outL
[_iter
]) - var1L
, 1e-20);
487 if(_mode
== 3 or _mode
== 4) {
488 // do the same with R channel if needed
489 lastoutR
= fft_outR
[_iter
];
490 fft_outR
[_iter
] = 0.25f
* std::max(n
* \
491 0.6f
* fabs(fft_outR
[_iter
]) - var1R
, 1e-20);
497 // Stereo Difference - draw the difference between left
498 // and right channel if fft was renewed, recalc the
499 // absolute values in left and right if frequencies are
501 // this is additive mode - no other mode is available
502 //for(int j = iter + 1; j < _iter; j++) {
503 // fft_outL[_iter] += fabs(fft_outL[j]);
504 // fft_outR[_iter] += fabs(fft_outR[j]);
506 //calculate difference between left an right channel
507 diff_fft
= fabs(fft_outL
[_iter
]) - fabs(fft_outR
[_iter
]);
508 posneg
= fabs(diff_fft
) / diff_fft
;
509 //fft_outL[_iter] = diff_fft / _accuracy;
514 // #######################################
515 // Calculate transitions for falling and
516 // smooting and fill delta buffers if fft
518 // #######################################
520 float _fdelta
= 0.91;
521 float _ffactor
= 2000.f
;
523 if(_mode
> 5 and _mode
< 11) {
530 // rebuild delta values after fft was done
531 if(_mode
< 5 or _mode
> 5) {
532 fft_deltaL
[iter
] = pow(fabs(fft_outL
[iter
]) / fabs(fft_smoothL
[iter
]), 1.f
/ __speed
);
534 fft_deltaL
[iter
] = (posneg
* fabs(fft_outL
[iter
]) - fft_smoothL
[iter
]) / __speed
;
537 // change fft_smooth according to delta
538 if(_mode
< 5 or _mode
> 5) {
539 fft_smoothL
[iter
] *= fft_deltaL
[iter
];
541 fft_smoothL
[iter
] += fft_deltaL
[iter
];
544 } else if(_smooth
== 1) {
547 // rebuild delta values after fft was done
548 //fft_deltaL[iter] = _fdelta;
550 // change fft_smooth according to delta
551 fft_smoothL
[iter
] *= fft_deltaL
[iter
];
553 if(fft_deltaL
[iter
] > _fdelta
) {
554 fft_deltaL
[iter
] *= 1.f
- (16.f
- __speed
) / _ffactor
;
558 if((_mode
> 2 and _mode
< 5) or (_mode
> 8 and _mode
< 11)) {
559 // we need right buffers, too for stereo image and
564 // rebuild delta values after fft was done
566 fft_deltaR
[iter
] = pow(fabs(fft_outR
[iter
]) / fabs(fft_smoothR
[iter
]), 1.f
/ __speed
);
568 fft_deltaR
[iter
] = (posneg
* fabs(fft_outR
[iter
]) - fft_smoothR
[iter
]) / __speed
;
571 // change fft_smooth according to delta
573 fft_smoothR
[iter
] *= fft_deltaR
[iter
];
575 fft_smoothR
[iter
] += fft_deltaR
[iter
];
578 } else if(_smooth
== 1) {
581 // rebuild delta values after fft was done
582 //fft_deltaR[iter] = _fdelta;
584 // change fft_smooth according to delta
585 fft_smoothR
[iter
] *= fft_deltaR
[iter
];
586 if(fft_deltaR
[iter
] > _fdelta
)
587 fft_deltaR
[iter
] *= 1.f
- (16.f
- __speed
) / _ffactor
;
591 // #######################################
592 // Choose the L and R value from the right
593 // buffer according to view settings
594 // #######################################
599 valL
= fft_freezeL
[iter
];
600 valR
= fft_freezeR
[iter
];
601 } else if ((subindex
== 1 and _mode
< 3) \
603 or (_mode
> 5 and _hold
)) {
604 // we draw the hold buffer
605 valL
= fft_holdL
[iter
];
606 valR
= fft_holdR
[iter
];
608 // we draw normally (no freeze)
612 valL
= fft_outL
[iter
];
613 valR
= fft_outR
[iter
];
617 valL
= fft_smoothL
[iter
];
618 valR
= fft_smoothR
[iter
];
622 valL
= fft_smoothL
[iter
];
623 valR
= fft_smoothR
[iter
];
626 // fill freeze buffer
627 fft_freezeL
[iter
] = valL
;
628 fft_freezeR
[iter
] = valR
;
631 // #####################################
632 // send values back to painting function
633 // according to mode setting but only if
634 // we are drawing lines or boxes
635 // #####################################
641 // stereo analyzer/spectralizer
642 if(subindex
== 0 or subindex
== 2) {
643 data
[i
] = dB_grid(fabs(valL
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
645 data
[i
] = dB_grid(fabs(valR
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
649 // we want to draw Stereo Image
650 if(subindex
== 0 or subindex
== 2) {
651 // Left channel signal
652 tmp
= dB_grid(fabs(valL
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
653 //only signals above the middle are interesting
654 data
[i
] = tmp
< 0 ? 0 : tmp
;
655 } else if (subindex
== 1 or subindex
== 3) {
656 // Right channel signal
657 tmp
= dB_grid(fabs(valR
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
658 //only signals above the middle are interesting. after cutting away
659 //the unneeded stuff, the curve is flipped vertical at the middle.
661 data
[i
] = -1.f
* tmp
;
665 // We want to draw Stereo Difference
667 tmp
= dB_grid(fabs((fabs(valL
) - fabs(valR
))) / _accuracy
* 2.f
+ 1e-20, _resolution
, 1.f
/ _offset
);
668 //only show differences above a threshhold which results from the db_grid-calculation
670 //bring right signals below the middle
671 tmp
*= fabs(valL
) < fabs(valR
) ? -1.f
: 1.f
;
677 // spectralizer parallel
679 pos2
= points
/ 2 + pos1
;
680 data
[pos1
] = dB_grid(fabs(valL
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
681 data
[pos2
] = dB_grid(fabs(valR
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
685 // normal analyzer behavior
686 data
[i
] = dB_grid(fabs(valL
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
691 else if(_view
== 2) {
692 // we have to draw splines, so we draw every x-pixel according to
693 // the pre-generated fft_splinesL and fft_splinesR buffers
696 // int _splinepos = -1;
699 // for (int i = 0; i<=points; i++) {
700 // if (subindex == 1 and i == spline_buffer[_splinepos]) _splinepos++;
702 // freq = 20.f * pow (1000.f, (float)i / points); //1000=20000/20
703 // float a0,b0,c0,d0,a1,b1,c1,d1,a2,b2,c2,d2;
705 // if(((i % lintrans == 0 and points - i > lintrans) or i == points - 1 ) and subindex == 0) {
707 // _iter = std::max(1, (int)floor(freq * (float)_accuracy / (float)srate));
708 // //printf("_iter %3d\n",_iter);
710 // if(_iter > iter and subindex == 0)
713 // spline_buffer[_splinepos] = _iter;
714 // //printf("_splinepos: %3d - lintrans: %3d\n", _splinepos,lintrans);
715 // if(fftdone and i and subindex == 0)
717 // // if fft was renewed, recalc the absolute values if frequencies
719 // for(int j = iter + 1; j < _iter; j++) {
720 // fft_out[_iter] += fabs(fft_out[j]);
725 // if(fftdone and subindex == 1 and _splinepos >= 0 and (_splinepos % 3 == 0 or _splinepos == 0))
727 // float mleft, mright, y0, y1, y2, y3, y4;
729 // //jetzt spline interpolation
730 // y0 = dB_grid(fft_out[spline_buffer[_splinepos]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
731 // y1 = dB_grid(fft_out[spline_buffer[_splinepos + 1]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
732 // y2 = dB_grid(fft_out[spline_buffer[_splinepos + 2]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
733 // y3 = dB_grid(fft_out[spline_buffer[_splinepos + 3]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
734 // y4 = dB_grid(fft_out[spline_buffer[_splinepos + 4]] / _accuracy * 2.f + 1e-20, pow(64, _level), 0.5f);
737 // printf("y-werte %3d, %3d, %3d, %3d, %3d\n",y0,y1,y2,y3,y4);
738 // a0 = (-3*y3+15*y2-44*y1+32*y0+mright+22*mleft)/34;
739 // b0 = -(-3*y3+15*y2-78*y1+66*y0+mright+56*mleft)/34;
742 // a1 = -(-15*y3+41*y2-50*y1+24*y0+5*mright+8*mleft)/34;
743 // b1 = (-6*y3+30*y2-54*y1+30*y0+2*mright+10*mleft)/17;
744 // c1 = -(3*y3-15*y2-24*y1+36*y0-mright+12*mleft)/34;
746 // a2 = (-25*y3+40*y2-21*y1+6*y0+14*mright+2*mleft)/17;
747 // b2 = -(-33*y3+63*y2-42*y1+12*y0+11*mright+4*mleft)/17;
748 // c2 = (9*y3+6*y2-21*y1+6*y0-3*mright+2*mleft)/17;
754 // if(i > spline_buffer[_splinepos] and i <= spline_buffer[_splinepos + 1] and _splinepos >= 0 and subindex == 1)
756 // data[i] = a0 * pow(i / lintrans - _splinepos, 3) + b0 * pow(i / lintrans - _splinepos, 2) + c0 * (i / lintrans - _splinepos) + d0;
757 // printf("1.spline\n");
759 // if(i > spline_buffer[_splinepos + 1] and i <= spline_buffer[_splinepos + 2] and _splinepos >= 0 and subindex == 1)
761 // printf("2.spline\n");
762 // data[i] = a1 * pow(i / lintrans - _splinepos, 3) + b1 * pow(i / lintrans - _splinepos, 2) + c1 * (i / lintrans - _splinepos) + d1;
764 // if(i > spline_buffer[_splinepos + 2] and i <= spline_buffer[_splinepos + 3] and _splinepos >= 0 and subindex == 1)
766 // printf("3.spline\n");
767 // data[i] = a2 * pow(i / lintrans - _splinepos, 3) + b2 * pow(i / lintrans - _splinepos, 2) + c2 * (i / lintrans - _splinepos) + d2;
769 // if(subindex==1) printf("data[i] %3d _splinepos %2d\n", data[i], _splinepos);
770 // if (subindex == 0)
772 // data[i] = INFINITY;
773 // } else data[i] = dB_grid(i/200, pow(64, _level), 0.5f);
781 else if (_last
!= i
/ 2) {
782 data
[i
/ 2] = INFINITY
;
783 data
[points
/ 2 + i
/ 2] = INFINITY
;
789 bool analyzer::get_graph(int subindex
, int phase
, float *data
, int points
, cairo_iface
*context
, int *mode
) const
794 if ((subindex
== 1 and !_hold
and _mode
< 3) \
795 or (subindex
> 1 and _mode
< 3) \
796 or (subindex
== 2 and !_hold
and (_mode
== 3 or _mode
== 4)) \
797 or (subindex
== 4 and (_mode
== 3 or _mode
== 4)) \
798 or (subindex
== 1 and _mode
== 5) \
801 // stop drawing when all curves have been drawn according to the mode
805 bool fftdone
= false;
807 fftdone
= do_fft(subindex
, points
);
808 draw(subindex
, data
, points
, fftdone
);
810 // #############################
811 // choose a drawing mode between
812 // boxes, lines and bars
813 // #############################
832 // 3: boxes (little things on the values position
833 // 4: centered bars (0dB is centered in y direction)
835 if (_mode
> 3 and _mode
< 6) {
836 // centered viewing modes like stereo image and stereo difference
852 if((subindex
== 0 and _mode
< 3) or (subindex
<= 1 and _mode
== 3)) {
863 // ###################################
864 // colorize the curves/boxes according
865 // to the chosen display settings
866 // ###################################
868 // change alpha (or color) for hold lines or stereo modes
869 if((subindex
== 1 and _mode
< 3) or (subindex
> 1 and _mode
== 4)) {
870 // subtle hold line on left, right, average or stereo image
871 context
->set_source_rgba(0.15, 0.2, 0.0, 0.2);
873 if(subindex
== 0 and _mode
== 3) {
874 // left channel in stereo analyzer
875 context
->set_source_rgba(0.25, 0.10, 0.0, 0.33);
877 if(subindex
== 1 and _mode
== 3) {
878 // right channel in stereo analyzer
879 context
->set_source_rgba(0.05, 0.25, 0.0, 0.33);
881 if(subindex
== 2 and _mode
== 3) {
882 // left hold in stereo analyzer
883 context
->set_source_rgba(0.45, 0.30, 0.2, 0.2);
885 if(subindex
== 3 and _mode
== 3) {
886 // right hold in stereo analyzer
887 context
->set_source_rgba(0.25, 0.45, 0.2, 0.2);
890 context
->set_line_width(0.75);
894 bool analyzer::get_moving(int subindex
, int &direction
, float *data
, int x
, int y
, int &offset
, uint32_t &color
) const
896 if ((subindex
and _mode
!= 9) or subindex
> 1)
898 bool fftdone
= false;
900 fftdone
= do_fft(subindex
, x
);
901 draw(subindex
, data
, x
, fftdone
);
902 direction
= LG_MOVING_UP
;
904 if (_mode
== 9 and subindex
) {
905 color
= RGBAtoINT(0.35, 0.1, 0, 0.4);
906 } else if (_mode
== 9) {
907 color
= RGBAtoINT(0.15, 0.35, 0, 0.4);
912 bool analyzer::get_gridline(int subindex
, int phase
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
) const
916 redraw_graph
= false;
918 int sub
= subindex
+ (_draw_upper
% 2) - 1;
919 static const double dash
[] = {2.0};
926 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true, _resolution
, _offset
);
930 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true);
934 gain
= _draw_upper
> 0 ? 1.f
/ (1 << (subindex
- _draw_upper
))
935 : 1.f
/ (1 << subindex
);
936 pos
= dB_grid(gain
, _resolution
, _offset
);
940 context
->set_dash(dash
, 1);
941 if ((!(subindex
& 1) and !_draw_upper
)
942 or ((sub
& 1) and _draw_upper
> 0)) {
943 // add a label and make the lines straight
944 std::stringstream ss
;
945 ss
<< (subindex
- std::max(0, _draw_upper
)) * -6 << " dB";
947 context
->set_dash(dash
, 0);
950 if (pos
< 0 and !_draw_upper
) {
951 // start drawing the lower end
952 _draw_upper
= subindex
;
955 if (_draw_upper
< 0) {
956 // end the drawing of the grid
960 if (pos
> 0 and _draw_upper
> 0) {
964 context
->set_dash(dash
, 0);
967 context
->set_source_rgba(0, 0, 0, 0.1);
973 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true);
977 gain
= _draw_upper
> 0 ? 1.0 / (1 << (subindex
- _draw_upper
))
979 pos
= dB_grid(gain
, _resolution
, 0);
981 context
->set_dash(dash
, 1);
982 if ((!(subindex
& 1) and !_draw_upper
)
983 or ((subindex
& 1) and _draw_upper
)) {
984 std::stringstream ss
;
985 ss
<< (subindex
- std::max(0, _draw_upper
)) * 6 - 72 << " dB";
987 context
->set_dash(dash
, 0);
990 if (pos
> 1 and !_draw_upper
and (subindex
& 1)) {
991 _draw_upper
= subindex
;
993 if (pos
< -1 and _draw_upper
) {
999 context
->set_source_rgba(0, 0, 0, 0.1);
1006 if (subindex
< 28) {
1008 if (subindex
== 9) legend
= "100 Hz";
1009 if (subindex
== 18) legend
= "1 kHz";
1010 if (subindex
== 27) legend
= "10 kHz";
1012 float freq
= subindex_to_freq(subindex
);
1013 pos
= log(freq
/ 20.0) / log(1000);
1015 if (!legend
.empty()) {
1016 context
->set_source_rgba(0, 0, 0, 0.33);
1018 context
->set_source_rgba(0, 0, 0, 0.2);
1025 //cairo_t *ctx = context->context;
1026 //cairo_set_source_rgb(ctx, 0.35, 0.4, 0.2);
1027 //cairo_select_font_face(ctx, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
1028 //cairo_set_font_size(ctx, 20);
1029 //cairo_move_to (ctx, context->size_x / 2 - 20, 40);
1030 //cairo_show_text (ctx, "L");
1031 //cairo_move_to (ctx, context->size_x / 2 + 12, 40);
1032 //cairo_show_text (ctx, "R");
1034 if (subindex
< 56) {
1036 if (subindex
== 9 or subindex
== 36) legend
= "100 Hz";
1037 if (subindex
== 18 or subindex
== 45) legend
= "1 kHz";
1038 if (subindex
== 27 or subindex
== 54) legend
= "10 kHz";
1040 float freq
= subindex_to_freq(subindex
- (subindex
> 27 ? 27 : 0));
1041 pos
= log(freq
/ 20.0) / log(1000) / 2 + (subindex
> 27 ? 0.5 : 0);
1042 if (!legend
.empty() and subindex
!= 28) {
1043 context
->set_source_rgba(0, 0, 0, 0.33);
1044 } else if (subindex
!= 28) {
1045 context
->set_source_rgba(0, 0, 0, 0.2);
1054 bool analyzer::get_layers(int generation
, unsigned int &layers
) const
1056 if (_mode
> 5 and _mode
< 11)
1057 layers
= LG_REALTIME_MOVING
;
1059 layers
= LG_REALTIME_GRAPH
;
1060 layers
|= ((!generation
or redraw_graph
) ? LG_CACHE_GRID
: 0);