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>
25 #include <calf/giface.h>
26 #include <calf/analyzer.h>
27 #include <calf/modules_dev.h>
29 #include <calf/utils.h>
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() {
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;
95 void analyzer::set_sample_rate(uint32_t 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
)
102 _windowing
= windowing
;
106 if(accuracy
!= _acc
) {
107 _accuracy
= 1 << (7 + (int)accuracy
);
109 recreate_plan
= true;
115 if(smoothing
!= _smooth
) {
124 if(scale
!= _scale
) {
132 if(resolution
!= _resolution
|| offset
!= _offset
) {
133 _resolution
= resolution
;
138 void analyzer::process(float L
, float R
) {
139 fft_buffer
[fpos
] = L
;
140 fft_buffer
[fpos
+ 1] = R
;
142 fpos
%= (max_fft_buffer_size
- 2);
145 bool analyzer::do_fft(int subindex
, int points
) const
149 recreate_plan
= false;
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;
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
175 if(_mode
> 5 and _mode
< 11) {
176 // there's no smoothing for spectralizer mode
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
;
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
);
204 // #######################################
205 // Do some windowing functions on the
207 // #######################################
210 float _a
, a0
, a1
, a2
, a3
;
219 _f
= 0.54 + 0.46 * cos(2 * M_PI
* (i
- 2 / points
));
223 _f
= 0.5 * (1 + cos(2 * M_PI
* (i
- 2 / points
)));
231 _f
= a0
+ a1
* cos((2.f
* M_PI
* i
) / points
- 1) + \
232 a2
* cos((4.f
* M_PI
* i
) / points
- 1);
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);
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);
256 _f
= sin((M_PI
* i
) / (points
- 1));
260 _f
= sinc((2.f
* i
) / (points
- 1) - 1);
264 _a
= 2.718281828459045;
265 _f
= pow(_a
, -0.5f
* pow((i
- (points
- 1) / 2) / (0.4 * (points
- 1) / 2.f
), 2));
269 _f
= (2.f
/ (points
- 1)) * (((points
- 1) / 2.f
) - \
270 fabs(i
- ((points
- 1) / 2.f
)));
274 _f
= (2.f
/ points
) * ((2.f
/ points
) - fabs(i
- ((points
- 1) / 2.f
)));
281 _f
= a0
- a1
* fabs((i
/ (points
- 1)) - 0.5) - \
282 a2
* cos((2 * M_PI
* i
) / (points
- 1));
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'"
297 // left channel (mode 1)
298 // or both channels (mode 3, 4, 5, 7, 9, 10)
310 // right channel (mode 2)
315 // store values in analyzer buffer
319 // fill smoothing & falling buffer
321 fft_smoothL
[i
] = fft_outL
[i
];
322 fft_smoothR
[i
] = fft_outR
[i
];
325 if(fft_smoothL
[i
] < fabs(fft_outL
[i
])) {
326 fft_smoothL
[i
] = fabs(fft_outL
[i
]);
329 if(fft_smoothR
[i
] < fabs(fft_outR
[i
])) {
330 fft_smoothR
[i
] = fabs(fft_outR
[i
]);
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
]);
344 // this takes our latest buffer and returns an array with
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
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;
356 analyzer_phase_drawn
++;
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
368 int __speed
= 16 - (int)_speed
;
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
));
399 // we have logarithmic view enabled
400 _iter
= std::max(1, (int)floor(freq
* (float)_accuracy
/ (float)srate
));
403 // we are flipping one step further in drawing
405 // ################################
406 // Manipulate the fft_out values
407 // according to the post processing
408 // ################################
410 float var1L
= 0.f
; // used later for denoising peaks
417 // only if we don't see difference mode
420 // Analyzer Normalized - nothing to do
423 // Analyzer Additive - cycle through skipped values and
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
);
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
]);
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
452 var1L
+= fabs(fft_outL
[_iter
- k
]);
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) {
460 var1R
+= fabs(fft_outR
[_iter
- k
]);
463 if(k
!= 0) var1R
+= fabs(fft_outR
[_iter
+ k
]);
464 else if(i
) var1R
+= fabs(lastoutR
);
465 else var1R
+= fabs(fft_outR
[_iter
]);
469 //do not forget fft_out[_iter] for the next time
470 lastoutL
= fft_outL
[_iter
];
471 //pumping up actual signal an erase surrounding
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);
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
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;
502 // #######################################
503 // Calculate transitions for falling and
504 // smooting and fill delta buffers if fft
506 // #######################################
508 float _fdelta
= 0.91;
509 float _ffactor
= 2000.f
;
511 if(_mode
> 5 and _mode
< 11) {
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
);
522 fft_deltaL
[iter
] = (posneg
* fabs(fft_outL
[iter
]) - fft_smoothL
[iter
]) / __speed
;
525 // change fft_smooth according to delta
526 if(_mode
< 5 or _mode
> 5) {
527 fft_smoothL
[iter
] *= fft_deltaL
[iter
];
529 fft_smoothL
[iter
] += fft_deltaL
[iter
];
532 } else if(_smooth
== 1) {
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
552 // rebuild delta values after fft was done
554 fft_deltaR
[iter
] = pow(fabs(fft_outR
[iter
]) / fabs(fft_smoothR
[iter
]), 1.f
/ __speed
);
556 fft_deltaR
[iter
] = (posneg
* fabs(fft_outR
[iter
]) - fft_smoothR
[iter
]) / __speed
;
559 // change fft_smooth according to delta
561 fft_smoothR
[iter
] *= fft_deltaR
[iter
];
563 fft_smoothR
[iter
] += fft_deltaR
[iter
];
566 } else if(_smooth
== 1) {
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 // #######################################
587 valL
= fft_freezeL
[iter
];
588 valR
= fft_freezeR
[iter
];
589 } else if ((subindex
== 1 and _mode
< 3) \
591 or (_mode
> 5 and _hold
)) {
592 // we draw the hold buffer
593 valL
= fft_holdL
[iter
];
594 valR
= fft_holdR
[iter
];
596 // we draw normally (no freeze)
600 valL
= fft_outL
[iter
];
601 valR
= fft_outR
[iter
];
605 valL
= fft_smoothL
[iter
];
606 valR
= fft_smoothR
[iter
];
610 valL
= fft_smoothL
[iter
];
611 valR
= fft_smoothR
[iter
];
614 // fill freeze buffer
615 fft_freezeL
[iter
] = valL
;
616 fft_freezeR
[iter
] = valR
;
619 // #####################################
620 // send values back to painting function
621 // according to mode setting but only if
622 // we are drawing lines or boxes
623 // #####################################
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
);
633 data
[i
] = dB_grid(fabs(valR
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
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.
649 data
[i
] = -1.f
* tmp
;
653 // We want to draw Stereo Difference
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
658 //bring right signals below the middle
659 tmp
*= fabs(valL
) < fabs(valR
) ? -1.f
: 1.f
;
665 // spectralizer parallel
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
);
673 // normal analyzer behavior
674 data
[i
] = dB_grid(fabs(valL
) / _accuracy
* 2.f
+ 1e-20, _resolution
, _offset
);
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
684 // int _splinepos = -1;
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);
698 // if(_iter > iter and subindex == 0)
701 // spline_buffer[_splinepos] = _iter;
702 // //printf("_splinepos: %3d - lintrans: %3d\n", _splinepos,lintrans);
703 // if(fftdone and i and subindex == 0)
705 // // if fft was renewed, recalc the absolute values if frequencies
707 // for(int j = iter + 1; j < _iter; j++) {
708 // fft_out[_iter] += fabs(fft_out[j]);
713 // if(fftdone and subindex == 1 and _splinepos >= 0 and (_splinepos % 3 == 0 or _splinepos == 0))
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);
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;
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;
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;
742 // if(i > spline_buffer[_splinepos] and i <= spline_buffer[_splinepos + 1] and _splinepos >= 0 and subindex == 1)
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");
747 // if(i > spline_buffer[_splinepos + 1] and i <= spline_buffer[_splinepos + 2] and _splinepos >= 0 and subindex == 1)
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;
752 // if(i > spline_buffer[_splinepos + 2] and i <= spline_buffer[_splinepos + 3] and _splinepos >= 0 and subindex == 1)
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;
757 // if(subindex==1) printf("data[i] %3d _splinepos %2d\n", data[i], _splinepos);
758 // if (subindex == 0)
760 // data[i] = INFINITY;
761 // } else data[i] = dB_grid(i/200, pow(64, _level), 0.5f);
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
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) \
789 // stop drawing when all curves have been drawn according to the mode
793 bool fftdone
= false;
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 // #############################
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
840 if((subindex
== 0 and _mode
< 3) or (subindex
<= 1 and _mode
== 3)) {
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);
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)
886 bool fftdone
= false;
888 fftdone
= do_fft(subindex
, x
);
889 draw(subindex
, data
, x
, fftdone
);
890 direction
= LG_MOVING_UP
;
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);
900 bool analyzer::get_gridline(int subindex
, int phase
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
) const
904 redraw_graph
= false;
906 int sub
= subindex
+ (_draw_upper
% 2) - 1;
907 static const double dash
[] = {2.0};
914 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true, _resolution
, _offset
);
918 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true);
922 gain
= _draw_upper
> 0 ? 1.f
/ (1 << (subindex
- _draw_upper
))
923 : 1.f
/ (1 << subindex
);
924 pos
= dB_grid(gain
, _resolution
, _offset
);
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";
935 context
->set_dash(dash
, 0);
938 if (pos
< 0 and !_draw_upper
) {
939 // start drawing the lower end
940 _draw_upper
= subindex
;
943 if (_draw_upper
< 0) {
944 // end the drawing of the grid
948 if (pos
> 0 and _draw_upper
> 0) {
952 context
->set_dash(dash
, 0);
955 context
->set_source_rgba(0, 0, 0, 0.1);
961 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true);
965 gain
= _draw_upper
> 0 ? 1.0 / (1 << (subindex
- _draw_upper
))
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";
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
) {
987 context
->set_source_rgba(0, 0, 0, 0.1);
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);
1006 context
->set_source_rgba(0, 0, 0, 0.2);
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) {
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);
1042 bool analyzer::get_layers(int generation
, unsigned int &layers
) const
1044 if (_mode
> 5 and _mode
< 11)
1045 layers
= LG_REALTIME_MOVING
;
1047 layers
= LG_REALTIME_GRAPH
;
1048 layers
|= ((!generation
or redraw_graph
) ? LG_CACHE_GRID
: 0);