changeset 1068:521f7e8b0559 spectrogram-minor-refactor

Introduce ColourScale to handle colour mapping for both spectrogram and colour 3d plot layers
author Chris Cannam
date Thu, 23 Jun 2016 14:42:37 +0100
parents 6eb9e032e708
children 0c4734cd33c1
files layer/Colour3DPlotLayer.h layer/ColourScale.cpp layer/ColourScale.h
diffstat 3 files changed, 237 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.h	Thu Jun 23 10:57:21 2016 +0100
+++ b/layer/Colour3DPlotLayer.h	Thu Jun 23 14:42:37 2016 +0100
@@ -13,8 +13,8 @@
     COPYING included with this distribution for more information.
 */
 
-#ifndef _COLOUR_3D_PLOT_H_
-#define _COLOUR_3D_PLOT_H_
+#ifndef COLOUR_3D_PLOT_LAYER_H
+#define COLOUR_3D_PLOT_LAYER_H
 
 #include "SliceableLayer.h"
 
@@ -30,13 +30,10 @@
  * colour range.  Its source is a DenseThreeDimensionalModel.
  *
  * This was the original implementation for the spectrogram view, but
- * it was replaced with a more efficient implementation that derived
- * the spectrogram itself from a DenseTimeValueModel instead of using
- * a three-dimensional model.  This class is retained in case it
- * becomes useful, but it will probably need some cleaning up if it's
- * ever actually used.
+ * it was replaced for that purpose with a more efficient
+ * implementation that derived the spectrogram itself from a
+ * DenseTimeValueModel instead of using a three-dimensional model.
  */
-
 class Colour3DPlotLayer : public SliceableLayer
 {
     Q_OBJECT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/ColourScale.cpp	Thu Jun 23 14:42:37 2016 +0100
@@ -0,0 +1,136 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2016 Chris Cannam and QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "ColourScale.h"
+
+#include "base/AudioLevel.h"
+#include "base/LogRange.h"
+
+#include <cmath>
+
+int ColourScale::m_maxPixel = 255;
+
+ColourScale::ColourScale(int colourMap,
+			 Scale scale,
+			 double minValue,
+			 double maxValue,
+			 double threshold,
+			 double gain) :
+    m_mapper(colourMap, 1.f, double(m_maxPixel)),
+    m_scale(scale),
+    m_min(minValue),
+    m_max(maxValue),
+    m_threshold(threshold),
+    m_gain(gain)
+{
+    if (minValue >= maxValue) {
+	throw std::logic_error("maxValue must be greater than minValue");
+    }
+
+    m_mappedMin = m_min;
+    m_mappedMax = m_max;
+
+    if (m_scale == LogColourScale) {
+
+	LogRange::mapRange(m_mappedMin, m_mappedMax);
+	
+    } else if (m_scale == PlusMinusOneScale) {
+	
+	m_mappedMin = -1.0;
+	m_mappedMax =  1.0;
+
+    } else if (m_scale == AbsoluteScale) {
+
+	m_mappedMin = fabs(m_mappedMin);
+	m_mappedMax = fabs(m_mappedMax);
+	if (m_mappedMin >= m_mappedMax) {
+	    std::swap(m_mappedMin, m_mappedMax);
+	}
+    }
+
+    if (m_mappedMin >= m_mappedMax) {
+	throw std::logic_error("maxValue must be greater than minValue [after mapping]");
+    }
+}
+
+int
+ColourScale::getPixel(double value)
+{
+    double maxPixF = m_maxPixel;
+
+    if (m_scale == PhaseColourScale) {
+	double half = (maxPixF - 1.f) / 2.f;
+	return 1 + int((value * half) / M_PI + half);
+    }
+    
+    value *= m_gain;
+
+    if (value < m_threshold) return 0;
+
+    double mapped = value;
+
+    if (m_scale == LogColourScale) {
+	mapped = LogRange::map(value);
+    } else if (m_scale == PlusMinusOneScale) {
+	if (mapped < -1.f) mapped = -1.f;
+	if (mapped > 1.f) mapped = 1.f;
+    } else if (m_scale == AbsoluteScale) {
+	if (mapped < 0.f) mapped = -mapped;
+    }
+	
+    if (mapped < m_mappedMin) {
+	mapped = m_mappedMin;
+    }
+    if (mapped > m_mappedMax) {
+	mapped = m_mappedMax;
+    }
+
+    double proportion = (mapped - m_mappedMin) / (m_mappedMax - m_mappedMin);
+
+    int pixel = 0;
+
+    if (m_scale == MeterColourScale) {
+	pixel = AudioLevel::multiplier_to_preview(proportion, m_maxPixel-1) + 1;
+    } else {
+	pixel = int(proportion * maxPixF) + 1;
+    }
+
+    if (pixel > m_maxPixel) pixel = m_maxPixel;
+    if (pixel < 0) pixel = 0;
+    return pixel;
+}
+
+QColor
+ColourScale::getColourForPixel(int pixel, int rotation)
+{
+    if (pixel < 0) {
+	pixel = 0;
+    }
+    if (pixel > m_maxPixel) {
+	pixel = m_maxPixel;
+    }
+    if (pixel == 0) {
+	if (m_mapper.hasLightBackground()) {
+	    return Qt::white;
+	} else {
+	    return Qt::black;
+	}
+    } else {
+	int target = int(pixel) + rotation;
+	while (target < 1) target += m_maxPixel;
+	while (target > m_maxPixel) target -= m_maxPixel;
+	return m_mapper.map(double(target));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/ColourScale.h	Thu Jun 23 14:42:37 2016 +0100
@@ -0,0 +1,96 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2016 Chris Cannam and QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef COLOUR_SCALE_H
+#define COLOUR_SCALE_H
+
+#include "ColourMapper.h"
+
+/**
+ * Map values within a range onto a set of colours, with a given
+ * distribution (linear, log etc) and optional colourmap rotation.
+ */
+class ColourScale
+{
+public:
+    enum Scale {
+	LinearColourScale,
+	MeterColourScale,
+	LogColourScale,
+	PhaseColourScale,
+        PlusMinusOneScale,
+        AbsoluteScale
+    };
+
+    /**
+     * Create a ColourScale with the given parameters:
+     * 
+     * @param colourMap A colour map index as used by ColourMapper
+     * @param scale Distribution for the scale
+     * @param minValue Minimum value in range
+     * @param maxValue Maximum value in range. Must be > minValue
+     * @param threshold Threshold below which every value is mapped to
+     *   background pixel 0
+     * @param gain Gain to apply before clamping and mapping, typically 1
+     *
+     * Note that some parameters may be ignored for some scale
+     * distribution settings. For example, min and max are ignored for
+     * PlusMinusOneScale and PhaseColourScale and threshold and gain
+     * are ignored for PhaseColourScale.
+     */
+    ColourScale(int colourMap,
+		Scale scale,
+		double minValue,
+		double maxValue,
+		double threshold,
+		double gain);
+
+    /**
+     * Return a pixel number (in the range 0-255 inclusive)
+     * corresponding to the given value.  The pixel 0 is used only for
+     * values below the threshold supplied in the constructor. All
+     * other values are mapped onto the range 1-255.
+     */
+    int getPixel(double value);
+
+    /**
+     * Return the colour for the given pixel number (which must be in
+     * the range 0-255). The pixel 0 is always the background
+     * colour. Other pixels are mapped taking into account the given
+     * colourmap rotation (which is also a value in the range 0-255).
+     */
+    QColor getColourForPixel(int pixel, int rotation);
+    
+    /**
+     * Return the colour corresponding to the given value. This is
+     * equivalent to getColourForPixel(getPixel(value), rotation).
+     */
+    QColor getColour(double value, int rotation) {
+	return getColourForPixel(getPixel(value), rotation);
+    }
+
+private:
+    ColourMapper m_mapper;
+    Scale m_scale;
+    double m_min;
+    double m_max;
+    double m_mappedMin;
+    double m_mappedMax;
+    double m_threshold;
+    double m_gain;
+    static int m_maxPixel;
+};
+
+#endif