Mercurial > hg > svgui
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