annotate layer/SpectrumLayer.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents be6d31baecb9
children
rev   line source
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