Mercurial > hg > svgui
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 |