lbajardsilogic@0
|
1
|
lbajardsilogic@0
|
2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
3
|
lbajardsilogic@0
|
4 /*
|
lbajardsilogic@0
|
5 Sonic Visualiser
|
lbajardsilogic@0
|
6 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
7 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
8 This file copyright 2006-2007 QMUL.
|
lbajardsilogic@0
|
9
|
lbajardsilogic@0
|
10 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
11 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
12 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
13 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
14 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
15 */
|
lbajardsilogic@0
|
16
|
lbajardsilogic@0
|
17 #include "SpectrumLayer.h"
|
lbajardsilogic@0
|
18
|
lbajardsilogic@0
|
19 #include "system/System.h"
|
lbajardsilogic@0
|
20 #include "data/model/FFTModel.h"
|
lbajardsilogic@0
|
21 #include "view/View.h"
|
lbajardsilogic@0
|
22 #include "base/AudioLevel.h"
|
lbajardsilogic@0
|
23 #include "base/Preferences.h"
|
lbajardsilogic@0
|
24 #include "base/RangeMapper.h"
|
lbajardsilogic@0
|
25
|
lbajardsilogic@0
|
26 SpectrumLayer::SpectrumLayer() :
|
lbajardsilogic@0
|
27 m_originModel(0),
|
lbajardsilogic@0
|
28 m_channel(-1),
|
lbajardsilogic@0
|
29 m_channelSet(false),
|
lbajardsilogic@0
|
30 m_windowSize(1024),
|
lbajardsilogic@0
|
31 m_windowType(HanningWindow),
|
lbajardsilogic@0
|
32 m_windowHopLevel(2)
|
lbajardsilogic@0
|
33 {
|
lbajardsilogic@0
|
34 Preferences *prefs = Preferences::getInstance();
|
lbajardsilogic@0
|
35 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
|
lbajardsilogic@0
|
36 this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
|
lbajardsilogic@0
|
37 setWindowType(prefs->getWindowType());
|
lbajardsilogic@0
|
38
|
lbajardsilogic@0
|
39 setBinScale(LogBins);
|
lbajardsilogic@0
|
40 }
|
lbajardsilogic@0
|
41
|
lbajardsilogic@0
|
42 SpectrumLayer::~SpectrumLayer()
|
lbajardsilogic@0
|
43 {
|
lbajardsilogic@0
|
44 //!!! delete parent's model
|
lbajardsilogic@0
|
45 // for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i];
|
lbajardsilogic@0
|
46 }
|
lbajardsilogic@0
|
47
|
lbajardsilogic@0
|
48 void
|
lbajardsilogic@0
|
49 SpectrumLayer::setModel(DenseTimeValueModel *model)
|
lbajardsilogic@0
|
50 {
|
lbajardsilogic@0
|
51 if (m_originModel == model) return;
|
lbajardsilogic@0
|
52 m_originModel = model;
|
lbajardsilogic@0
|
53 setupFFT();
|
lbajardsilogic@0
|
54 }
|
lbajardsilogic@0
|
55
|
lbajardsilogic@0
|
56 void
|
lbajardsilogic@0
|
57 SpectrumLayer::setupFFT()
|
lbajardsilogic@0
|
58 {
|
lbajardsilogic@0
|
59 FFTModel *oldFFT = dynamic_cast<FFTModel *>
|
lbajardsilogic@0
|
60 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
|
lbajardsilogic@0
|
61
|
lbajardsilogic@0
|
62 if (oldFFT) {
|
lbajardsilogic@0
|
63 setSliceableModel(0);
|
lbajardsilogic@0
|
64 delete oldFFT;
|
lbajardsilogic@0
|
65 }
|
lbajardsilogic@0
|
66
|
lbajardsilogic@0
|
67 FFTModel *newFFT = new FFTModel(m_originModel,
|
lbajardsilogic@0
|
68 m_channel,
|
lbajardsilogic@0
|
69 m_windowType,
|
lbajardsilogic@0
|
70 m_windowSize,
|
lbajardsilogic@0
|
71 getWindowIncrement(),
|
lbajardsilogic@0
|
72 m_windowSize,
|
lbajardsilogic@0
|
73 true);
|
lbajardsilogic@0
|
74
|
lbajardsilogic@0
|
75 setSliceableModel(newFFT);
|
lbajardsilogic@0
|
76
|
lbajardsilogic@0
|
77 newFFT->resume();
|
lbajardsilogic@0
|
78 }
|
lbajardsilogic@0
|
79
|
lbajardsilogic@0
|
80 void
|
lbajardsilogic@0
|
81 SpectrumLayer::setChannel(int channel)
|
lbajardsilogic@0
|
82 {
|
lbajardsilogic@0
|
83 m_channelSet = true;
|
lbajardsilogic@0
|
84
|
lbajardsilogic@0
|
85 FFTModel *fft = dynamic_cast<FFTModel *>
|
lbajardsilogic@0
|
86 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
|
lbajardsilogic@0
|
87
|
lbajardsilogic@0
|
88 if (m_channel == channel) {
|
lbajardsilogic@0
|
89 if (fft) fft->resume();
|
lbajardsilogic@0
|
90 return;
|
lbajardsilogic@0
|
91 }
|
lbajardsilogic@0
|
92
|
lbajardsilogic@0
|
93 m_channel = channel;
|
lbajardsilogic@0
|
94
|
lbajardsilogic@0
|
95 if (!fft) setupFFT();
|
lbajardsilogic@0
|
96
|
lbajardsilogic@0
|
97 emit layerParametersChanged();
|
lbajardsilogic@0
|
98 }
|
lbajardsilogic@0
|
99
|
lbajardsilogic@0
|
100 Layer::PropertyList
|
lbajardsilogic@0
|
101 SpectrumLayer::getProperties() const
|
lbajardsilogic@0
|
102 {
|
lbajardsilogic@0
|
103 PropertyList list = SliceLayer::getProperties();
|
lbajardsilogic@0
|
104 list.push_back("Window Size");
|
lbajardsilogic@0
|
105 list.push_back("Window Increment");
|
lbajardsilogic@0
|
106 return list;
|
lbajardsilogic@0
|
107 }
|
lbajardsilogic@0
|
108
|
lbajardsilogic@0
|
109 QString
|
lbajardsilogic@0
|
110 SpectrumLayer::getPropertyLabel(const PropertyName &name) const
|
lbajardsilogic@0
|
111 {
|
lbajardsilogic@0
|
112 if (name == "Window Size") return tr("Window Size");
|
lbajardsilogic@0
|
113 if (name == "Window Increment") return tr("Window Overlap");
|
lbajardsilogic@0
|
114 return SliceLayer::getPropertyLabel(name);
|
lbajardsilogic@0
|
115 }
|
lbajardsilogic@0
|
116
|
lbajardsilogic@0
|
117 Layer::PropertyType
|
lbajardsilogic@0
|
118 SpectrumLayer::getPropertyType(const PropertyName &name) const
|
lbajardsilogic@0
|
119 {
|
lbajardsilogic@0
|
120 if (name == "Window Size") return ValueProperty;
|
lbajardsilogic@0
|
121 if (name == "Window Increment") return ValueProperty;
|
lbajardsilogic@0
|
122 return SliceLayer::getPropertyType(name);
|
lbajardsilogic@0
|
123 }
|
lbajardsilogic@0
|
124
|
lbajardsilogic@0
|
125 QString
|
lbajardsilogic@0
|
126 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const
|
lbajardsilogic@0
|
127 {
|
lbajardsilogic@0
|
128 if (name == "Window Size" ||
|
lbajardsilogic@0
|
129 name == "Window Increment") return tr("Window");
|
lbajardsilogic@0
|
130 return SliceLayer::getPropertyGroupName(name);
|
lbajardsilogic@0
|
131 }
|
lbajardsilogic@0
|
132
|
lbajardsilogic@0
|
133 int
|
lbajardsilogic@0
|
134 SpectrumLayer::getPropertyRangeAndValue(const PropertyName &name,
|
lbajardsilogic@0
|
135 int *min, int *max, int *deflt) const
|
lbajardsilogic@0
|
136 {
|
lbajardsilogic@0
|
137 int val = 0;
|
lbajardsilogic@0
|
138
|
lbajardsilogic@0
|
139 int garbage0, garbage1, garbage2;
|
lbajardsilogic@0
|
140 if (!min) min = &garbage0;
|
lbajardsilogic@0
|
141 if (!max) max = &garbage1;
|
lbajardsilogic@0
|
142 if (!deflt) deflt = &garbage2;
|
lbajardsilogic@0
|
143
|
lbajardsilogic@0
|
144 if (name == "Window Size") {
|
lbajardsilogic@0
|
145
|
lbajardsilogic@0
|
146 *min = 0;
|
lbajardsilogic@0
|
147 *max = 10;
|
lbajardsilogic@0
|
148 *deflt = 5;
|
lbajardsilogic@0
|
149
|
lbajardsilogic@0
|
150 val = 0;
|
lbajardsilogic@0
|
151 int ws = m_windowSize;
|
lbajardsilogic@0
|
152 while (ws > 32) { ws >>= 1; val ++; }
|
lbajardsilogic@0
|
153
|
lbajardsilogic@0
|
154 } else if (name == "Window Increment") {
|
lbajardsilogic@0
|
155
|
lbajardsilogic@0
|
156 *min = 0;
|
lbajardsilogic@0
|
157 *max = 5;
|
lbajardsilogic@0
|
158 *deflt = 2;
|
lbajardsilogic@0
|
159
|
lbajardsilogic@0
|
160 val = m_windowHopLevel;
|
lbajardsilogic@0
|
161
|
lbajardsilogic@0
|
162 } else {
|
lbajardsilogic@0
|
163
|
lbajardsilogic@0
|
164 val = SliceLayer::getPropertyRangeAndValue(name, min, max, deflt);
|
lbajardsilogic@0
|
165 }
|
lbajardsilogic@0
|
166
|
lbajardsilogic@0
|
167 return val;
|
lbajardsilogic@0
|
168 }
|
lbajardsilogic@0
|
169
|
lbajardsilogic@0
|
170 QString
|
lbajardsilogic@0
|
171 SpectrumLayer::getPropertyValueLabel(const PropertyName &name,
|
lbajardsilogic@0
|
172 int value) const
|
lbajardsilogic@0
|
173 {
|
lbajardsilogic@0
|
174 if (name == "Window Size") {
|
lbajardsilogic@0
|
175 return QString("%1").arg(32 << value);
|
lbajardsilogic@0
|
176 }
|
lbajardsilogic@0
|
177 if (name == "Window Increment") {
|
lbajardsilogic@0
|
178 switch (value) {
|
lbajardsilogic@0
|
179 default:
|
lbajardsilogic@0
|
180 case 0: return tr("None");
|
lbajardsilogic@0
|
181 case 1: return tr("25 %");
|
lbajardsilogic@0
|
182 case 2: return tr("50 %");
|
lbajardsilogic@0
|
183 case 3: return tr("75 %");
|
lbajardsilogic@0
|
184 case 4: return tr("87.5 %");
|
lbajardsilogic@0
|
185 case 5: return tr("93.75 %");
|
lbajardsilogic@0
|
186 }
|
lbajardsilogic@0
|
187 }
|
lbajardsilogic@0
|
188 return SliceLayer::getPropertyValueLabel(name, value);
|
lbajardsilogic@0
|
189 }
|
lbajardsilogic@0
|
190
|
lbajardsilogic@0
|
191 RangeMapper *
|
lbajardsilogic@0
|
192 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const
|
lbajardsilogic@0
|
193 {
|
lbajardsilogic@0
|
194 return SliceLayer::getNewPropertyRangeMapper(name);
|
lbajardsilogic@0
|
195 }
|
lbajardsilogic@0
|
196
|
lbajardsilogic@0
|
197 void
|
lbajardsilogic@0
|
198 SpectrumLayer::setProperty(const PropertyName &name, int value)
|
lbajardsilogic@0
|
199 {
|
lbajardsilogic@0
|
200 if (name == "Window Size") {
|
lbajardsilogic@0
|
201 setWindowSize(32 << value);
|
lbajardsilogic@0
|
202 } else if (name == "Window Increment") {
|
lbajardsilogic@0
|
203 setWindowHopLevel(value);
|
lbajardsilogic@0
|
204 } else {
|
lbajardsilogic@0
|
205 SliceLayer::setProperty(name, value);
|
lbajardsilogic@0
|
206 }
|
lbajardsilogic@0
|
207 }
|
lbajardsilogic@0
|
208
|
lbajardsilogic@0
|
209 void
|
lbajardsilogic@0
|
210 SpectrumLayer::setWindowSize(size_t ws)
|
lbajardsilogic@0
|
211 {
|
lbajardsilogic@0
|
212 if (m_windowSize == ws) return;
|
lbajardsilogic@0
|
213 m_windowSize = ws;
|
lbajardsilogic@0
|
214 setupFFT();
|
lbajardsilogic@0
|
215 emit layerParametersChanged();
|
lbajardsilogic@0
|
216 }
|
lbajardsilogic@0
|
217
|
lbajardsilogic@0
|
218 void
|
lbajardsilogic@0
|
219 SpectrumLayer::setWindowHopLevel(size_t v)
|
lbajardsilogic@0
|
220 {
|
lbajardsilogic@0
|
221 if (m_windowHopLevel == v) return;
|
lbajardsilogic@0
|
222 m_windowHopLevel = v;
|
lbajardsilogic@0
|
223 setupFFT();
|
lbajardsilogic@0
|
224 emit layerParametersChanged();
|
lbajardsilogic@0
|
225 }
|
lbajardsilogic@0
|
226
|
lbajardsilogic@0
|
227 void
|
lbajardsilogic@0
|
228 SpectrumLayer::setWindowType(WindowType w)
|
lbajardsilogic@0
|
229 {
|
lbajardsilogic@0
|
230 if (m_windowType == w) return;
|
lbajardsilogic@0
|
231 m_windowType = w;
|
lbajardsilogic@0
|
232 setupFFT();
|
lbajardsilogic@0
|
233 emit layerParametersChanged();
|
lbajardsilogic@0
|
234 }
|
lbajardsilogic@0
|
235
|
lbajardsilogic@0
|
236 void
|
lbajardsilogic@0
|
237 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name)
|
lbajardsilogic@0
|
238 {
|
lbajardsilogic@0
|
239 if (name == "Window Type") {
|
lbajardsilogic@0
|
240 setWindowType(Preferences::getInstance()->getWindowType());
|
lbajardsilogic@0
|
241 return;
|
lbajardsilogic@0
|
242 }
|
lbajardsilogic@0
|
243 }
|
lbajardsilogic@0
|
244
|
lbajardsilogic@0
|
245 bool
|
lbajardsilogic@0
|
246 SpectrumLayer::getValueExtents(float &, float &, bool &, QString &) const
|
lbajardsilogic@0
|
247 {
|
lbajardsilogic@0
|
248 return false;
|
lbajardsilogic@0
|
249 }
|
lbajardsilogic@0
|
250
|
lbajardsilogic@0
|
251 QString
|
lbajardsilogic@0
|
252 SpectrumLayer::getFeatureDescription(View *v, QPoint &p) const
|
lbajardsilogic@0
|
253 {
|
lbajardsilogic@0
|
254 if (!m_sliceableModel) return "";
|
lbajardsilogic@0
|
255
|
lbajardsilogic@0
|
256 int minbin = 0, maxbin = 0, range = 0;
|
lbajardsilogic@0
|
257 QString genericDesc = SliceLayer::getFeatureDescription
|
lbajardsilogic@0
|
258 (v, p, false, minbin, maxbin, range);
|
lbajardsilogic@0
|
259
|
lbajardsilogic@0
|
260 if (genericDesc == "") return "";
|
lbajardsilogic@0
|
261
|
lbajardsilogic@0
|
262 float minvalue = 0.f;
|
lbajardsilogic@0
|
263 if (minbin < int(m_values.size())) minvalue = m_values[minbin];
|
lbajardsilogic@0
|
264
|
lbajardsilogic@0
|
265 float maxvalue = minvalue;
|
lbajardsilogic@0
|
266 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin];
|
lbajardsilogic@0
|
267
|
lbajardsilogic@0
|
268 if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
|
lbajardsilogic@0
|
269
|
lbajardsilogic@0
|
270 QString binstr;
|
lbajardsilogic@0
|
271 QString hzstr;
|
lbajardsilogic@0
|
272 int minfreq = lrintf((minbin * m_sliceableModel->getSampleRate()) /
|
lbajardsilogic@0
|
273 m_windowSize);
|
lbajardsilogic@191
|
274 int maxfreq = lrintf((MAX(maxbin, minbin+1)
|
lbajardsilogic@0
|
275 * m_sliceableModel->getSampleRate()) /
|
lbajardsilogic@0
|
276 m_windowSize);
|
lbajardsilogic@0
|
277
|
lbajardsilogic@0
|
278 if (maxbin != minbin) {
|
lbajardsilogic@0
|
279 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
|
lbajardsilogic@0
|
280 } else {
|
lbajardsilogic@0
|
281 binstr = QString("%1").arg(minbin+1);
|
lbajardsilogic@0
|
282 }
|
lbajardsilogic@0
|
283 if (minfreq != maxfreq) {
|
lbajardsilogic@0
|
284 hzstr = tr("%1 - %2 Hz").arg(minfreq).arg(maxfreq);
|
lbajardsilogic@0
|
285 } else {
|
lbajardsilogic@0
|
286 hzstr = tr("%1 Hz").arg(minfreq);
|
lbajardsilogic@0
|
287 }
|
lbajardsilogic@0
|
288
|
lbajardsilogic@0
|
289 QString valuestr;
|
lbajardsilogic@0
|
290 if (maxvalue != minvalue) {
|
lbajardsilogic@0
|
291 valuestr = tr("%1 - %2").arg(minvalue).arg(maxvalue);
|
lbajardsilogic@0
|
292 } else {
|
lbajardsilogic@0
|
293 valuestr = QString("%1").arg(minvalue);
|
lbajardsilogic@0
|
294 }
|
lbajardsilogic@0
|
295
|
lbajardsilogic@0
|
296 QString dbstr;
|
lbajardsilogic@0
|
297 float mindb = AudioLevel::multiplier_to_dB(minvalue);
|
lbajardsilogic@0
|
298 float maxdb = AudioLevel::multiplier_to_dB(maxvalue);
|
lbajardsilogic@0
|
299 QString mindbstr;
|
lbajardsilogic@0
|
300 QString maxdbstr;
|
lbajardsilogic@0
|
301 if (mindb == AudioLevel::DB_FLOOR) {
|
lbajardsilogic@0
|
302 mindbstr = tr("-Inf");
|
lbajardsilogic@0
|
303 } else {
|
lbajardsilogic@0
|
304 mindbstr = QString("%1").arg(lrintf(mindb));
|
lbajardsilogic@0
|
305 }
|
lbajardsilogic@0
|
306 if (maxdb == AudioLevel::DB_FLOOR) {
|
lbajardsilogic@0
|
307 maxdbstr = tr("-Inf");
|
lbajardsilogic@0
|
308 } else {
|
lbajardsilogic@0
|
309 maxdbstr = QString("%1").arg(lrintf(maxdb));
|
lbajardsilogic@0
|
310 }
|
lbajardsilogic@0
|
311 if (lrintf(mindb) != lrintf(maxdb)) {
|
lbajardsilogic@0
|
312 dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr);
|
lbajardsilogic@0
|
313 } else {
|
lbajardsilogic@0
|
314 dbstr = tr("%1").arg(mindbstr);
|
lbajardsilogic@0
|
315 }
|
lbajardsilogic@0
|
316
|
lbajardsilogic@0
|
317 QString description;
|
lbajardsilogic@0
|
318
|
lbajardsilogic@0
|
319 if (range > int(m_sliceableModel->getResolution())) {
|
lbajardsilogic@0
|
320 description = tr("%1\nBin:\t%2 (%3)\n%4 value:\t%5\ndB:\t%6")
|
lbajardsilogic@0
|
321 .arg(genericDesc)
|
lbajardsilogic@0
|
322 .arg(binstr)
|
lbajardsilogic@0
|
323 .arg(hzstr)
|
lbajardsilogic@0
|
324 .arg(m_samplingMode == NearestSample ? tr("First") :
|
lbajardsilogic@0
|
325 m_samplingMode == SampleMean ? tr("Mean") : tr("Peak"))
|
lbajardsilogic@0
|
326 .arg(valuestr)
|
lbajardsilogic@0
|
327 .arg(dbstr);
|
lbajardsilogic@0
|
328 } else {
|
lbajardsilogic@0
|
329 description = tr("%1\nBin:\t%2 (%3)\nValue:\t%4\ndB:\t%5")
|
lbajardsilogic@0
|
330 .arg(genericDesc)
|
lbajardsilogic@0
|
331 .arg(binstr)
|
lbajardsilogic@0
|
332 .arg(hzstr)
|
lbajardsilogic@0
|
333 .arg(valuestr)
|
lbajardsilogic@0
|
334 .arg(dbstr);
|
lbajardsilogic@0
|
335 }
|
lbajardsilogic@0
|
336
|
lbajardsilogic@0
|
337 return description;
|
lbajardsilogic@0
|
338 }
|
lbajardsilogic@0
|
339
|
lbajardsilogic@0
|
340
|
lbajardsilogic@0
|
341 QString
|
lbajardsilogic@0
|
342 SpectrumLayer::toXmlString(QString indent, QString extraAttributes) const
|
lbajardsilogic@0
|
343 {
|
lbajardsilogic@0
|
344 QString s;
|
lbajardsilogic@0
|
345
|
lbajardsilogic@0
|
346 s += QString("windowSize=\"%1\" "
|
lbajardsilogic@0
|
347 "windowHopLevel=\"%2\"")
|
lbajardsilogic@0
|
348 .arg(m_windowSize)
|
lbajardsilogic@0
|
349 .arg(m_windowHopLevel);
|
lbajardsilogic@0
|
350
|
lbajardsilogic@0
|
351 return SliceLayer::toXmlString(indent, extraAttributes + " " + s);
|
lbajardsilogic@0
|
352 }
|
lbajardsilogic@0
|
353
|
lbajardsilogic@0
|
354 void
|
lbajardsilogic@0
|
355 SpectrumLayer::setProperties(const QXmlAttributes &attributes)
|
lbajardsilogic@0
|
356 {
|
lbajardsilogic@0
|
357 SliceLayer::setProperties(attributes);
|
lbajardsilogic@0
|
358
|
lbajardsilogic@0
|
359 bool ok = false;
|
lbajardsilogic@0
|
360
|
lbajardsilogic@0
|
361 size_t windowSize = attributes.value("windowSize").toUInt(&ok);
|
lbajardsilogic@0
|
362 if (ok) setWindowSize(windowSize);
|
lbajardsilogic@0
|
363
|
lbajardsilogic@0
|
364 size_t windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok);
|
lbajardsilogic@0
|
365 if (ok) setWindowHopLevel(windowHopLevel);
|
lbajardsilogic@0
|
366 }
|
lbajardsilogic@0
|
367
|
lbajardsilogic@0
|
368
|