comparison main/PreferencesDialog.cpp @ 9:8b34a6460545

* Pull window type selector and shape preview out into their own widgets (from the preferences dialog)
author Chris Cannam
date Mon, 11 Sep 2006 15:32:49 +0000
parents d4487202d0e8
children e3b32dc5180b
comparison
equal deleted inserted replaced
8:92cb01225e7a 9:8b34a6460545
21 #include <QGroupBox> 21 #include <QGroupBox>
22 #include <QDoubleSpinBox> 22 #include <QDoubleSpinBox>
23 #include <QLabel> 23 #include <QLabel>
24 #include <QPushButton> 24 #include <QPushButton>
25 #include <QHBoxLayout> 25 #include <QHBoxLayout>
26 #include <QPainter>
27 #include <QPainterPath>
28 #include <QFont>
29 #include <QString> 26 #include <QString>
30 27
31 #include <fftw3.h> 28 #include <fftw3.h>
32 29
30 #include "widgets/WindowTypeSelector.h"
33 #include "base/Preferences.h" 31 #include "base/Preferences.h"
34 32
35 PreferencesDialog::PreferencesDialog(QWidget *parent, Qt::WFlags flags) : 33 PreferencesDialog::PreferencesDialog(QWidget *parent, Qt::WFlags flags) :
36 QDialog(parent, flags) 34 QDialog(parent, flags)
37 { 35 {
51 49
52 // Create this first, as slots that get called from the ctor will 50 // Create this first, as slots that get called from the ctor will
53 // refer to it 51 // refer to it
54 m_applyButton = new QPushButton(tr("Apply")); 52 m_applyButton = new QPushButton(tr("Apply"));
55 53
56 // The WindowType enum is in rather a ragbag order -- reorder it here 54 int min, max, i;
57 // in a more sensible order
58 m_windows = new WindowType[9];
59 m_windows[0] = HanningWindow;
60 m_windows[1] = HammingWindow;
61 m_windows[2] = BlackmanWindow;
62 m_windows[3] = BlackmanHarrisWindow;
63 m_windows[4] = NuttallWindow;
64 m_windows[5] = GaussianWindow;
65 m_windows[6] = ParzenWindow;
66 m_windows[7] = BartlettWindow;
67 m_windows[8] = RectangularWindow;
68 55
69 QComboBox *windowCombo = new QComboBox; 56 m_windowType = WindowType(prefs->getPropertyRangeAndValue
70 int min, max, i; 57 ("Window Type", &min, &max));
71 int window = prefs->getPropertyRangeAndValue("Window Type", &min, &max); 58 m_windowTypeSelector = new WindowTypeSelector(m_windowType);
72 m_windowType = window;
73 int index = 0;
74
75 for (i = 0; i <= 8; ++i) {
76 windowCombo->addItem(prefs->getPropertyValueLabel("Window Type",
77 m_windows[i]));
78 if (m_windows[i] == window) index = i;
79 }
80 59
81 windowCombo->setCurrentIndex(index); 60 connect(m_windowTypeSelector, SIGNAL(windowTypeChanged(WindowType)),
82 61 this, SLOT(windowTypeChanged(WindowType)));
83 m_windowTimeExampleLabel = new QLabel;
84 m_windowFreqExampleLabel = new QLabel;
85
86 connect(windowCombo, SIGNAL(currentIndexChanged(int)),
87 this, SLOT(windowTypeChanged(int)));
88 windowTypeChanged(index);
89 62
90 QCheckBox *smoothing = new QCheckBox; 63 QCheckBox *smoothing = new QCheckBox;
91 m_smoothSpectrogram = prefs->getSmoothSpectrogram(); 64 m_smoothSpectrogram = prefs->getSmoothSpectrogram();
92 smoothing->setCheckState(m_smoothSpectrogram ? 65 smoothing->setCheckState(m_smoothSpectrogram ?
93 Qt::Checked : Qt::Unchecked); 66 Qt::Checked : Qt::Unchecked);
139 subgrid->addWidget(smoothing, row++, 2); 112 subgrid->addWidget(smoothing, row++, 2);
140 113
141 subgrid->addWidget(new QLabel(tr("%1:").arg(prefs->getPropertyLabel 114 subgrid->addWidget(new QLabel(tr("%1:").arg(prefs->getPropertyLabel
142 ("Window Type"))), 115 ("Window Type"))),
143 row, 0); 116 row, 0);
144 subgrid->addWidget(windowCombo, row++, 1, 1, 2); 117 subgrid->addWidget(m_windowTypeSelector, row++, 1, 2, 2);
145 118 subgrid->setRowStretch(row, 10);
146 subgrid->addWidget(m_windowTimeExampleLabel, row, 1); 119 row++;
147 subgrid->addWidget(m_windowFreqExampleLabel, row, 2);
148 120
149 QHBoxLayout *hbox = new QHBoxLayout; 121 QHBoxLayout *hbox = new QHBoxLayout;
150 grid->addLayout(hbox, 1, 0); 122 grid->addLayout(hbox, 1, 0);
151 123
152 QPushButton *ok = new QPushButton(tr("OK")); 124 QPushButton *ok = new QPushButton(tr("OK"));
163 } 135 }
164 136
165 PreferencesDialog::~PreferencesDialog() 137 PreferencesDialog::~PreferencesDialog()
166 { 138 {
167 std::cerr << "PreferencesDialog::~PreferencesDialog()" << std::endl; 139 std::cerr << "PreferencesDialog::~PreferencesDialog()" << std::endl;
168
169 delete[] m_windows;
170 } 140 }
171 141
172 void 142 void
173 PreferencesDialog::windowTypeChanged(int value) 143 PreferencesDialog::windowTypeChanged(WindowType type)
174 { 144 {
175 int step = 24;
176 int peak = 48;
177 int w = step * 4, h = 64;
178 WindowType type = m_windows[value];
179 Window<float> windower = Window<float>(type, step * 2);
180
181 QPixmap timeLabel(w, h + 1);
182 timeLabel.fill(Qt::white);
183 QPainter timePainter(&timeLabel);
184
185 QPainterPath path;
186
187 path.moveTo(0, h - peak + 1);
188 path.lineTo(w, h - peak + 1);
189
190 timePainter.setPen(Qt::gray);
191 timePainter.setRenderHint(QPainter::Antialiasing, true);
192 timePainter.drawPath(path);
193
194 path = QPainterPath();
195
196 float acc[w];
197 for (int i = 0; i < w; ++i) acc[i] = 0.f;
198 for (int j = 0; j < 3; ++j) {
199 for (int i = 0; i < step * 2; ++i) {
200 acc[j * step + i] += windower.getValue(i);
201 }
202 }
203 for (int i = 0; i < w; ++i) {
204 int y = h - int(peak * acc[i] + 0.001) + 1;
205 if (i == 0) path.moveTo(i, y);
206 else path.lineTo(i, y);
207 }
208
209 timePainter.drawPath(path);
210 timePainter.setRenderHint(QPainter::Antialiasing, false);
211
212 path = QPainterPath();
213
214 timePainter.setPen(Qt::black);
215
216 for (int i = 0; i < step * 2; ++i) {
217 int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
218 if (i == 0) path.moveTo(i + step, float(y));
219 else path.lineTo(i + step, float(y));
220 }
221
222 if (type == RectangularWindow) {
223 timePainter.drawPath(path);
224 path = QPainterPath();
225 }
226
227 timePainter.setRenderHint(QPainter::Antialiasing, true);
228 path.addRect(0, 0, w, h + 1);
229 timePainter.drawPath(path);
230
231 QFont font;
232 font.setPixelSize(10);
233 font.setItalic(true);
234 timePainter.setFont(font);
235 QString label = tr("V / time");
236 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
237 timePainter.fontMetrics().ascent() + 1, label);
238
239 m_windowTimeExampleLabel->setPixmap(timeLabel);
240
241 int fw = 100;
242
243 QPixmap freqLabel(fw, h + 1);
244 freqLabel.fill(Qt::white);
245 QPainter freqPainter(&freqLabel);
246 path = QPainterPath();
247
248 size_t fftsize = 512;
249
250 float *input = (float *)fftwf_malloc(fftsize * sizeof(float));
251 fftwf_complex *output =
252 (fftwf_complex *)fftwf_malloc(fftsize * sizeof(fftwf_complex));
253 fftwf_plan plan = fftwf_plan_dft_r2c_1d(fftsize, input, output,
254 FFTW_ESTIMATE);
255 for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
256 for (int i = 0; i < step * 2; ++i) {
257 input[fftsize/2 - step + i] = windower.getValue(i);
258 }
259
260 fftwf_execute(plan);
261 fftwf_destroy_plan(plan);
262
263 float maxdb = 0.f;
264 float mindb = 0.f;
265 bool first = true;
266 for (int i = 0; i < fftsize/2; ++i) {
267 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
268 float db = mindb;
269 if (power > 0) {
270 db = 20 * log10(power);
271 if (first || db > maxdb) maxdb = db;
272 if (first || db < mindb) mindb = db;
273 first = false;
274 }
275 }
276
277 if (mindb > -80.f) mindb = -80.f;
278
279 // -- no, don't use the actual mindb -- it's easier to compare
280 // plots with a fixed min value
281 mindb = -170.f;
282
283 float maxval = maxdb + -mindb;
284
285 float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
286
287 path.moveTo(0, h - peak + 1);
288 path.lineTo(fw, h - peak + 1);
289
290 freqPainter.setPen(Qt::gray);
291 freqPainter.setRenderHint(QPainter::Antialiasing, true);
292 freqPainter.drawPath(path);
293
294 path = QPainterPath();
295 freqPainter.setPen(Qt::black);
296
297 // std::cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << std::endl;
298
299 for (int i = 0; i < fftsize/2; ++i) {
300 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
301 float db = 20 * log10(power);
302 float val = db + -mindb;
303 if (val < 0) val = 0;
304 float norm = val / maxval;
305 float x = (fw / float(fftsize/2)) * i;
306 float y = h - norm * peak + 1;
307 if (i == 0) path.moveTo(x, y);
308 else path.lineTo(x, y);
309 }
310
311 freqPainter.setRenderHint(QPainter::Antialiasing, true);
312 path.addRect(0, 0, fw, h + 1);
313 freqPainter.drawPath(path);
314
315 fftwf_free(input);
316 fftwf_free(output);
317
318 freqPainter.setFont(font);
319 label = tr("dB / freq");
320 freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4,
321 freqPainter.fontMetrics().ascent() + 1, label);
322
323 m_windowFreqExampleLabel->setPixmap(freqLabel);
324
325 m_windowType = type; 145 m_windowType = type;
326 m_applyButton->setEnabled(true); 146 m_applyButton->setEnabled(true);
327 } 147 }
328 148
329 void 149 void