18 #include "data/model/FFTModel.h" 20 #include "base/AudioLevel.h" 21 #include "base/Preferences.h" 22 #include "base/RangeMapper.h" 23 #include "base/Pitch.h" 27 #include <QTextStream> 35 m_windowType(HanningWindow),
40 Preferences *prefs = Preferences::getInstance();
41 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
50 Model *m = const_cast<Model *>
52 if (m) m->aboutToDelete();
60 SVDEBUG <<
"SpectrumLayer::setModel(" << model <<
") from " <<
m_originModel << endl;
67 Model *m = const_cast<Model *>
82 SVDEBUG <<
"SpectrumLayer::setChannel(" << channel <<
") from " <<
m_channel << endl;
99 Model *m = const_cast<Model *>
117 StorageAdviser::Criteria
118 (StorageAdviser::SpeedCritical |
119 StorageAdviser::FrequentLookupLikely));
137 list.push_back(
"Window Size");
138 list.push_back(
"Window Increment");
139 list.push_back(
"Show Peak Frequencies");
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");
155 if (name ==
"Show Peak Frequencies")
return "show-peaks";
162 if (name ==
"Window Size")
return ValueProperty;
163 if (name ==
"Window Increment")
return ValueProperty;
164 if (name ==
"Show Peak Frequencies")
return ToggleProperty;
171 if (name ==
"Window Size" ||
172 name ==
"Window Increment")
return tr(
"Window");
173 if (name ==
"Show Peak Frequencies")
return tr(
"Bins");
179 int *min,
int *max,
int *deflt)
const 183 int garbage0, garbage1, garbage2;
184 if (!min) min = &garbage0;
185 if (!max) max = &garbage1;
186 if (!deflt) deflt = &garbage2;
188 if (name ==
"Window Size") {
196 while (ws > 32) { ws >>= 1; val ++; }
198 }
else if (name ==
"Window Increment") {
206 }
else if (name ==
"Show Peak Frequencies") {
222 if (name ==
"Window Size") {
223 return QString(
"%1").arg(32 << value);
225 if (name ==
"Window Increment") {
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 %");
248 if (name ==
"Window Size") {
250 }
else if (name ==
"Window Increment") {
252 }
else if (name ==
"Show Peak Frequencies") {
297 if (name ==
"Window Type") {
315 float binfreq = (sampleRate * bin) / (totalBins * 2);
328 return int((binfreq * totalBins * 2) / sampleRate);
339 float maxfreq = float(sampleRate) / 2;
344 freq = ((x * maxfreq) / w);
348 freq = powf(10.f, (x * log10f(maxfreq)) / w);
352 freq = maxfreq - powf(10.f, ((w - x) * log10f(maxfreq)) / w);
367 float maxfreq = float(sampleRate) / 2;
372 x = (freq * w) / maxfreq;
376 x = (log10f(freq) * w) / log10f(maxfreq);
380 if (maxfreq == freq) x = w;
381 else x = w - (log10f(maxfreq - freq) * w) / log10f(maxfreq);
390 float &value, QString &unit)
const 401 float &value, QString &unit)
const 408 value = 10.f * log10f(value);
423 float &diff, QString &unit)
const 426 if (rv && (unit ==
"dBV")) unit =
"dB";
434 std::vector<QRect> &extents)
const 436 QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->height() - cursorPos.y());
437 extents.push_back(vertical);
439 QRect horizontal(0, cursorPos.y(), v->width(), 12);
440 extents.push_back(horizontal);
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);
452 QRect log(sw, cursorPos.y() + 2,
453 paint.fontMetrics().width(
"-80.000 dBV") + 2,
454 paint.fontMetrics().height());
455 extents.push_back(log);
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);
463 int w(
paint.fontMetrics().width(
"C#10+50c") + 2);
464 QRect pitch(cursorPos.x() - w,
465 v->height() -
paint.fontMetrics().height() - hoffset,
467 paint.fontMetrics().height());
468 extents.push_back(pitch);
475 QPoint cursorPos)
const 480 QFont fn =
paint.font();
481 if (fn.pointSize() > 8) {
482 fn.setPointSize(fn.pointSize() - 1);
490 int w = v->width() - xorigin - 1;
492 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y());
493 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height());
502 v->height() - 2 - hoffset,
503 QString(
"%1 Hz").arg(fundamental),
506 if (Pitch::isFrequencyInMidiRange(fundamental)) {
507 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
509 cursorPos.x() -
paint.fontMetrics().width(pitchLabel) - 2,
510 v->height() - 2 - hoffset,
518 if (value > 0.f) db = 10.f * log10f(value);
519 if (db < thresh) db = thresh;
524 QString(
"%1 V").arg(value),
529 cursorPos.y() + 2 +
paint.fontMetrics().ascent(),
530 QString(
"%1 dBV").arg(db),
535 while (harmonic < 100) {
540 if (hx < xorigin || hx > v->width())
break;
544 if (harmonic % 2 == 0) {
545 if (harmonic % 4 == 0) {
552 paint.drawLine(
int(hx),
555 cursorPos.y() + len);
568 int minbin = 0, maxbin = 0, range = 0;
570 (v, p,
false, minbin, maxbin, range);
572 if (genericDesc ==
"")
return "";
574 float minvalue = 0.f;
577 float maxvalue = minvalue;
580 if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
586 int maxfreq = lrintf((std::max(maxbin, minbin+1)
590 if (maxbin != minbin) {
591 binstr = tr(
"%1 - %2").arg(minbin+1).arg(maxbin+1);
593 binstr = QString(
"%1").arg(minbin+1);
595 if (minfreq != maxfreq) {
596 hzstr = tr(
"%1 - %2 Hz").arg(minfreq).arg(maxfreq);
598 hzstr = tr(
"%1 Hz").arg(minfreq);
602 if (maxvalue != minvalue) {
603 valuestr = tr(
"%1 - %2").arg(minvalue).arg(maxvalue);
605 valuestr = QString(
"%1").arg(minvalue);
609 float mindb = AudioLevel::multiplier_to_dB(minvalue);
610 float maxdb = AudioLevel::multiplier_to_dB(maxvalue);
613 if (mindb == AudioLevel::DB_FLOOR) {
614 mindbstr = tr(
"-Inf");
616 mindbstr = QString(
"%1").arg(lrintf(mindb));
618 if (maxdb == AudioLevel::DB_FLOOR) {
619 maxdbstr = tr(
"-Inf");
621 maxdbstr = QString(
"%1").arg(lrintf(maxdb));
623 if (lrintf(mindb) != lrintf(maxdb)) {
624 dbstr = tr(
"%1 - %2").arg(mindbstr).arg(maxdbstr);
626 dbstr = tr(
"%1").arg(mindbstr);
632 description = tr(
"%1\nBin:\t%2 (%3)\n%4 value:\t%5\ndB:\t%6")
641 description = tr(
"%1\nBin:\t%2 (%3)\nValue:\t%4\ndB:\t%5")
657 SVDEBUG <<
"SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl;
662 SVDEBUG <<
"SpectrumLayer::paint: new FFT needed, calling setupFFT" << endl;
663 const_cast<SpectrumLayer *>(
this)->setupFFT();
666 FFTModel *fft = dynamic_cast<FFTModel *>
672 int w = v->width() - xorigin - 1;
690 paint.setRenderHint(QPainter::Antialiasing,
false);
691 paint.setPen(QColor(160, 160, 160));
694 int peakmaxbin = fft->getHeight() - 1;
695 float peakmaxfreq = Pitch::getFrequencyForPitch(128);
696 peakmaxbin = ((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate());
698 FFTModel::PeakSet peaks = fft->getPeakFrequencies
699 (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin);
705 int cs = curve.size();
707 std::vector<float> values;
709 for (
int bin = 0; bin < fft->getHeight(); ++bin) {
711 if (bin < cs) value *= curve[bin];
712 values.push_back(value);
715 for (FFTModel::PeakSet::iterator i = peaks.begin();
716 i != peaks.end(); ++i) {
722 if (!fft->isOverThreshold(col, bin, thresh))
continue;
724 float freq = i->second;
732 paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);
758 paint.drawLine(xorigin, h - pkh - 1, w + xorigin, h - pkh - 1);
760 int px = xorigin, ppx = xorigin;
763 for (
int i = 0; i < 128; ++i) {
765 float f = Pitch::getFrequencyForPitch(i);
791 QColor col = Qt::gray;
794 col = col.light(150);
797 paint.fillRect((px + ppx) / 2 + 1,
799 x - (px + ppx) / 2 - 1,
805 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
807 paint.drawLine(x, h - pkh, x, h);
808 int rw = lrintf(
float(x - px) / 4) * 2;
810 paint.drawRect(x - rw/2, h - pkh, rw, pkh/2);
811 }
else if (n == 0 || n == 5) {
814 paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h);
834 QString indent, QString extraAttributes)
const 836 QString s = QString(
"windowSize=\"%1\" " 837 "windowHopLevel=\"%2\" " 853 int windowSize = attributes.value(
"windowSize").toUInt(&ok);
856 int windowHopLevel = attributes.value(
"windowHopLevel").toUInt(&ok);
859 bool showPeaks = (attributes.value(
"showPeaks").trimmed() ==
"true");
virtual float getXForBin(int bin, int totalBins, float w) const
EnergyScale m_energyScale
virtual QString getPropertyLabel(const PropertyName &) const
virtual PropertyList getProperties() const
float getXForFrequency(float freq, float w) const
virtual QString getPropertyIconName(const PropertyName &) const
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
virtual float getXForBin(int bin, int totalBins, float w) const
virtual QString getFeatureDescription(View *v, QPoint &) const
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
virtual PropertyType getPropertyType(const PropertyName &) const
virtual float getYForValue(float value, const View *v, float &norm) const
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
const DenseThreeDimensionalModel * m_sliceableModel
virtual int getVerticalScaleWidth(View *, bool, QPainter &) const
virtual QString getPropertyGroupName(const PropertyName &) const
WindowType getWindowType() 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 void paintCrosshairs(View *, QPainter &, QPoint) const
virtual void getBiasCurve(BiasCurve &) const
virtual void setProperty(const PropertyName &, int value)
int getWindowIncrement() const
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
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
virtual PropertyList getProperties() const
void setSliceableModel(const Model *model)
void layerParametersChanged()
virtual QString getPropertyIconName(const PropertyName &) const
virtual float getValueForY(float y, const View *v) const
std::vector< float > m_values
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.
QColor map(float value) const
virtual RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const
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)
virtual int getBinForX(float x, int totalBins, float w) const
virtual RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const
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,...
virtual QString getPropertyLabel(const PropertyName &) const
DenseTimeValueModel * m_originModel
std::vector< float > BiasCurve
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
SamplingMode m_samplingMode
int getCentreFrame() const
Return the centre frame of the visible widget.
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,...
void setWindowType(WindowType type)
void setWindowHopLevel(int level)
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 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)