svgui  1.9
SpectrumLayer.cpp
Go to the documentation of this file.
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-2007 QMUL.
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 "SpectrumLayer.h"
17 
18 #include "data/model/FFTModel.h"
19 #include "view/View.h"
20 #include "base/AudioLevel.h"
21 #include "base/Preferences.h"
22 #include "base/RangeMapper.h"
23 #include "base/Pitch.h"
24 #include "ColourMapper.h"
25 
26 #include <QPainter>
27 #include <QTextStream>
28 
29 
31  m_originModel(0),
32  m_channel(-1),
33  m_channelSet(false),
34  m_windowSize(4096),
35  m_windowType(HanningWindow),
36  m_windowHopLevel(3),
37  m_showPeaks(false),
38  m_newFFTNeeded(true)
39 {
40  Preferences *prefs = Preferences::getInstance();
41  connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
42  this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
43  setWindowType(prefs->getWindowType());
44 
46 }
47 
49 {
50  Model *m = const_cast<Model *>
51  (static_cast<const Model *>(m_sliceableModel));
52  if (m) m->aboutToDelete();
53  m_sliceableModel = 0;
54  delete m;
55 }
56 
57 void
58 SpectrumLayer::setModel(DenseTimeValueModel *model)
59 {
60  SVDEBUG << "SpectrumLayer::setModel(" << model << ") from " << m_originModel << endl;
61 
62  if (m_originModel == model) return;
63 
64  m_originModel = model;
65 
66  if (m_sliceableModel) {
67  Model *m = const_cast<Model *>
68  (static_cast<const Model *>(m_sliceableModel));
69  m->aboutToDelete();
71  delete m;
72  }
73 
74  m_newFFTNeeded = true;
75 
77 }
78 
79 void
81 {
82  SVDEBUG << "SpectrumLayer::setChannel(" << channel << ") from " << m_channel << endl;
83 
84  m_channelSet = true;
85 
86  if (m_channel == channel) return;
87 
88  m_channel = channel;
89 
90  m_newFFTNeeded = true;
91 
93 }
94 
95 void
97 {
98  if (m_sliceableModel) {
99  Model *m = const_cast<Model *>
100  (static_cast<const Model *>(m_sliceableModel));
101  m->aboutToDelete();
103  delete m;
104  }
105 
106  if (!m_originModel) {
107  return;
108  }
109 
110  FFTModel *newFFT = new FFTModel(m_originModel,
111  m_channel,
112  m_windowType,
113  m_windowSize,
115  m_windowSize,
116  false,
117  StorageAdviser::Criteria
118  (StorageAdviser::SpeedCritical |
119  StorageAdviser::FrequentLookupLikely));
120 
121  setSliceableModel(newFFT);
122 
123  m_biasCurve.clear();
124  for (int i = 0; i < m_windowSize; ++i) {
125  m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f));
126  }
127 
128  newFFT->resume();
129 
130  m_newFFTNeeded = false;
131 }
132 
133 Layer::PropertyList
135 {
136  PropertyList list = SliceLayer::getProperties();
137  list.push_back("Window Size");
138  list.push_back("Window Increment");
139  list.push_back("Show Peak Frequencies");
140  return list;
141 }
142 
143 QString
144 SpectrumLayer::getPropertyLabel(const PropertyName &name) const
145 {
146  if (name == "Window Size") return tr("Window Size");
147  if (name == "Window Increment") return tr("Window Overlap");
148  if (name == "Show Peak Frequencies") return tr("Show Peak Frequencies");
149  return SliceLayer::getPropertyLabel(name);
150 }
151 
152 QString
153 SpectrumLayer::getPropertyIconName(const PropertyName &name) const
154 {
155  if (name == "Show Peak Frequencies") return "show-peaks";
156  return SliceLayer::getPropertyIconName(name);
157 }
158 
159 Layer::PropertyType
160 SpectrumLayer::getPropertyType(const PropertyName &name) const
161 {
162  if (name == "Window Size") return ValueProperty;
163  if (name == "Window Increment") return ValueProperty;
164  if (name == "Show Peak Frequencies") return ToggleProperty;
165  return SliceLayer::getPropertyType(name);
166 }
167 
168 QString
169 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const
170 {
171  if (name == "Window Size" ||
172  name == "Window Increment") return tr("Window");
173  if (name == "Show Peak Frequencies") return tr("Bins");
175 }
176 
177 int
179  int *min, int *max, int *deflt) const
180 {
181  int val = 0;
182 
183  int garbage0, garbage1, garbage2;
184  if (!min) min = &garbage0;
185  if (!max) max = &garbage1;
186  if (!deflt) deflt = &garbage2;
187 
188  if (name == "Window Size") {
189 
190  *min = 0;
191  *max = 15;
192  *deflt = 5;
193 
194  val = 0;
195  int ws = m_windowSize;
196  while (ws > 32) { ws >>= 1; val ++; }
197 
198  } else if (name == "Window Increment") {
199 
200  *min = 0;
201  *max = 5;
202  *deflt = 2;
203 
204  val = m_windowHopLevel;
205 
206  } else if (name == "Show Peak Frequencies") {
207 
208  return m_showPeaks ? 1 : 0;
209 
210  } else {
211 
212  val = SliceLayer::getPropertyRangeAndValue(name, min, max, deflt);
213  }
214 
215  return val;
216 }
217 
218 QString
219 SpectrumLayer::getPropertyValueLabel(const PropertyName &name,
220  int value) const
221 {
222  if (name == "Window Size") {
223  return QString("%1").arg(32 << value);
224  }
225  if (name == "Window Increment") {
226  switch (value) {
227  default:
228  case 0: return tr("None");
229  case 1: return tr("25 %");
230  case 2: return tr("50 %");
231  case 3: return tr("75 %");
232  case 4: return tr("87.5 %");
233  case 5: return tr("93.75 %");
234  }
235  }
236  return SliceLayer::getPropertyValueLabel(name, value);
237 }
238 
239 RangeMapper *
240 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const
241 {
243 }
244 
245 void
246 SpectrumLayer::setProperty(const PropertyName &name, int value)
247 {
248  if (name == "Window Size") {
249  setWindowSize(32 << value);
250  } else if (name == "Window Increment") {
251  setWindowHopLevel(value);
252  } else if (name == "Show Peak Frequencies") {
253  setShowPeaks(value ? true : false);
254  } else {
255  SliceLayer::setProperty(name, value);
256  }
257 }
258 
259 void
261 {
262  if (m_windowSize == ws) return;
263  m_windowSize = ws;
264  m_newFFTNeeded = true;
265  emit layerParametersChanged();
266 }
267 
268 void
270 {
271  if (m_windowHopLevel == v) return;
272  m_windowHopLevel = v;
273  m_newFFTNeeded = true;
274  emit layerParametersChanged();
275 }
276 
277 void
279 {
280  if (m_windowType == w) return;
281  m_windowType = w;
282  m_newFFTNeeded = true;
283  emit layerParametersChanged();
284 }
285 
286 void
288 {
289  if (m_showPeaks == show) return;
290  m_showPeaks = show;
291  emit layerParametersChanged();
292 }
293 
294 void
295 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name)
296 {
297  if (name == "Window Type") {
298  setWindowType(Preferences::getInstance()->getWindowType());
299  return;
300  }
301 }
302 
303 bool
304 SpectrumLayer::getValueExtents(float &, float &, bool &, QString &) const
305 {
306  return false;
307 }
308 
309 float
310 SpectrumLayer::getXForBin(int bin, int totalBins, float w) const
311 {
312  if (!m_sliceableModel) return SliceLayer::getXForBin(bin, totalBins, w);
313 
314  float sampleRate = m_sliceableModel->getSampleRate();
315  float binfreq = (sampleRate * bin) / (totalBins * 2);
316 
317  return getXForFrequency(binfreq, w);
318 }
319 
320 int
321 SpectrumLayer::getBinForX(float x, int totalBins, float w) const
322 {
323  if (!m_sliceableModel) return SliceLayer::getBinForX(x, totalBins, w);
324 
325  float sampleRate = m_sliceableModel->getSampleRate();
326  float binfreq = getFrequencyForX(x, w);
327 
328  return int((binfreq * totalBins * 2) / sampleRate);
329 }
330 
331 float
332 SpectrumLayer::getFrequencyForX(float x, float w) const
333 {
334  float freq = 0;
335  if (!m_sliceableModel) return 0;
336 
337  int sampleRate = m_sliceableModel->getSampleRate();
338 
339  float maxfreq = float(sampleRate) / 2;
340 
341  switch (m_binScale) {
342 
343  case LinearBins:
344  freq = ((x * maxfreq) / w);
345  break;
346 
347  case LogBins:
348  freq = powf(10.f, (x * log10f(maxfreq)) / w);
349  break;
350 
351  case InvertedLogBins:
352  freq = maxfreq - powf(10.f, ((w - x) * log10f(maxfreq)) / w);
353  break;
354  }
355 
356  return freq;
357 }
358 
359 float
360 SpectrumLayer::getXForFrequency(float freq, float w) const
361 {
362  float x = 0;
363  if (!m_sliceableModel) return x;
364 
365  int sampleRate = m_sliceableModel->getSampleRate();
366 
367  float maxfreq = float(sampleRate) / 2;
368 
369  switch (m_binScale) {
370 
371  case LinearBins:
372  x = (freq * w) / maxfreq;
373  break;
374 
375  case LogBins:
376  x = (log10f(freq) * w) / log10f(maxfreq);
377  break;
378 
379  case InvertedLogBins:
380  if (maxfreq == freq) x = w;
381  else x = w - (log10f(maxfreq - freq) * w) / log10f(maxfreq);
382  break;
383  }
384 
385  return x;
386 }
387 
388 bool
390  float &value, QString &unit) const
391 {
392  if (m_xorigins.find(v) == m_xorigins.end()) return false;
393  int xorigin = m_xorigins.find(v)->second;
394  value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1);
395  unit = "Hz";
396  return true;
397 }
398 
399 bool
401  float &value, QString &unit) const
402 {
403  value = getValueForY(y, v);
404 
406 
407  if (value > 0.f) {
408  value = 10.f * log10f(value);
409  if (value < m_threshold) value = m_threshold;
410  } else value = m_threshold;
411 
412  unit = "dBV";
413 
414  } else {
415  unit = "V";
416  }
417 
418  return true;
419 }
420 
421 bool
422 SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1,
423  float &diff, QString &unit) const
424 {
425  bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit);
426  if (rv && (unit == "dBV")) unit = "dB";
427  return rv;
428 }
429 
430 
431 bool
433  QPoint cursorPos,
434  std::vector<QRect> &extents) const
435 {
436  QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->height() - cursorPos.y());
437  extents.push_back(vertical);
438 
439  QRect horizontal(0, cursorPos.y(), v->width(), 12);
440  extents.push_back(horizontal);
441 
442  int hoffset = 2;
443  if (m_binScale == LogBins) hoffset = 13;
444 
445  int sw = getVerticalScaleWidth(v, false, paint);
446 
447  QRect value(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
448  paint.fontMetrics().width("0.0000001 V") + 2,
449  paint.fontMetrics().height());
450  extents.push_back(value);
451 
452  QRect log(sw, cursorPos.y() + 2,
453  paint.fontMetrics().width("-80.000 dBV") + 2,
454  paint.fontMetrics().height());
455  extents.push_back(log);
456 
457  QRect freq(cursorPos.x(),
458  v->height() - paint.fontMetrics().height() - hoffset,
459  paint.fontMetrics().width("123456 Hz") + 2,
460  paint.fontMetrics().height());
461  extents.push_back(freq);
462 
463  int w(paint.fontMetrics().width("C#10+50c") + 2);
464  QRect pitch(cursorPos.x() - w,
465  v->height() - paint.fontMetrics().height() - hoffset,
466  w,
467  paint.fontMetrics().height());
468  extents.push_back(pitch);
469 
470  return true;
471 }
472 
473 void
475  QPoint cursorPos) const
476 {
477  if (!m_sliceableModel) return;
478 
479  paint.save();
480  QFont fn = paint.font();
481  if (fn.pointSize() > 8) {
482  fn.setPointSize(fn.pointSize() - 1);
483  paint.setFont(fn);
484  }
485 
486  ColourMapper mapper(m_colourMap, 0, 1);
487  paint.setPen(mapper.getContrastingColour());
488 
489  int xorigin = m_xorigins[v];
490  int w = v->width() - xorigin - 1;
491 
492  paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y());
493  paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height());
494 
495  float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
496 
497  int hoffset = 2;
498  if (m_binScale == LogBins) hoffset = 13;
499 
501  cursorPos.x() + 2,
502  v->height() - 2 - hoffset,
503  QString("%1 Hz").arg(fundamental),
505 
506  if (Pitch::isFrequencyInMidiRange(fundamental)) {
507  QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
509  cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2,
510  v->height() - 2 - hoffset,
511  pitchLabel,
513  }
514 
515  float value = getValueForY(cursorPos.y(), v);
516  float thresh = m_threshold;
517  float db = thresh;
518  if (value > 0.f) db = 10.f * log10f(value);
519  if (db < thresh) db = thresh;
520 
522  xorigin + 2,
523  cursorPos.y() - 2,
524  QString("%1 V").arg(value),
526 
528  xorigin + 2,
529  cursorPos.y() + 2 + paint.fontMetrics().ascent(),
530  QString("%1 dBV").arg(db),
532 
533  int harmonic = 2;
534 
535  while (harmonic < 100) {
536 
537  float hx = lrintf(getXForFrequency(fundamental * harmonic, w));
538  hx += xorigin;
539 
540  if (hx < xorigin || hx > v->width()) break;
541 
542  int len = 7;
543 
544  if (harmonic % 2 == 0) {
545  if (harmonic % 4 == 0) {
546  len = 12;
547  } else {
548  len = 10;
549  }
550  }
551 
552  paint.drawLine(int(hx),
553  cursorPos.y(),
554  int(hx),
555  cursorPos.y() + len);
556 
557  ++harmonic;
558  }
559 
560  paint.restore();
561 }
562 
563 QString
565 {
566  if (!m_sliceableModel) return "";
567 
568  int minbin = 0, maxbin = 0, range = 0;
569  QString genericDesc = SliceLayer::getFeatureDescriptionAux
570  (v, p, false, minbin, maxbin, range);
571 
572  if (genericDesc == "") return "";
573 
574  float minvalue = 0.f;
575  if (minbin < int(m_values.size())) minvalue = m_values[minbin];
576 
577  float maxvalue = minvalue;
578  if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin];
579 
580  if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
581 
582  QString binstr;
583  QString hzstr;
584  int minfreq = lrintf((minbin * m_sliceableModel->getSampleRate()) /
585  m_windowSize);
586  int maxfreq = lrintf((std::max(maxbin, minbin+1)
587  * m_sliceableModel->getSampleRate()) /
588  m_windowSize);
589 
590  if (maxbin != minbin) {
591  binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
592  } else {
593  binstr = QString("%1").arg(minbin+1);
594  }
595  if (minfreq != maxfreq) {
596  hzstr = tr("%1 - %2 Hz").arg(minfreq).arg(maxfreq);
597  } else {
598  hzstr = tr("%1 Hz").arg(minfreq);
599  }
600 
601  QString valuestr;
602  if (maxvalue != minvalue) {
603  valuestr = tr("%1 - %2").arg(minvalue).arg(maxvalue);
604  } else {
605  valuestr = QString("%1").arg(minvalue);
606  }
607 
608  QString dbstr;
609  float mindb = AudioLevel::multiplier_to_dB(minvalue);
610  float maxdb = AudioLevel::multiplier_to_dB(maxvalue);
611  QString mindbstr;
612  QString maxdbstr;
613  if (mindb == AudioLevel::DB_FLOOR) {
614  mindbstr = tr("-Inf");
615  } else {
616  mindbstr = QString("%1").arg(lrintf(mindb));
617  }
618  if (maxdb == AudioLevel::DB_FLOOR) {
619  maxdbstr = tr("-Inf");
620  } else {
621  maxdbstr = QString("%1").arg(lrintf(maxdb));
622  }
623  if (lrintf(mindb) != lrintf(maxdb)) {
624  dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr);
625  } else {
626  dbstr = tr("%1").arg(mindbstr);
627  }
628 
629  QString description;
630 
631  if (range > int(m_sliceableModel->getResolution())) {
632  description = tr("%1\nBin:\t%2 (%3)\n%4 value:\t%5\ndB:\t%6")
633  .arg(genericDesc)
634  .arg(binstr)
635  .arg(hzstr)
636  .arg(m_samplingMode == NearestSample ? tr("First") :
637  m_samplingMode == SampleMean ? tr("Mean") : tr("Peak"))
638  .arg(valuestr)
639  .arg(dbstr);
640  } else {
641  description = tr("%1\nBin:\t%2 (%3)\nValue:\t%4\ndB:\t%5")
642  .arg(genericDesc)
643  .arg(binstr)
644  .arg(hzstr)
645  .arg(valuestr)
646  .arg(dbstr);
647  }
648 
649  return description;
650 }
651 
652 void
653 SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const
654 {
655  if (!m_originModel || !m_originModel->isOK() ||
656  !m_originModel->isReady()) {
657  SVDEBUG << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl;
658  return;
659  }
660 
661  if (m_newFFTNeeded) {
662  SVDEBUG << "SpectrumLayer::paint: new FFT needed, calling setupFFT" << endl;
663  const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh
664  }
665 
666  FFTModel *fft = dynamic_cast<FFTModel *>
667  (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
668 
669  float thresh = (powf(10, -6) / m_gain) * (m_windowSize / 2.f); // -60dB adj
670 
671  int xorigin = getVerticalScaleWidth(v, false, paint) + 1;
672  int w = v->width() - xorigin - 1;
673 
674  int pkh = 0;
676  pkh = 10;
678 
679  paint.save();
680 
681  if (fft && m_showPeaks) {
682 
683  // draw peak lines
684 
685 // SVDEBUG << "Showing peaks..." << endl;
686 
687  int col = v->getCentreFrame() / fft->getResolution();
688 
689  paint.save();
690  paint.setRenderHint(QPainter::Antialiasing, false);
691  paint.setPen(QColor(160, 160, 160));
692 
693  int peakminbin = 0;
694  int peakmaxbin = fft->getHeight() - 1;
695  float peakmaxfreq = Pitch::getFrequencyForPitch(128);
696  peakmaxbin = ((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate());
697 
698  FFTModel::PeakSet peaks = fft->getPeakFrequencies
699  (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin);
700 
702 
703  BiasCurve curve;
704  getBiasCurve(curve);
705  int cs = curve.size();
706 
707  std::vector<float> values;
708 
709  for (int bin = 0; bin < fft->getHeight(); ++bin) {
710  float value = m_sliceableModel->getValueAt(col, bin);
711  if (bin < cs) value *= curve[bin];
712  values.push_back(value);
713  }
714 
715  for (FFTModel::PeakSet::iterator i = peaks.begin();
716  i != peaks.end(); ++i) {
717 
718  int bin = i->first;
719 
720 // cerr << "bin = " << bin << ", thresh = " << thresh << ", value = " << fft->getMagnitudeAt(col, bin) << endl;
721 
722  if (!fft->isOverThreshold(col, bin, thresh)) continue;
723 
724  float freq = i->second;
725 
726  int x = lrintf(getXForFrequency(freq, w));
727 
728  float norm = 0.f;
729  (void)getYForValue(values[bin], v, norm); // don't need return value, need norm
730 
731  paint.setPen(mapper.map(norm));
732  paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);
733  }
734 
735  paint.restore();
736  }
737 
738  SliceLayer::paint(v, paint, rect);
739 
741  //(keyboard, crosshairs etc) should be applicable to any slice
742  //layer whose model has a vertical scale unit of Hz. However, the
743  //dense 3d model at the moment doesn't record its vertical scale
744  //unit -- we need to fix that and hoist this code as appropriate.
745  //Same really goes for any code in SpectrogramLayer that could be
746  //relevant to Colour3DPlotLayer with unit Hz, but that's a bigger
747  //proposition.
748 
749 // if (m_binScale == LogBins) {
750 
751 // int pkh = 10;
752  int h = v->height();
753 
754  // piano keyboard
756  // nice to have a piano keyboard class, of course
757 
758  paint.drawLine(xorigin, h - pkh - 1, w + xorigin, h - pkh - 1);
759 
760  int px = xorigin, ppx = xorigin;
761  paint.setBrush(paint.pen().color());
762 
763  for (int i = 0; i < 128; ++i) {
764 
765  float f = Pitch::getFrequencyForPitch(i);
766  int x = lrintf(getXForFrequency(f, w));
767 
768  x += xorigin;
769 
770  if (i == 0) {
771  px = ppx = x;
772  }
773  if (i == 1) {
774  ppx = px - (x - px);
775  }
776 
777  if (x < xorigin) {
778  ppx = px;
779  px = x;
780  continue;
781  }
782 
783  if (x > w) {
784  break;
785  }
786 
787  int n = (i % 12);
788 
789  if (n == 1) {
790  // C# -- fill the C from here
791  QColor col = Qt::gray;
792  if (i == 61) { // filling middle C
793  col = Qt::blue;
794  col = col.light(150);
795  }
796  if (x - ppx > 2) {
797  paint.fillRect((px + ppx) / 2 + 1,
798  h - pkh,
799  x - (px + ppx) / 2 - 1,
800  pkh,
801  col);
802  }
803  }
804 
805  if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
806  // black notes
807  paint.drawLine(x, h - pkh, x, h);
808  int rw = lrintf(float(x - px) / 4) * 2;
809  if (rw < 2) rw = 2;
810  paint.drawRect(x - rw/2, h - pkh, rw, pkh/2);
811  } else if (n == 0 || n == 5) {
812  // C, F
813  if (px < w) {
814  paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h);
815  }
816  }
817 
818  ppx = px;
819  px = x;
820  }
821 // }
822 
823  paint.restore();
824 }
825 
826 void
827 SpectrumLayer::getBiasCurve(BiasCurve &curve) const
828 {
829  curve = m_biasCurve;
830 }
831 
832 void
833 SpectrumLayer::toXml(QTextStream &stream,
834  QString indent, QString extraAttributes) const
835 {
836  QString s = QString("windowSize=\"%1\" "
837  "windowHopLevel=\"%2\" "
838  "showPeaks=\"%3\" ")
839  .arg(m_windowSize)
840  .arg(m_windowHopLevel)
841  .arg(m_showPeaks ? "true" : "false");
842 
843  SliceLayer::toXml(stream, indent, extraAttributes + " " + s);
844 }
845 
846 void
847 SpectrumLayer::setProperties(const QXmlAttributes &attributes)
848 {
849  SliceLayer::setProperties(attributes);
850 
851  bool ok = false;
852 
853  int windowSize = attributes.value("windowSize").toUInt(&ok);
854  if (ok) setWindowSize(windowSize);
855 
856  int windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok);
857  if (ok) setWindowHopLevel(windowHopLevel);
858 
859  bool showPeaks = (attributes.value("showPeaks").trimmed() == "true");
860  setShowPeaks(showPeaks);
861 }
862 
863 
virtual float getXForBin(int bin, int totalBins, float w) const
EnergyScale m_energyScale
Definition: SliceLayer.h:135
virtual QString getPropertyLabel(const PropertyName &) const
Definition: SliceLayer.cpp:565
virtual PropertyList getProperties() const
float getXForFrequency(float freq, float w) const
virtual QString getPropertyIconName(const PropertyName &) const
Definition: SliceLayer.cpp:578
void setChannel(int)
virtual bool getValueExtents(float &min, float &max, bool &logarithmic, QString &unit) const
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
virtual QString getFeatureDescriptionAux(View *v, QPoint &, bool includeBinDescription, int &minbin, int &maxbin, int &range) const
Definition: SliceLayer.cpp:102
virtual float getXForBin(int bin, int totalBins, float w) const
Definition: SliceLayer.cpp:183
void setWindowSize(int)
virtual QString getFeatureDescription(View *v, QPoint &) const
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
Definition: SliceLayer.cpp:701
virtual PropertyType getPropertyType(const PropertyName &) const
Definition: SliceLayer.cpp:585
virtual float getYForValue(float value, const View *v, float &norm) const
Definition: SliceLayer.cpp:229
virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos, std::vector< QRect > &extents) const
virtual QString getPropertyGroupName(const PropertyName &) const
float getFrequencyForX(float x, float w) const
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
virtual bool getXScaleValue(const View *v, int x, float &value, QString &unit) const
Return the value and unit at the given x coordinate in the given view.
std::map< const View *, int > m_xorigins
Definition: SliceLayer.h:144
const DenseThreeDimensionalModel * m_sliceableModel
Definition: SliceLayer.h:133
virtual int getVerticalScaleWidth(View *, bool, QPainter &) const
Definition: SpectrumLayer.h:96
virtual QString getPropertyGroupName(const PropertyName &) const
Definition: SliceLayer.cpp:599
WindowType getWindowType() const
Definition: SpectrumLayer.h:91
virtual void setProperties(const QXmlAttributes &)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
Definition: SliceLayer.cpp:909
virtual void paintCrosshairs(View *, QPainter &, QPoint) const
virtual void getBiasCurve(BiasCurve &) const
virtual void setProperty(const PropertyName &, int value)
Definition: SliceLayer.cpp:757
int getWindowIncrement() const
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
Definition: SliceLayer.cpp:612
int m_colourMap
Definition: SliceLayer.h:134
BinScale m_binScale
Definition: SliceLayer.h:138
void preferenceChanged(PropertyContainer::PropertyName name)
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
virtual void setProperties(const QXmlAttributes &)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
virtual int getBinForX(float x, int totalBins, float w) const
Definition: SliceLayer.cpp:206
virtual PropertyList getProperties() const
Definition: SliceLayer.cpp:551
void setSliceableModel(const Model *model)
Definition: SliceLayer.cpp:54
void layerParametersChanged()
virtual QString getPropertyIconName(const PropertyName &) const
BiasCurve m_biasCurve
virtual float getValueForY(float y, const View *v) const
Definition: SliceLayer.cpp:279
std::vector< float > m_values
Definition: SliceLayer.h:149
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
virtual void setProperty(const PropertyName &, int value)
A class for mapping intensity values onto various colour maps.
Definition: ColourMapper.h:27
QColor map(float value) const
virtual RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const
Definition: SliceLayer.cpp:745
QColor getContrastingColour() const
virtual bool getYScaleValue(const View *, int y, float &value, QString &unit) const
Return the value and unit at the given y coordinate in the given view.
virtual bool getYScaleDifference(const View *, int y0, int y1, float &diff, QString &unit) const
Return the difference between the values at the given y coordinates in the given view,...
void setBinScale(BinScale scale)
Definition: SliceLayer.cpp:835
virtual int getBinForX(float x, int totalBins, float w) const
virtual RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const
WindowType m_windowType
virtual bool getYScaleDifference(const View *v, int y0, int y1, float &diff, QString &unit) const
Return the difference between the values at the given y coordinates in the given view,...
Definition: Layer.cpp:155
virtual QString getPropertyLabel(const PropertyName &) const
float m_threshold
Definition: SliceLayer.h:140
DenseTimeValueModel * m_originModel
std::vector< float > BiasCurve
Definition: SliceLayer.h:126
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
Definition: View.h:50
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
Definition: View.cpp:787
SamplingMode m_samplingMode
Definition: SliceLayer.h:136
int getCentreFrame() const
Return the centre frame of the visible widget.
Definition: View.h:81
virtual void paint(View *v, QPainter &paint, QRect rect) const
Paint the given rectangle of this layer onto the given view using the given painter,...
Definition: SliceLayer.cpp:316
float m_gain
Definition: SliceLayer.h:142
void setWindowType(WindowType type)
void setWindowHopLevel(int level)
void setShowPeaks(bool)
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
Definition: SliceLayer.cpp:883
virtual void paint(View *v, QPainter &paint, QRect rect) const
Paint the given rectangle of this layer onto the given view using the given painter,...
virtual PropertyType getPropertyType(const PropertyName &) const
void setModel(DenseTimeValueModel *model)