fix drawing of zero-length notes
[ardour.git] / gtk2_ardour / fft_result.cc
1 /*
2  * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (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 along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include "fft_result.h"
20 #include "fft_graph.h"
21 #include <cstdlib>
22 #include <cstring>
23 #include <string>
24 #include <cmath>
25 #include <algorithm>
26
27 using namespace std;
28
29 FFTResult::FFTResult(FFTGraph *graph, Gdk::Color color, string trackname)
30 {
31         _graph = graph;
32
33         _windowSize = _graph->windowSize();
34         _dataSize   = _windowSize / 2;
35         _averages = 0;
36         _min_flat = _max_flat = 0.0;
37         _min_prop = _max_prop = 0.0;
38
39         _data_flat_avg = (float *) malloc (sizeof(float) * _dataSize);
40         _data_flat_min = (float *) malloc (sizeof(float) * _dataSize);
41         _data_flat_max = (float *) malloc (sizeof(float) * _dataSize);
42         _data_prop_avg = (float *) malloc (sizeof(float) * _dataSize);
43         _data_prop_min = (float *) malloc (sizeof(float) * _dataSize);
44         _data_prop_max = (float *) malloc (sizeof(float) * _dataSize);
45
46         for (unsigned int i = 0; i < _dataSize; i++) {
47                 _data_flat_min[i] = FLT_MAX;
48                 _data_flat_max[i] = FLT_MIN;
49                 _data_flat_avg[i] = 0;
50                 _data_prop_min[i] = FLT_MAX;
51                 _data_prop_max[i] = FLT_MIN;
52                 _data_prop_avg[i] = 0;
53         }
54
55         _color     = color;
56         _trackname = trackname;
57 }
58
59 void
60 FFTResult::analyzeWindow(float *window)
61 {
62         float const * const _hanning = _graph->_hanning;
63         float *_in = _graph->_in;
64         float *_out = _graph->_out;
65
66         // Copy the data and apply the hanning window
67         for (unsigned int i = 0; i < _windowSize; ++i) {
68                 _in[i] = window[i] * _hanning[i];
69         }
70
71         fftwf_execute(_graph->_plan);
72
73         // calculate signal power per bin
74         float b = _out[0] * _out[0];
75
76         _data_flat_avg[0] += b;
77         if (b < _data_flat_min[0]) _data_flat_min[0] = b;
78         if (b > _data_flat_max[0]) _data_flat_max[0] = b;
79
80         for (unsigned int i = 1; i < _dataSize - 1; ++i) {
81                 b = (_out[i] * _out[i]) + (_out[_windowSize - i] * _out[_windowSize - i]);
82                 _data_flat_avg[i] += b;
83                 if (_data_flat_min[i] > b)  _data_flat_min[i] = b;
84                 if (_data_flat_max[i] < b ) _data_flat_max[i] = b;
85         }
86
87         _averages++;
88 }
89
90 void
91 FFTResult::finalize()
92 {
93         if (_averages == 0) {
94                 _min_flat = _max_flat = 0.0;
95                 _min_prop = _max_prop = 0.0;
96                 return;
97         }
98
99         // Average & scale
100         for (unsigned int i = 0; i < _dataSize - 1; ++i) {
101                 _data_flat_avg[i] /= _averages;
102                 // proportional, pink spectrum @ -18dB
103                 _data_prop_avg[i] = _data_flat_avg [i] * i / 63.096f;
104                 _data_prop_min[i] = _data_flat_min [i] * i / 63.096f;
105                 _data_prop_max[i] = _data_flat_max [i] * i / 63.096f;
106         }
107
108         _data_prop_avg[0] = _data_flat_avg [0] / 63.096f;
109         _data_prop_min[0] = _data_flat_min [0] / 63.096f;
110         _data_prop_max[0] = _data_flat_max [0] / 63.096f;
111
112         // calculate power
113         for (unsigned int i = 0; i < _dataSize - 1; ++i) {
114                 _data_flat_min[i] = power_to_db (_data_flat_min[i]);
115                 _data_flat_max[i] = power_to_db (_data_flat_max[i]);
116                 _data_flat_avg[i] = power_to_db (_data_flat_avg[i]);
117                 _data_prop_min[i] = power_to_db (_data_prop_min[i]);
118                 _data_prop_max[i] = power_to_db (_data_prop_max[i]);
119                 _data_prop_avg[i] = power_to_db (_data_prop_avg[i]);
120         }
121
122         // find min & max
123         _min_flat = _max_flat = _data_flat_avg[0];
124         _min_prop = _max_prop = _data_prop_avg[0];
125
126         for (unsigned int i = 1; i < _dataSize - 1; ++i) {
127                 _min_flat = std::min (_min_flat, _data_flat_avg[i]);
128                 _max_flat = std::max (_max_flat, _data_flat_avg[i]);
129                 _min_prop = std::min (_min_prop, _data_prop_avg[i]);
130                 _max_prop = std::max (_max_prop, _data_prop_avg[i]);
131         }
132
133         _averages = 0;
134 }
135
136 FFTResult::~FFTResult()
137 {
138         free(_data_flat_avg);
139         free(_data_flat_min);
140         free(_data_flat_max);
141         free(_data_prop_avg);
142         free(_data_prop_min);
143         free(_data_prop_max);
144 }