lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7 This file copyright 2006 Chris Cannam.
|
lbajardsilogic@0
|
8
|
lbajardsilogic@0
|
9 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
10 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
11 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
12 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
13 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
14 */
|
lbajardsilogic@0
|
15
|
lbajardsilogic@0
|
16 #include "WindowShapePreview.h"
|
lbajardsilogic@0
|
17
|
lbajardsilogic@0
|
18 #include <QHBoxLayout>
|
lbajardsilogic@0
|
19 #include <QLabel>
|
lbajardsilogic@0
|
20 #include <QPainter>
|
lbajardsilogic@0
|
21 #include <QPainterPath>
|
lbajardsilogic@0
|
22 #include <QFont>
|
lbajardsilogic@0
|
23 #include <QString>
|
lbajardsilogic@0
|
24
|
lbajardsilogic@0
|
25 #include "data/fft/FFTapi.h"
|
lbajardsilogic@0
|
26
|
lbajardsilogic@0
|
27 #include <iostream>
|
lbajardsilogic@0
|
28
|
lbajardsilogic@0
|
29 WindowShapePreview::WindowShapePreview(QWidget *parent) :
|
lbajardsilogic@0
|
30 QFrame(parent),
|
lbajardsilogic@0
|
31 m_windowType(WindowType(999))
|
lbajardsilogic@0
|
32 {
|
lbajardsilogic@0
|
33 QHBoxLayout *layout = new QHBoxLayout;
|
lbajardsilogic@0
|
34 layout->setMargin(0);
|
lbajardsilogic@0
|
35 setLayout(layout);
|
lbajardsilogic@0
|
36 m_windowTimeExampleLabel = new QLabel;
|
lbajardsilogic@0
|
37 m_windowFreqExampleLabel = new QLabel;
|
lbajardsilogic@0
|
38 layout->addWidget(m_windowTimeExampleLabel);
|
lbajardsilogic@0
|
39 layout->addWidget(m_windowFreqExampleLabel);
|
lbajardsilogic@0
|
40 }
|
lbajardsilogic@0
|
41
|
lbajardsilogic@0
|
42 WindowShapePreview::~WindowShapePreview()
|
lbajardsilogic@0
|
43 {
|
lbajardsilogic@0
|
44 }
|
lbajardsilogic@0
|
45
|
lbajardsilogic@0
|
46 void
|
lbajardsilogic@0
|
47 WindowShapePreview::updateLabels()
|
lbajardsilogic@0
|
48 {
|
lbajardsilogic@0
|
49 int step = 24;
|
lbajardsilogic@0
|
50 int peak = 48;
|
lbajardsilogic@0
|
51 int w = step * 4, h = 64;
|
lbajardsilogic@0
|
52 WindowType type = m_windowType;
|
lbajardsilogic@0
|
53 Window<float> windower = Window<float>(type, step * 2);
|
lbajardsilogic@0
|
54
|
lbajardsilogic@0
|
55 QPixmap timeLabel(w, h + 1);
|
lbajardsilogic@0
|
56 timeLabel.fill(Qt::white);
|
lbajardsilogic@0
|
57 QPainter timePainter(&timeLabel);
|
lbajardsilogic@0
|
58
|
lbajardsilogic@0
|
59 QPainterPath path;
|
lbajardsilogic@0
|
60
|
lbajardsilogic@0
|
61 path.moveTo(0, h - peak + 1);
|
lbajardsilogic@0
|
62 path.lineTo(w, h - peak + 1);
|
lbajardsilogic@0
|
63
|
lbajardsilogic@0
|
64 timePainter.setPen(Qt::gray);
|
lbajardsilogic@0
|
65 timePainter.setRenderHint(QPainter::Antialiasing, true);
|
lbajardsilogic@0
|
66 timePainter.drawPath(path);
|
lbajardsilogic@0
|
67
|
lbajardsilogic@0
|
68 path = QPainterPath();
|
lbajardsilogic@0
|
69
|
lbajardsilogic@0
|
70 //float acc[w];
|
lbajardsilogic@0
|
71 float *acc = (float*) malloc(w*sizeof(float));
|
lbajardsilogic@0
|
72 for (int i = 0; i < w; ++i) acc[i] = 0.f;
|
lbajardsilogic@0
|
73 for (int j = 0; j < 3; ++j) {
|
lbajardsilogic@0
|
74 for (int i = 0; i < step * 2; ++i) {
|
lbajardsilogic@0
|
75 acc[j * step + i] += windower.getValue(i);
|
lbajardsilogic@0
|
76 }
|
lbajardsilogic@0
|
77 }
|
lbajardsilogic@0
|
78 for (int i = 0; i < w; ++i) {
|
lbajardsilogic@0
|
79 int y = h - int(peak * acc[i] + 0.001) + 1;
|
lbajardsilogic@0
|
80 if (i == 0) path.moveTo(i, y);
|
lbajardsilogic@0
|
81 else path.lineTo(i, y);
|
lbajardsilogic@0
|
82 }
|
lbajardsilogic@0
|
83
|
lbajardsilogic@0
|
84 timePainter.drawPath(path);
|
lbajardsilogic@0
|
85 timePainter.setRenderHint(QPainter::Antialiasing, false);
|
lbajardsilogic@0
|
86
|
lbajardsilogic@0
|
87 path = QPainterPath();
|
lbajardsilogic@0
|
88
|
lbajardsilogic@0
|
89 timePainter.setPen(Qt::black);
|
lbajardsilogic@0
|
90
|
lbajardsilogic@0
|
91 for (int i = 0; i < step * 2; ++i) {
|
lbajardsilogic@0
|
92 int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
|
lbajardsilogic@0
|
93 if (i == 0) path.moveTo(i + step, float(y));
|
lbajardsilogic@0
|
94 else path.lineTo(i + step, float(y));
|
lbajardsilogic@0
|
95 }
|
lbajardsilogic@0
|
96
|
lbajardsilogic@0
|
97 if (type == RectangularWindow) {
|
lbajardsilogic@0
|
98 timePainter.drawPath(path);
|
lbajardsilogic@0
|
99 path = QPainterPath();
|
lbajardsilogic@0
|
100 }
|
lbajardsilogic@0
|
101
|
lbajardsilogic@0
|
102 timePainter.setRenderHint(QPainter::Antialiasing, true);
|
lbajardsilogic@0
|
103 path.addRect(0, 0, w, h + 1);
|
lbajardsilogic@0
|
104 timePainter.drawPath(path);
|
lbajardsilogic@0
|
105
|
lbajardsilogic@0
|
106 QFont font;
|
lbajardsilogic@0
|
107 font.setPixelSize(10);
|
lbajardsilogic@0
|
108 font.setItalic(true);
|
lbajardsilogic@0
|
109 timePainter.setFont(font);
|
lbajardsilogic@0
|
110 QString label = tr("V / time");
|
lbajardsilogic@0
|
111 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
|
lbajardsilogic@0
|
112 timePainter.fontMetrics().ascent() + 1, label);
|
lbajardsilogic@0
|
113
|
lbajardsilogic@0
|
114 m_windowTimeExampleLabel->setPixmap(timeLabel);
|
lbajardsilogic@0
|
115
|
lbajardsilogic@0
|
116 int fw = 100;
|
lbajardsilogic@0
|
117
|
lbajardsilogic@0
|
118 QPixmap freqLabel(fw, h + 1);
|
lbajardsilogic@0
|
119 freqLabel.fill(Qt::white);
|
lbajardsilogic@0
|
120 QPainter freqPainter(&freqLabel);
|
lbajardsilogic@0
|
121 path = QPainterPath();
|
lbajardsilogic@0
|
122
|
lbajardsilogic@0
|
123 int fftsize = 512;
|
lbajardsilogic@0
|
124
|
lbajardsilogic@0
|
125 float *input = (float *)fftf_malloc(fftsize * sizeof(float));
|
lbajardsilogic@0
|
126 fftf_complex *output =
|
lbajardsilogic@0
|
127 (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex));
|
lbajardsilogic@0
|
128 fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output,
|
lbajardsilogic@0
|
129 FFTW_ESTIMATE);
|
lbajardsilogic@0
|
130 for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
|
lbajardsilogic@0
|
131 for (int i = 0; i < step * 2; ++i) {
|
lbajardsilogic@0
|
132 input[fftsize/2 - step + i] = windower.getValue(i);
|
lbajardsilogic@0
|
133 }
|
lbajardsilogic@0
|
134
|
lbajardsilogic@0
|
135 fftf_execute(plan);
|
lbajardsilogic@0
|
136 fftf_destroy_plan(plan);
|
lbajardsilogic@0
|
137
|
lbajardsilogic@0
|
138 float maxdb = 0.f;
|
lbajardsilogic@0
|
139 float mindb = 0.f;
|
lbajardsilogic@0
|
140 bool first = true;
|
lbajardsilogic@0
|
141 for (int i = 0; i < fftsize/2; ++i) {
|
lbajardsilogic@0
|
142 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
|
lbajardsilogic@0
|
143 float db = mindb;
|
lbajardsilogic@0
|
144 if (power > 0) {
|
lbajardsilogic@0
|
145 db = 20 * log10(power);
|
lbajardsilogic@0
|
146 if (first || db > maxdb) maxdb = db;
|
lbajardsilogic@0
|
147 if (first || db < mindb) mindb = db;
|
lbajardsilogic@0
|
148 first = false;
|
lbajardsilogic@0
|
149 }
|
lbajardsilogic@0
|
150 }
|
lbajardsilogic@0
|
151
|
lbajardsilogic@0
|
152 if (mindb > -80.f) mindb = -80.f;
|
lbajardsilogic@0
|
153
|
lbajardsilogic@0
|
154 // -- no, don't use the actual mindb -- it's easier to compare
|
lbajardsilogic@0
|
155 // plots with a fixed min value
|
lbajardsilogic@0
|
156 mindb = -170.f;
|
lbajardsilogic@0
|
157
|
lbajardsilogic@0
|
158 float maxval = maxdb + -mindb;
|
lbajardsilogic@0
|
159
|
lbajardsilogic@0
|
160 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
|
lbajardsilogic@0
|
161
|
lbajardsilogic@0
|
162 path.moveTo(0, h - peak + 1);
|
lbajardsilogic@0
|
163 path.lineTo(fw, h - peak + 1);
|
lbajardsilogic@0
|
164
|
lbajardsilogic@0
|
165 freqPainter.setPen(Qt::gray);
|
lbajardsilogic@0
|
166 freqPainter.setRenderHint(QPainter::Antialiasing, true);
|
lbajardsilogic@0
|
167 freqPainter.drawPath(path);
|
lbajardsilogic@0
|
168
|
lbajardsilogic@0
|
169 path = QPainterPath();
|
lbajardsilogic@0
|
170 freqPainter.setPen(Qt::black);
|
lbajardsilogic@0
|
171
|
lbajardsilogic@0
|
172 // std::cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << std::endl;
|
lbajardsilogic@0
|
173
|
lbajardsilogic@0
|
174 for (int i = 0; i < fftsize/2; ++i) {
|
lbajardsilogic@0
|
175 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
|
lbajardsilogic@0
|
176 float db = 20 * log10(power);
|
lbajardsilogic@0
|
177 float val = db + -mindb;
|
lbajardsilogic@0
|
178 if (val < 0) val = 0;
|
lbajardsilogic@0
|
179 float norm = val / maxval;
|
lbajardsilogic@0
|
180 float x = (fw / float(fftsize/2)) * i;
|
lbajardsilogic@0
|
181 float y = h - norm * peak + 1;
|
lbajardsilogic@0
|
182 if (i == 0) path.moveTo(x, y);
|
lbajardsilogic@0
|
183 else path.lineTo(x, y);
|
lbajardsilogic@0
|
184 }
|
lbajardsilogic@0
|
185
|
lbajardsilogic@0
|
186 freqPainter.setRenderHint(QPainter::Antialiasing, true);
|
lbajardsilogic@0
|
187 path.addRect(0, 0, fw, h + 1);
|
lbajardsilogic@0
|
188 freqPainter.drawPath(path);
|
lbajardsilogic@0
|
189
|
lbajardsilogic@0
|
190 fftf_free(input);
|
lbajardsilogic@0
|
191 fftf_free(output);
|
lbajardsilogic@0
|
192
|
lbajardsilogic@0
|
193 freqPainter.setFont(font);
|
lbajardsilogic@0
|
194 label = tr("dB / freq");
|
lbajardsilogic@0
|
195 freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4,
|
lbajardsilogic@0
|
196 freqPainter.fontMetrics().ascent() + 1, label);
|
lbajardsilogic@0
|
197
|
lbajardsilogic@0
|
198 m_windowFreqExampleLabel->setPixmap(freqLabel);
|
lbajardsilogic@0
|
199 }
|
lbajardsilogic@0
|
200
|
lbajardsilogic@0
|
201 void
|
lbajardsilogic@0
|
202 WindowShapePreview::setWindowType(WindowType type)
|
lbajardsilogic@0
|
203 {
|
lbajardsilogic@0
|
204 if (m_windowType == type) return;
|
lbajardsilogic@0
|
205 m_windowType = type;
|
lbajardsilogic@0
|
206 updateLabels();
|
lbajardsilogic@0
|
207 }
|
lbajardsilogic@0
|
208
|