# HG changeset patch # User Chris Cannam # Date 1486479319 0 # Node ID 4d0ca1ab4cd0a51538ebe96f391f28163074114a # Parent 2cc9e0e5df51f07132584085055a4ba661801684 Some work to make spectrum layers (and slice layers generally) zoomable in the frequency axis. Also fixes a number of view id mixups in SliceLayer which broke offset calculations for the x axis scale. diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/Colour3DPlotLayer.cpp --- a/layer/Colour3DPlotLayer.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/Colour3DPlotLayer.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -640,7 +640,7 @@ min = 0; max = double(m_model->getHeight()); - logarithmic = false; + logarithmic = (m_binScale == BinScale::Log); unit = ""; return true; diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/PianoScale.cpp --- a/layer/PianoScale.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/PianoScale.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -23,6 +23,9 @@ #include "LayerGeometryProvider.h" +#include +using namespace std; + void PianoScale::paintPianoVertical(LayerGeometryProvider *v, QPainter &paint, @@ -83,3 +86,75 @@ } } +void +PianoScale::paintPianoHorizontal(LayerGeometryProvider *v, + const HorizontalScaleProvider *p, + QPainter &paint, + QRect r) +{ + int x0 = r.x(), y0 = r.y(), x1 = r.x() + r.width(), y1 = r.y() + r.height(); + + paint.drawLine(x0, y0, x1, y0); + + int px = x0, ppx = x0; + paint.setBrush(paint.pen().color()); + + for (int i = 0; i < 128; ++i) { + + double f = Pitch::getFrequencyForPitch(i); + int x = int(lrint(p->getXForFrequency(v, f))); + + if (i == 0) { + px = ppx = x; + } + if (i == 1) { + ppx = px - (x - px); + } + + if (x < x0) { + ppx = px; + px = x; + continue; + } + + if (x > x1) { + break; + } + + int n = (i % 12); + + if (n == 1) { + // C# -- fill the C from here + QColor col = Qt::gray; + if (i == 61) { // filling middle C + col = Qt::blue; + col = col.light(150); + } + if (x - ppx > 2) { + paint.fillRect((px + ppx) / 2 + 1, + y0 + 1, + x - (px + ppx) / 2 - 1, + y1 - y0, + col); + } + } + + if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { + // black notes + paint.drawLine(x, y0, x, y1); + int rw = int(lrint(double(x - px) / 4) * 2); + if (rw < 2) rw = 2; + paint.drawRect(x - rw/2, (y0 + y1) / 2, rw, (y1 - y0) / 2); + } else if (n == 0 || n == 5) { + // C, F + if (px < x1) { + paint.drawLine((x + px) / 2, y0, (x + px) / 2, y1); + } + } + + ppx = px; + px = x; + } +} + + diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/PianoScale.h --- a/layer/PianoScale.h Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/PianoScale.h Tue Feb 07 14:55:19 2017 +0000 @@ -26,6 +26,16 @@ public: void paintPianoVertical (LayerGeometryProvider *v, QPainter &paint, QRect rect, double minf, double maxf); + + class HorizontalScaleProvider { + public: + virtual double getFrequencyForX(const LayerGeometryProvider *, double x) const = 0; + virtual double getXForFrequency(const LayerGeometryProvider *, double freq) const = 0; + }; + + void paintPianoHorizontal + (LayerGeometryProvider *v, const HorizontalScaleProvider *p, + QPainter &paint, QRect rect); }; #endif diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/SliceLayer.cpp --- a/layer/SliceLayer.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/SliceLayer.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -40,6 +40,8 @@ m_threshold(0.0), m_initialThreshold(0.0), m_gain(1.0), + m_minbin(0), + m_maxbin(0), m_currentf0(0), m_currentf1(0) { @@ -67,7 +69,11 @@ connectSignals(m_sliceableModel); + m_minbin = 0; + m_maxbin = m_sliceableModel->getHeight(); + emit modelReplaced(); + emit layerParametersChanged(); } void @@ -107,13 +113,10 @@ maxbin = 0; if (!m_sliceableModel) return ""; - int xorigin = m_xorigins[v]; - int w = v->getPaintWidth() - xorigin - 1; - + minbin = int(round(getBinForX(v, p.x()))); + maxbin = int(round(getBinForX(v, p.x() + 1))); + int mh = m_sliceableModel->getHeight(); - minbin = getBinForX(p.x() - xorigin, mh, w); - maxbin = getBinForX(p.x() - xorigin + 1, mh, w); - if (minbin >= mh) minbin = mh - 1; if (maxbin >= mh) maxbin = mh - 1; if (minbin < 0) minbin = 0; @@ -133,12 +136,15 @@ if (includeBinDescription) { + int i0 = minbin - m_minbin; + int i1 = maxbin - m_minbin; + float minvalue = 0.0; - if (minbin < int(m_values.size())) minvalue = m_values[minbin]; + if (in_range_for(m_values, i0)) minvalue = m_values[i0]; float maxvalue = minvalue; - if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; - + if (in_range_for(m_values, i1)) maxvalue = m_values[i1]; + if (minvalue > maxvalue) std::swap(minvalue, maxvalue); QString binstr; @@ -180,10 +186,21 @@ } double -SliceLayer::getXForBin(int bin, int count, double w) const +SliceLayer::getXForBin(const LayerGeometryProvider *v, double bin) const { double x = 0; + bin -= m_minbin; + if (bin < 0) bin = 0; + + double count = m_maxbin - m_minbin; + if (count < 0) count = 0; + + int pw = v->getPaintWidth(); + int origin = m_xorigins[v->getId()]; + int w = pw - origin; + if (w < 1) w = 1; + switch (m_binScale) { case LinearBins: @@ -198,15 +215,27 @@ x = w - (w * log10(count - bin - 1)) / log10(count); break; } - - return x; + + return x + origin; } -int -SliceLayer::getBinForX(double x, int count, double w) const +double +SliceLayer::getBinForX(const LayerGeometryProvider *v, double x) const { - int bin = 0; + double bin = 0; + double count = m_maxbin - m_minbin; + if (count < 0) count = 0; + + int pw = v->getPaintWidth(); + int origin = m_xorigins[v->getId()]; + + int w = pw - origin; + if (w < 1) w = 1; + + x = x - origin; + if (x < 0) x = 0; + switch (m_binScale) { case LinearBins: @@ -222,20 +251,20 @@ break; } - return bin; + return bin + m_minbin; } double -SliceLayer::getYForValue(double value, const LayerGeometryProvider *v, double &norm) const +SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const { norm = 0.0; - if (m_yorigins.find(v) == m_yorigins.end()) return 0; + if (m_yorigins.find(v->getId()) == m_yorigins.end()) return 0; value *= m_gain; - int yorigin = m_yorigins[v]; - int h = m_heights[v]; + int yorigin = m_yorigins[v->getId()]; + int h = m_heights[v->getId()]; double thresh = getThresholdDb(); double y = 0.0; @@ -276,14 +305,14 @@ } double -SliceLayer::getValueForY(double y, const LayerGeometryProvider *v) const +SliceLayer::getValueForY(const LayerGeometryProvider *v, double y) const { double value = 0.0; - if (m_yorigins.find(v) == m_yorigins.end()) return value; + if (m_yorigins.find(v->getId()) == m_yorigins.end()) return value; - int yorigin = m_yorigins[v]; - int h = m_heights[v]; + int yorigin = m_yorigins[v->getId()]; + int h = m_heights[v->getId()]; double thresh = getThresholdDb(); if (h <= 0) return value; @@ -341,20 +370,26 @@ int xorigin = getVerticalScaleWidth(v, true, paint) + 1; int w = v->getPaintWidth() - xorigin - 1; - m_xorigins[v] = xorigin; // for use in getFeatureDescription + m_xorigins[v->getId()] = xorigin; // for use in getFeatureDescription int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; int h = yorigin - paint.fontMetrics().height() - 8; - m_yorigins[v] = yorigin; // for getYForValue etc - m_heights[v] = h; + m_yorigins[v->getId()] = yorigin; // for getYForValue etc + m_heights[v->getId()] = h; if (h <= 0) return; QPainterPath path; int mh = m_sliceableModel->getHeight(); + int bin0 = 0; + if (m_maxbin > m_minbin) { + mh = m_maxbin - m_minbin; + bin0 = m_minbin; + } + int divisor = 0; m_values.clear(); @@ -388,7 +423,7 @@ for (int col = col0; col <= col1; ++col) { for (int bin = 0; bin < mh; ++bin) { - float value = m_sliceableModel->getValueAt(col, bin); + float value = m_sliceableModel->getValueAt(col, bin0 + bin); if (bin < cs) value *= curve[bin]; if (m_samplingMode == SamplePeak) { if (value > m_values[bin]) m_values[bin] = value; @@ -412,18 +447,18 @@ } } - double nx = xorigin; + double nx = getXForBin(v, bin0); ColourMapper mapper(m_colourMap, 0, 1); for (int bin = 0; bin < mh; ++bin) { double x = nx; - nx = xorigin + getXForBin(bin + 1, mh, w); + nx = getXForBin(v, bin + bin0 + 1); double value = m_values[bin]; double norm = 0.0; - double y = getYForValue(value, v, norm); + double y = getYForValue(v, value, norm); if (m_plotStyle == PlotLines) { @@ -461,60 +496,20 @@ paint.drawPath(path); } paint.restore(); -/* - QPoint discard; - - if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() && - v->shouldIlluminateLocalFeatures(this, discard)) { - - int sampleRate = m_sliceableModel->getSampleRate(); - - QString startText = QString("%1 / %2") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f0, sampleRate).toText(true))) - .arg(f0); - - QString endText = QString(" %1 / %2") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f1, sampleRate).toText(true))) - .arg(f1); - - QString durationText = QString("(%1 / %2) ") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f1 - f0 + 1, sampleRate).toText(true))) - .arg(f1 - f0 + 1); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + 5, - startText, PaintAssistant::OutlinedText); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10, - endText, PaintAssistant::OutlinedText); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15, - durationText, PaintAssistant::OutlinedText); - } -*/ } int SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const { + int width; if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { - return std::max(paint.fontMetrics().width("0.0") + 13, - paint.fontMetrics().width("x10-10")); + width = std::max(paint.fontMetrics().width("0.0") + 13, + paint.fontMetrics().width("x10-10")); } else { - return std::max(paint.fontMetrics().width(tr("0dB")), - paint.fontMetrics().width(tr("-Inf"))) + 13; + width = std::max(paint.fontMetrics().width(tr("0dB")), + paint.fontMetrics().width(tr("-Inf"))) + 13; } + return width; } void @@ -630,7 +625,7 @@ *max = 50; *deflt = 0; - cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; +// cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; val = int(lrint(log10(m_gain) * 20.0)); if (val < *min) val = *min; @@ -897,7 +892,7 @@ "binScale=\"%5\" " "gain=\"%6\" " "threshold=\"%7\" " - "normalize=\"%8\"") + "normalize=\"%8\" %9") .arg(m_colourMap) .arg(m_energyScale) .arg(m_samplingMode) @@ -905,7 +900,11 @@ .arg(m_binScale) .arg(m_gain) .arg(m_threshold) - .arg(m_normalize ? "true" : "false"); + .arg(m_normalize ? "true" : "false") + .arg(QString("minbin=\"%1\" " + "maxbin=\"%2\"") + .arg(m_minbin) + .arg(m_maxbin)); SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s); } @@ -944,11 +943,105 @@ bool normalize = (attributes.value("normalize").trimmed() == "true"); setNormalize(normalize); + + bool alsoOk = false; + + float min = attributes.value("minbin").toFloat(&ok); + float max = attributes.value("maxbin").toFloat(&alsoOk); + if (ok && alsoOk) setDisplayExtents(min, max); } bool -SliceLayer::getValueExtents(double &, double &, bool &, QString &) const +SliceLayer::getValueExtents(double &min, double &max, bool &logarithmic, + QString &unit) const { - return false; + if (!m_sliceableModel) return false; + + min = 0; + max = double(m_sliceableModel->getHeight()); + + logarithmic = (m_binScale == BinScale::LogBins); + unit = ""; + + return true; } +bool +SliceLayer::getDisplayExtents(double &min, double &max) const +{ + if (!m_sliceableModel) return false; + + double hmax = double(m_sliceableModel->getHeight()); + + min = m_minbin; + max = m_maxbin; + if (max <= min) { + min = 0; + max = hmax; + } + if (min < 0) min = 0; + if (max > hmax) max = hmax; + + return true; +} + +bool +SliceLayer::setDisplayExtents(double min, double max) +{ + if (!m_sliceableModel) return false; + + m_minbin = int(lrint(min)); + m_maxbin = int(lrint(max)); + + emit layerParametersChanged(); + return true; +} + +int +SliceLayer::getVerticalZoomSteps(int &defaultStep) const +{ + if (!m_sliceableModel) return 0; + + defaultStep = 0; + int h = m_sliceableModel->getHeight(); + return h; +} + +int +SliceLayer::getCurrentVerticalZoomStep() const +{ + if (!m_sliceableModel) return 0; + + double min, max; + getDisplayExtents(min, max); + return m_sliceableModel->getHeight() - int(lrint(max - min)); +} + +void +SliceLayer::setVerticalZoomStep(int step) +{ + if (!m_sliceableModel) return; + +// SVDEBUG << "SliceLayer::setVerticalZoomStep(" < m_scalePoints; - mutable std::map m_xorigins; - mutable std::map m_yorigins; - mutable std::map m_heights; + mutable std::map m_xorigins; // LayerGeometryProvider id -> x + mutable std::map m_yorigins; // LayerGeometryProvider id -> y + mutable std::map m_heights; // LayerGeometryProvider id -> h mutable sv_frame_t m_currentf0; mutable sv_frame_t m_currentf1; mutable std::vector m_values; diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/SpectrumLayer.cpp --- a/layer/SpectrumLayer.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/SpectrumLayer.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -297,98 +297,29 @@ } } -bool -SpectrumLayer::getValueExtents(double &, double &, bool &, QString &) const +double +SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const { - return false; + if (!m_sliceableModel) return 0; + double bin = getBinForX(v, x); + return (m_sliceableModel->getSampleRate() * bin) / + (m_sliceableModel->getHeight() * 2); } double -SpectrumLayer::getXForBin(int bin, int totalBins, double w) const +SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const { - if (!m_sliceableModel) return SliceLayer::getXForBin(bin, totalBins, w); - - sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); - double binfreq = (sampleRate * bin) / (totalBins * 2); - - return getXForFrequency(binfreq, w); -} - -int -SpectrumLayer::getBinForX(double x, int totalBins, double w) const -{ - if (!m_sliceableModel) return SliceLayer::getBinForX(x, totalBins, w); - - sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); - double binfreq = getFrequencyForX(x, w); - - return int((binfreq * totalBins * 2) / sampleRate); -} - -double -SpectrumLayer::getFrequencyForX(double x, double w) const -{ - double freq = 0; if (!m_sliceableModel) return 0; - - sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); - - double maxfreq = double(sampleRate) / 2; - - switch (m_binScale) { - - case LinearBins: - freq = ((x * maxfreq) / w); - break; - - case LogBins: - freq = pow(10.0, (x * log10(maxfreq)) / w); - break; - - case InvertedLogBins: - freq = maxfreq - pow(10.0, ((w - x) * log10(maxfreq)) / w); - break; - } - - return freq; -} - -double -SpectrumLayer::getXForFrequency(double freq, double w) const -{ - double x = 0; - if (!m_sliceableModel) return x; - - sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); - - double maxfreq = double(sampleRate) / 2; - - switch (m_binScale) { - - case LinearBins: - x = (freq * w) / maxfreq; - break; - - case LogBins: - x = (log10(freq) * w) / log10(maxfreq); - break; - - case InvertedLogBins: - if (maxfreq == freq) x = w; - else x = w - (log10(maxfreq - freq) * w) / log10(maxfreq); - break; - } - - return x; + double bin = (freq * m_sliceableModel->getHeight() * 2) / + m_sliceableModel->getSampleRate(); + return getXForBin(v, bin); } bool SpectrumLayer::getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const { - if (m_xorigins.find(v) == m_xorigins.end()) return false; - int xorigin = m_xorigins.find(v)->second; - value = getFrequencyForX(x - xorigin, v->getPaintWidth() - xorigin - 1); + value = getFrequencyForX(v, x); unit = "Hz"; return true; } @@ -397,7 +328,7 @@ SpectrumLayer::getYScaleValue(const LayerGeometryProvider *v, int y, double &value, QString &unit) const { - value = getValueForY(y, v); + value = getValueForY(v, y); if (m_energyScale == dBScale || m_energyScale == MeterScale) { @@ -483,33 +414,34 @@ ColourMapper mapper(m_colourMap, 0, 1); paint.setPen(mapper.getContrastingColour()); - int xorigin = m_xorigins[v]; + int xorigin = m_xorigins[v->getId()]; int w = v->getPaintWidth() - xorigin - 1; paint.drawLine(xorigin, cursorPos.y(), v->getPaintWidth(), cursorPos.y()); paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->getPaintHeight()); - double fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); + double fundamental = getFrequencyForX(v, cursorPos.x()); int hoffset = 2; if (m_binScale == LogBins) hoffset = 13; PaintAssistant::drawVisibleText(v, paint, - cursorPos.x() + 2, - v->getPaintHeight() - 2 - hoffset, - QString("%1 Hz").arg(fundamental), - PaintAssistant::OutlinedText); + cursorPos.x() + 2, + v->getPaintHeight() - 2 - hoffset, + QString("%1 Hz").arg(fundamental), + PaintAssistant::OutlinedText); if (Pitch::isFrequencyInMidiRange(fundamental)) { QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental); PaintAssistant::drawVisibleText(v, paint, - cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2, - v->getPaintHeight() - 2 - hoffset, - pitchLabel, - PaintAssistant::OutlinedText); + cursorPos.x() - + paint.fontMetrics().width(pitchLabel) - 2, + v->getPaintHeight() - 2 - hoffset, + pitchLabel, + PaintAssistant::OutlinedText); } - double value = getValueForY(cursorPos.y(), v); + double value = getValueForY(v, cursorPos.y()); double thresh = m_threshold; double db = thresh; if (value > 0.0) db = 10.0 * log10(value); @@ -531,7 +463,7 @@ while (harmonic < 100) { - int hx = int(lrint(getXForFrequency(fundamental * harmonic, w))); + int hx = int(lrint(getXForFrequency(v, fundamental * harmonic))); hx += xorigin; if (hx < xorigin || hx > v->getPaintWidth()) break; @@ -568,12 +500,15 @@ if (genericDesc == "") return ""; - double minvalue = 0.f; - if (minbin < int(m_values.size())) minvalue = m_values[minbin]; + int i0 = minbin - m_minbin; + int i1 = maxbin - m_minbin; + + float minvalue = 0.0; + if (in_range_for(m_values, i0)) minvalue = m_values[i0]; - double maxvalue = minvalue; - if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; - + float maxvalue = minvalue; + if (in_range_for(m_values, i1)) maxvalue = m_values[i1]; + if (minvalue > maxvalue) std::swap(minvalue, maxvalue); QString binstr; @@ -718,10 +653,10 @@ double freq = i->second; - int x = int(lrint(getXForFrequency(freq, w))); + int x = int(lrint(getXForFrequency(v, freq))); double norm = 0.f; - (void)getYForValue(values[bin], v, norm); // don't need return value, need norm + (void)getYForValue(v, values[bin], norm); // don't need return value, need norm paint.setPen(mapper.map(norm)); paint.drawLine(xorigin + x, 0, xorigin + x, v->getPaintHeight() - pkh - 1); @@ -733,87 +668,18 @@ SliceLayer::paint(v, paint, rect); //!!! All of this stuff relating to depicting frequencies - //(keyboard, crosshairs etc) should be applicable to any slice - //layer whose model has a vertical scale unit of Hz. However, the - //dense 3d model at the moment doesn't record its vertical scale - //unit -- we need to fix that and hoist this code as appropriate. - //Same really goes for any code in SpectrogramLayer that could be - //relevant to Colour3DPlotLayer with unit Hz, but that's a bigger - //proposition. + // (keyboard, crosshairs etc) should be applicable to any slice + // layer whose model has a vertical scale unit of Hz. However, + // the dense 3d model at the moment doesn't record its vertical + // scale unit -- we need to fix that and hoist this code as + // appropriate. Same really goes for any code in SpectrogramLayer + // that could be relevant to Colour3DPlotLayer with unit Hz, but + // that's a bigger proposition. -// if (m_binScale == LogBins) { + int h = v->getPaintHeight(); -// int pkh = 10; - int h = v->getPaintHeight(); - - // piano keyboard - - //!!! todo: move to PianoScale::paintPianoHorizontal - - paint.drawLine(xorigin, h - pkh - 1, w + xorigin, h - pkh - 1); - - int px = xorigin, ppx = xorigin; - paint.setBrush(paint.pen().color()); - - for (int i = 0; i < 128; ++i) { - - double f = Pitch::getFrequencyForPitch(i); - int x = int(lrint(getXForFrequency(f, w))); - - x += xorigin; - - if (i == 0) { - px = ppx = x; - } - if (i == 1) { - ppx = px - (x - px); - } - - if (x < xorigin) { - ppx = px; - px = x; - continue; - } - - if (x > w) { - break; - } - - int n = (i % 12); - - if (n == 1) { - // C# -- fill the C from here - QColor col = Qt::gray; - if (i == 61) { // filling middle C - col = Qt::blue; - col = col.light(150); - } - if (x - ppx > 2) { - paint.fillRect((px + ppx) / 2 + 1, - h - pkh, - x - (px + ppx) / 2 - 1, - pkh, - col); - } - } - - if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { - // black notes - paint.drawLine(x, h - pkh, x, h); - int rw = int(lrint(double(x - px) / 4) * 2); - if (rw < 2) rw = 2; - paint.drawRect(x - rw/2, h - pkh, rw, pkh/2); - } else if (n == 0 || n == 5) { - // C, F - if (px < w) { - paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h); - } - } - - ppx = px; - px = x; - } -// } + PianoScale().paintPianoHorizontal + (v, this, paint, QRect(xorigin, h - pkh - 1, w + xorigin, pkh)); paint.restore(); } diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 layer/SpectrumLayer.h --- a/layer/SpectrumLayer.h Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/SpectrumLayer.h Tue Feb 07 14:55:19 2017 +0000 @@ -14,8 +14,8 @@ COPYING included with this distribution for more information. */ -#ifndef _SPECTRUM_LAYER_H_ -#define _SPECTRUM_LAYER_H_ +#ifndef SV_SPECTRUM_LAYER_H +#define SV_SPECTRUM_LAYER_H #include "SliceLayer.h" @@ -23,12 +23,15 @@ #include "data/model/DenseTimeValueModel.h" +#include "PianoScale.h" + #include #include class FFTModel; -class SpectrumLayer : public SliceLayer +class SpectrumLayer : public SliceLayer, + public PianoScale::HorizontalScaleProvider { Q_OBJECT @@ -64,9 +67,6 @@ virtual void setProperty(const PropertyName &, int value); virtual void setProperties(const QXmlAttributes &); - virtual bool getValueExtents(double &min, double &max, - bool &logarithmic, QString &unit) const; - virtual bool getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const; @@ -96,15 +96,15 @@ virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; + virtual double getFrequencyForX(const LayerGeometryProvider *, + double x) const override; + virtual double getXForFrequency(const LayerGeometryProvider *, + double freq) const override; + protected slots: void preferenceChanged(PropertyContainer::PropertyName name); protected: - // make this SliceLayer method unavailable to the general public -// virtual void setModel(DenseThreeDimensionalModel *model) { -// SliceLayer::setModel(model); -// } - DenseTimeValueModel *m_originModel; int m_channel; bool m_channelSet; @@ -121,12 +121,6 @@ virtual void getBiasCurve(BiasCurve &) const; BiasCurve m_biasCurve; - virtual double getXForBin(int bin, int totalBins, double w) const; - virtual int getBinForX(double x, int totalBins, double w) const; - - double getFrequencyForX(double x, double w) const; - double getXForFrequency(double freq, double w) const; - int getWindowIncrement() const { if (m_windowHopLevel == 0) return m_windowSize; else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4; diff -r 2cc9e0e5df51 -r 4d0ca1ab4cd0 widgets/Panner.cpp --- a/widgets/Panner.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/widgets/Panner.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -20,6 +20,8 @@ #include #include +#include "WidgetScale.h" + #include #include @@ -156,9 +158,13 @@ QColor bg(palette().background().color()); bg.setAlpha(m_backgroundAlpha); - paint.setPen(palette().dark().color()); + int penWidth = WidgetScale::scalePixelSize(1); + if (penWidth < 1) penWidth = 1; + paint.setPen(QPen(palette().dark().color(), penWidth)); + paint.setBrush(bg); - paint.drawRect(0, 0, width()-1, height()-1); + paint.drawRect(penWidth/2, penWidth/2, + width()-penWidth/2-1, height()-penWidth/2-1); QColor hl(m_thumbColour); hl.setAlpha(m_thumbAlpha);