Mercurial > hg > svgui
changeset 280:3c402c6052f6
* Pull peak-picker out of SpectrumLayer and into FFTModel; use combined
peak-picker and frequency estimator for SpectrogramLayer (makes the
peak frequency spectrogram a bit quicker)
* Add more information to spectrum and spectrogram crosshairs
author | Chris Cannam |
---|---|
date | Wed, 04 Jul 2007 15:29:16 +0000 |
parents | 47fe0352861e |
children | ac58acbd7482 |
files | layer/Layer.cpp layer/Layer.h layer/SliceLayer.cpp layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp view/Pane.cpp widgets/LayerTree.cpp widgets/PropertyBox.cpp |
diffstat | 8 files changed, 131 insertions(+), 40 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/Layer.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/layer/Layer.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -272,6 +272,12 @@ } void +Layer::measureDoubleClick(View *v, QMouseEvent *e) +{ + // nothing +} + +void Layer::paintMeasurementRects(View *v, QPainter &paint, bool showFocus, QPoint focusPoint) const {
--- a/layer/Layer.h Tue Jul 03 18:56:27 2007 +0000 +++ b/layer/Layer.h Wed Jul 04 15:29:16 2007 +0000 @@ -170,6 +170,7 @@ virtual void measureStart(View *, QMouseEvent *); virtual void measureDrag(View *, QMouseEvent *); virtual void measureEnd(View *, QMouseEvent *); + virtual void measureDoubleClick(View *, QMouseEvent *); /** * Open an editor on the item under the mouse (e.g. on
--- a/layer/SliceLayer.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/layer/SliceLayer.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -133,6 +133,8 @@ range = f1 - f0 + 1; + QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str()); + if (includeBinDescription) { float minvalue = 0.f; @@ -157,10 +159,11 @@ valuestr = QString("%1").arg(minvalue); } - QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples\nBin:\t%4\n%5 value:\t%6") + QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)\nBin:\t%5\n%6 value:\t%7") .arg(QString::fromStdString(rt0.toText(true))) .arg(QString::fromStdString(rt1.toText(true))) .arg(range) + .arg(rtrangestr) .arg(binstr) .arg(m_samplingMode == NearestSample ? tr("First") : m_samplingMode == SampleMean ? tr("Mean") : tr("Peak")) @@ -170,10 +173,11 @@ } else { - QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples") + QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)") .arg(QString::fromStdString(rt0.toText(true))) .arg(QString::fromStdString(rt1.toText(true))) - .arg(range); + .arg(range) + .arg(rtrangestr); return description; }
--- a/layer/SpectrogramLayer.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/layer/SpectrogramLayer.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -2071,15 +2071,25 @@ MagnitudeRange mag; + FFTModel::PeakSet peaks; + if (m_binDisplay == PeakFrequencies && + s < int(fft->getWidth()) - 1) { + peaks = fft->getPeakFrequencies(FFTModel::AllPeaks, + s, + minbin, maxbin - 1); + } + for (size_t q = minbin; q < maxbin; ++q) { float y0 = yval[q + 1]; float y1 = yval[q]; - if (m_binDisplay == PeakBins || - m_binDisplay == PeakFrequencies) { + if (m_binDisplay == PeakBins) { if (!fft->isLocalPeak(s, q)) continue; } + if (m_binDisplay == PeakFrequencies) { + if (peaks.find(q) == peaks.end()) continue; + } if (m_threshold != 0.f && !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) { @@ -2090,14 +2100,9 @@ if (s == s0i) sprop *= (s + 1) - s0; if (s == s1i) sprop *= s1 - s; - if (m_binDisplay == PeakFrequencies && - s < int(fft->getWidth()) - 1) { - - float f = 0; - fft->estimateStableFrequency(s, q, f); - + if (m_binDisplay == PeakFrequencies) { y0 = y1 = v->getYForFrequency - (f, displayMinFreq, displayMaxFreq, logarithmic); + (peaks[q], displayMinFreq, displayMaxFreq, logarithmic); } int y0i = int(y0 + 0.001); @@ -2466,16 +2471,29 @@ int sw = getVerticalScaleWidth(v, paint); - QRect label(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2, - paint.fontMetrics().width("123456 Hz") + 2, - paint.fontMetrics().height()); - extents.push_back(label); + QRect freq(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2, + paint.fontMetrics().width("123456 Hz") + 2, + paint.fontMetrics().height()); + extents.push_back(freq); QRect pitch(sw, cursorPos.y() + 2, paint.fontMetrics().width("C#10+50c") + 2, paint.fontMetrics().height()); extents.push_back(pitch); + QRect rt(cursorPos.x(), + v->height() - paint.fontMetrics().height() - 2, + paint.fontMetrics().width("1234.567 s"), + paint.fontMetrics().height()); + extents.push_back(rt); + + int w(paint.fontMetrics().width("1234567890") + 2); + QRect frame(cursorPos.x() - w - 2, + v->height() - paint.fontMetrics().height() - 2, + w, + paint.fontMetrics().height()); + extents.push_back(frame); + return true; } @@ -2507,12 +2525,20 @@ View::OutlinedText); } - /*!!! - long frame = getFrameForX(cursorPos.x()); + long frame = v->getFrameForX(cursorPos.x()); RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); - QString timeLabel = rt.toText(true).c_str(); - ... - */ + QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); + QString frameLabel = QString("%1").arg(frame); + v->drawVisibleText(paint, + cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, + v->height() - 2, + frameLabel, + View::OutlinedText); + v->drawVisibleText(paint, + cursorPos.x() + 2, + v->height() - 2, + rtLabel, + View::OutlinedText); int harmonic = 2;
--- a/layer/SpectrumLayer.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/layer/SpectrumLayer.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -1,4 +1,3 @@ - /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* @@ -294,6 +293,7 @@ SpectrumLayer::getFrequencyForX(float x, float w) const { float freq = 0; + if (!m_sliceableModel) return 0; int sampleRate = m_sliceableModel->getSampleRate(); @@ -321,6 +321,7 @@ SpectrumLayer::getXForFrequency(float freq, float w) const { float x = 0; + if (!m_sliceableModel) return x; int sampleRate = m_sliceableModel->getSampleRate(); @@ -401,14 +402,26 @@ QRect horizontal(0, cursorPos.y(), v->width(), 12); extents.push_back(horizontal); - int hoffset = 1; - if (m_binScale == LogBins) hoffset = 12; + int hoffset = 2; + if (m_binScale == LogBins) hoffset = 13; - QRect label(cursorPos.x(), - v->height() - paint.fontMetrics().height() - hoffset, - paint.fontMetrics().width("123456 Hz") + 2, + int sw = getVerticalScaleWidth(v, paint); + + QRect value(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2, + paint.fontMetrics().width("0.0000001 V") + 2, paint.fontMetrics().height()); - extents.push_back(label); + extents.push_back(value); + + QRect log(sw, cursorPos.y() + 2, + paint.fontMetrics().width("-80.000 dBV") + 2, + paint.fontMetrics().height()); + extents.push_back(log); + + QRect freq(cursorPos.x(), + v->height() - paint.fontMetrics().height() - hoffset, + paint.fontMetrics().width("123456 Hz") + 2, + paint.fontMetrics().height()); + extents.push_back(freq); int w(paint.fontMetrics().width("C#10+50c") + 2); QRect pitch(cursorPos.x() - w, @@ -424,6 +437,8 @@ SpectrumLayer::paintCrosshairs(View *v, QPainter &paint, QPoint cursorPos) const { + if (!m_sliceableModel) return; + paint.save(); ColourMapper mapper(m_colourMap, 0, 1); @@ -437,8 +452,8 @@ float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); - int hoffset = 1; - if (m_binScale == LogBins) hoffset = 12; + int hoffset = 2; + if (m_binScale == LogBins) hoffset = 13; v->drawVisibleText(paint, cursorPos.x() + 2, @@ -455,6 +470,24 @@ View::OutlinedText); } + float value = getValueForY(cursorPos.y(), v); + float thresh = -80.f; + float db = thresh; + if (value > 0.f) db = 10.f * log10f(value); + if (db < thresh) db = thresh; + + v->drawVisibleText(paint, + xorigin + 2, + cursorPos.y() - 2, + QString("%1 V").arg(value), + View::OutlinedText); + + v->drawVisibleText(paint, + xorigin + 2, + cursorPos.y() + 2 + paint.fontMetrics().ascent(), + QString("%1 dBV").arg(db), + View::OutlinedText); + int harmonic = 2; while (harmonic < 100) { @@ -588,7 +621,7 @@ FFTModel *fft = dynamic_cast<FFTModel *> (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); - float thresh = powf(10, -8) / m_gain; // -80dB + float thresh = (powf(10, -6) / m_gain) * (m_windowSize / 2.f); // -60dB adj int xorigin = getVerticalScaleWidth(v, paint) + 1; int w = v->width() - xorigin - 1; @@ -607,27 +640,38 @@ paint.setRenderHint(QPainter::Antialiasing, false); paint.setPen(QColor(160, 160, 160)); //!!! - ColourMapper mapper(m_colourMap, 0, 1); + FFTModel::PeakSet peaks = fft->getPeakFrequencies + (FFTModel::MajorPitchAdaptivePeaks, col); + + ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1); BiasCurve curve; getBiasCurve(curve); size_t cs = curve.size(); + + std::vector<float> values; for (size_t bin = 0; bin < fft->getHeight(); ++bin) { + float value = m_sliceableModel->getValueAt(col, bin); + if (bin < cs) value *= curve[bin]; + values.push_back(value); + } + + for (FFTModel::PeakSet::iterator i = peaks.begin(); + i != peaks.end(); ++i) { + + size_t bin = i->first; - if (!fft->isLocalPeak(col, bin)) continue; +// std::cerr << "bin = " << bin << ", thresh = " << thresh << ", value = " << fft->getMagnitudeAt(col, bin) << std::endl; + if (!fft->isOverThreshold(col, bin, thresh)) continue; - float freq = 0; - bool haveFreq = fft->estimateStableFrequency(col, bin, freq); - if (!haveFreq) continue; - + float freq = i->second; + int x = lrintf(getXForFrequency(freq, w)); - float value = m_sliceableModel->getValueAt(col, bin); - if (bin < cs) value *= curve[bin]; float norm = 0.f; - float y = getYForValue(value, v, norm); // don't need y, need norm + float y = getYForValue(values[bin], v, norm); // don't need y, need norm paint.setPen(mapper.map(norm)); paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);
--- a/view/Pane.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/view/Pane.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -1587,6 +1587,12 @@ if (layer && layer->isLayerEditable()) { if (layer->editOpen(this, e)) relocate = false; } + + } else if (mode == ViewManager::MeasureMode) { + + Layer *layer = getTopLayer(); + if (layer) layer->measureDoubleClick(this, e); + update(); } if (relocate) {
--- a/widgets/LayerTree.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/widgets/LayerTree.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -21,6 +21,7 @@ #include "layer/Layer.h" #include "data/model/Model.h" +#include <QIcon> #include <iostream>
--- a/widgets/PropertyBox.cpp Tue Jul 03 18:56:27 2007 +0000 +++ b/widgets/PropertyBox.cpp Wed Jul 04 15:29:16 2007 +0000 @@ -429,6 +429,9 @@ cb->setEditable(true); } cb->blockSignals(false); + if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) { + cb->setMaxVisibleItems(cb->count()); + } } if (!have) {