comparison widgets/WindowShapePreview.cpp @ 139:5ec6b60658d8

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