comparison layer/SpectrumLayer.cpp @ 0:fc9323a41f5a

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