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);