Mercurial > hg > svgui
changeset 1137:4e7ed3252d80 spectrogram-minor-refactor
Re-implement dB^2 (log-power) spectrogram setting
author | Chris Cannam |
---|---|
date | Thu, 04 Aug 2016 11:26:11 +0100 |
parents | 9ff838a64461 |
children | 998e31e92dbe |
files | layer/Colour3DPlotLayer.cpp layer/ColourScale.cpp layer/ColourScale.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
diffstat | 5 files changed, 79 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp Wed Aug 03 16:16:23 2016 +0100 +++ b/layer/Colour3DPlotLayer.cpp Thu Aug 04 11:26:11 2016 +0100 @@ -1036,7 +1036,7 @@ ColourScale::Parameters cparams; cparams.colourMap = m_colourMap; - cparams.scale = m_colourScale; + cparams.scaleType = m_colourScale; cparams.gain = m_gain; if (m_normalization == ColumnNormalization::None) {
--- a/layer/ColourScale.cpp Wed Aug 03 16:16:23 2016 +0100 +++ b/layer/ColourScale.cpp Thu Aug 04 11:26:11 2016 +0100 @@ -42,16 +42,16 @@ m_mappedMin = m_params.threshold; } - if (m_params.scale == ColourScaleType::Log) { + if (m_params.scaleType == ColourScaleType::Log) { LogRange::mapRange(m_mappedMin, m_mappedMax); - } else if (m_params.scale == ColourScaleType::PlusMinusOne) { + } else if (m_params.scaleType == ColourScaleType::PlusMinusOne) { m_mappedMin = -1.0; m_mappedMax = 1.0; - } else if (m_params.scale == ColourScaleType::Absolute) { + } else if (m_params.scaleType == ColourScaleType::Absolute) { m_mappedMin = fabs(m_mappedMin); m_mappedMax = fabs(m_mappedMax); @@ -64,7 +64,7 @@ cerr << "ERROR: ColourScale::ColourScale: minValue = " << m_params.minValue << ", maxValue = " << m_params.maxValue << ", threshold = " << m_params.threshold - << ", scale = " << int(m_params.scale) + << ", scale = " << int(m_params.scaleType) << " resulting in mapped minValue = " << m_mappedMin << ", mapped maxValue = " << m_mappedMax << endl; throw std::logic_error("maxValue must be greater than minValue [after mapping]"); @@ -78,7 +78,7 @@ ColourScaleType ColourScale::getScale() const { - return m_params.scale; + return m_params.scaleType; } int @@ -86,26 +86,30 @@ { double maxPixF = m_maxPixel; - if (m_params.scale == ColourScaleType::Phase) { + if (m_params.scaleType == ColourScaleType::Phase) { double half = (maxPixF - 1.f) / 2.f; return 1 + int((value * half) / M_PI + half); } value *= m_params.gain; +// value = pow(value, m_params.multiple); + if (value < m_params.threshold) return 0; double mapped = value; - if (m_params.scale == ColourScaleType::Log) { + if (m_params.scaleType == ColourScaleType::Log) { mapped = LogRange::map(value); - } else if (m_params.scale == ColourScaleType::PlusMinusOne) { + } else if (m_params.scaleType == ColourScaleType::PlusMinusOne) { if (mapped < -1.f) mapped = -1.f; if (mapped > 1.f) mapped = 1.f; - } else if (m_params.scale == ColourScaleType::Absolute) { + } else if (m_params.scaleType == ColourScaleType::Absolute) { if (mapped < 0.f) mapped = -mapped; } - + + mapped *= m_params.multiple; + if (mapped < m_mappedMin) { mapped = m_mappedMin; } @@ -117,7 +121,7 @@ int pixel = 0; - if (m_params.scale == ColourScaleType::Meter) { + if (m_params.scaleType == ColourScaleType::Meter) { pixel = AudioLevel::multiplier_to_preview(proportion, m_maxPixel-1) + 1; } else { pixel = int(proportion * maxPixF) + 1;
--- a/layer/ColourScale.h Wed Aug 03 16:16:23 2016 +0100 +++ b/layer/ColourScale.h Thu Aug 04 11:26:11 2016 +0100 @@ -35,15 +35,15 @@ { public: struct Parameters { - Parameters() : colourMap(0), scale(ColourScaleType::Linear), + Parameters() : colourMap(0), scaleType(ColourScaleType::Linear), minValue(0.0), maxValue(1.0), - threshold(0.0), gain(1.0) { } + threshold(0.0), gain(1.0), multiple(1.0) { } /** A colour map index as used by ColourMapper */ int colourMap; /** Distribution for the scale */ - ColourScaleType scale; + ColourScaleType scaleType; /** Minimum value in source range */ double minValue; @@ -55,8 +55,15 @@ pixel 0 */ double threshold; - /** Gain to apply before clamping and mapping */ + /** Gain to apply before thresholding, mapping, and clamping */ double gain; + + /** Multiple to apply after thresholding and mapping. In most + * cases the gain parameter is the one you want instead of + * this, but this can be used for example with Log scale to + * produce the log of some power of the original value, + * e.g. multiple = 2 gives log(x^2). */ + double multiple; }; /**
--- a/layer/SpectrogramLayer.cpp Wed Aug 03 16:16:23 2016 +0100 +++ b/layer/SpectrogramLayer.cpp Thu Aug 04 11:26:11 2016 +0100 @@ -73,6 +73,7 @@ m_maxFrequency(8000), m_initialMaxFrequency(8000), m_colourScale(ColourScaleType::Log), + m_colourScaleMultiple(1.0), m_colourMap(0), m_binScale(BinScale::Linear), m_binDisplay(BinDisplay::AllBins), @@ -135,28 +136,27 @@ invalidateFFTModel(); } -ColourScaleType +pair<ColourScaleType, double> SpectrogramLayer::convertToColourScale(int value) { switch (value) { - case 0: return ColourScaleType::Linear; - case 1: return ColourScaleType::Meter; - case 2: return ColourScaleType::Log; //!!! db^2 - case 3: return ColourScaleType::Log; - case 4: return ColourScaleType::Phase; - default: return ColourScaleType::Linear; + case 0: return { ColourScaleType::Linear, 1.0 }; + case 1: return { ColourScaleType::Meter, 1.0 }; + case 2: return { ColourScaleType::Log, 2.0 }; // dB^2 (i.e. log of power) + case 3: return { ColourScaleType::Log, 1.0 }; // dB (of magnitude) + case 4: return { ColourScaleType::Phase, 1.0 }; + default: return { ColourScaleType::Linear, 1.0 }; } } int -SpectrogramLayer::convertFromColourScale(ColourScaleType scale) +SpectrogramLayer::convertFromColourScale(ColourScaleType scale, double multiple) { switch (scale) { case ColourScaleType::Linear: return 0; case ColourScaleType::Meter: return 1; - case ColourScaleType::Log: return 3; //!!! + db^2 + case ColourScaleType::Log: return (multiple > 1.5 ? 2 : 3); case ColourScaleType::Phase: return 4; - case ColourScaleType::PlusMinusOne: case ColourScaleType::Absolute: default: return 0; @@ -330,7 +330,7 @@ *max = 4; *deflt = 2; - val = convertFromColourScale(m_colourScale); + val = convertFromColourScale(m_colourScale, m_colourScaleMultiple); } else if (name == "Colour") { @@ -590,11 +590,15 @@ m_lastEmittedZoomStep = vs; } } else if (name == "Colour Scale") { + setColourScaleMultiple(1.0); switch (value) { default: case 0: setColourScale(ColourScaleType::Linear); break; case 1: setColourScale(ColourScaleType::Meter); break; - case 2: setColourScale(ColourScaleType::Log); break; //!!! dB^2 + case 2: + setColourScale(ColourScaleType::Log); + setColourScaleMultiple(2.0); + break; case 3: setColourScale(ColourScaleType::Log); break; case 4: setColourScale(ColourScaleType::Phase); break; } @@ -878,6 +882,24 @@ } void +SpectrogramLayer::setColourScaleMultiple(double multiple) +{ + if (m_colourScaleMultiple == multiple) return; + + invalidateRenderers(); + + m_colourScaleMultiple = multiple; + + emit layerParametersChanged(); +} + +double +SpectrogramLayer::getColourScaleMultiple() const +{ + return m_colourScaleMultiple; +} + +void SpectrogramLayer::setColourMap(int map) { if (m_colourMap == map) return; @@ -1408,7 +1430,8 @@ ColourScale::Parameters cparams; cparams.colourMap = m_colourMap; - cparams.scale = m_colourScale; + cparams.scaleType = m_colourScale; + cparams.multiple = m_colourScaleMultiple; if (m_colourScale != ColourScaleType::Phase) { cparams.gain = m_gain; @@ -1423,7 +1446,6 @@ maxValue = m_viewMags[viewId].getMax(); } else if (m_colourScale == ColourScaleType::Linear && m_normalization == ColumnNormalization::None) { - //!!! This should not be necessary -- what is the actual range maxValue = 0.1f; } @@ -2384,7 +2406,7 @@ "binDisplay=\"%7\" ") .arg(m_minFrequency) .arg(m_maxFrequency) - .arg(convertFromColourScale(m_colourScale)) + .arg(convertFromColourScale(m_colourScale, m_colourScaleMultiple)) .arg(m_colourMap) .arg(m_colourRotation) .arg(int(m_binScale)) @@ -2459,9 +2481,12 @@ setMaxFrequency(maxFrequency); } - ColourScaleType colourScale = convertToColourScale + auto colourScale = convertToColourScale (attributes.value("colourScale").toInt(&ok)); - if (ok) setColourScale(colourScale); + if (ok) { + setColourScale(colourScale.first); + setColourScaleMultiple(colourScale.second); + } int colourMap = attributes.value("colourScheme").toInt(&ok); if (ok) setColourMap(colourMap);
--- a/layer/SpectrogramLayer.h Wed Aug 03 16:16:23 2016 +0100 +++ b/layer/SpectrogramLayer.h Thu Aug 04 11:26:11 2016 +0100 @@ -145,6 +145,13 @@ ColourScaleType getColourScale() const; /** + * Specify multiple factor for colour scale. This is 2.0 for + * log-power spectrogram and 1.0 otherwise. + */ + void setColourScaleMultiple(double); + double getColourScaleMultiple() const; + + /** * Specify the scale for the y axis. */ void setBinScale(BinScale); @@ -249,6 +256,7 @@ int m_maxFrequency; int m_initialMaxFrequency; ColourScaleType m_colourScale; + double m_colourScaleMultiple; int m_colourMap; QColor m_crosshairColour; BinScale m_binScale; @@ -260,8 +268,8 @@ mutable bool m_haveDetailedScale; - static ColourScaleType convertToColourScale(int value); - static int convertFromColourScale(ColourScaleType); + static std::pair<ColourScaleType, double> convertToColourScale(int value); + static int convertFromColourScale(ColourScaleType type, double multiple); static std::pair<ColumnNormalization, bool> convertToColumnNorm(int value); static int convertFromColumnNorm(ColumnNormalization norm, bool visible);