# HG changeset patch # User Chris Cannam # Date 1170245627 0 # Node ID 22c99c8aa1e01baa776d603c3210f5123668ba02 # Parent 4a3bdde1ef131b7f1ca8b738e792a3516fc8157f * Add separate colour mapping unit; use it in spectrogram (colour 3d plot to follow) * Add another colour scheme resembling that of a noted commercial application diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 layer/ColourMapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/ColourMapper.cpp Wed Jan 31 12:13:47 2007 +0000 @@ -0,0 +1,176 @@ +/* -*- 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-2007 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 "ColourMapper.h" + +ColourMapper::ColourMapper(int map, float min, float max) : + QObject(), + m_map(map), + m_min(min), + m_max(max) +{ +} + +ColourMapper::~ColourMapper() +{ +} + +int +ColourMapper::getColourMapCount() +{ + return 8; +} + +QString +ColourMapper::getColourMapName(int n) +{ + if (n >= 8) return tr(""); + StandardMap map = (StandardMap)n; + + switch (map) { + case DefaultColours: return tr("Default"); + case WhiteOnBlack: return tr("White on Black"); + case BlackOnWhite: return tr("Black on White"); + case RedOnBlue: return tr("Red on Blue"); + case YellowOnBlack: return tr("Yellow on Black"); + case BlueOnBlack: return tr("Blue on Black"); + case Sunset: return tr("Sunset"); + case FruitSalad: return tr("Fruit Salad"); + } + + return tr(""); +} + +QColor +ColourMapper::map(float value) const +{ + float norm = (value - m_min) / (m_max - m_min); + if (norm < 0.f) norm = 0.f; + if (norm > 1.f) norm = 1.f; + + float h = 0.f, s = 0.f, v = 0.f, r = 0.f, g = 0.f, b = 0.f; + bool hsv = true; + + float red = 0.f, green = 0.3333f, blue = 0.6666f, pieslice = 0.3333f; + + if (m_map >= 8) return Qt::black; + StandardMap map = (StandardMap)m_map; + + switch (map) { + + case DefaultColours: + h = blue - norm * 2.f * pieslice; + s = 0.5f + norm/2.f; + v = norm; + break; + + case WhiteOnBlack: + r = g = b = norm; + hsv = false; + break; + + case BlackOnWhite: + r = g = b = 1.f - norm; + hsv = false; + break; + + case RedOnBlue: + h = blue - pieslice/4.f + norm * (pieslice + pieslice/4.f); + s = 1.f; + v = norm; + break; + + case YellowOnBlack: + h = 0.15f; + s = 1.f; + v = norm; + break; + + case BlueOnBlack: + h = blue / 1.f; + s = 1.f; + v = norm * 2.f; + if (v > 1) { + v = 1.f; + s = 1.f - (sqrtf(norm) - 0.707f) * 3.414f; + } + break; + + case Sunset: + r = (norm - 0.24f) * 2.38f; + if (r > 1.f) r = 1.f; + if (r < 0.f) r = 0.f; + g = (norm - 0.64f) * 2.777f; + if (g > 1.f) g = 1.f; + if (g < 0.f) g = 0.f; + b = (3.6f * norm); + if (norm > 0.277f) b = 2.f - b; + if (b > 1.f) b = 1.f; + if (b < 0.f) b = 0.f; + hsv = false; + break; + + case FruitSalad: + h = blue + (pieslice/2.f) - norm; + if (h < 0.f) h += 1.f; + s = 1.f; + v = 1.f; + break; + } + + if (hsv) { + return QColor::fromHsvF(h, s, v); + } else { + return QColor::fromRgbF(r, g, b); + } +} + +QColor +ColourMapper::getContrastingColour() const +{ + if (m_map >= 8) return Qt::white; + StandardMap map = (StandardMap)m_map; + + switch (map) { + + case DefaultColours: + return QColor(255, 150, 50); + + case WhiteOnBlack: + return Qt::red; + + case BlackOnWhite: + return Qt::darkGreen; + + case RedOnBlue: + return Qt::green; + + case YellowOnBlack: + return QColor::fromHsv(240, 255, 255); + + case BlueOnBlack: + return Qt::red; + + case Sunset: + return Qt::white; + + case FruitSalad: + return Qt::white; + } + + return Qt::white; +} + + diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 layer/ColourMapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/ColourMapper.h Wed Jan 31 12:13:47 2007 +0000 @@ -0,0 +1,62 @@ +/* -*- 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-2007 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_MAPPER_H_ +#define _COLOUR_MAPPER_H_ + +#include +#include +#include + +/** + * A class for mapping intensity values onto various colour maps. + */ + +class ColourMapper : public QObject +{ +public: + ColourMapper(int map, float minValue, float maxValue); + virtual ~ColourMapper(); + + enum StandardMap { + DefaultColours, + Sunset, + WhiteOnBlack, + BlackOnWhite, + RedOnBlue, + YellowOnBlack, + BlueOnBlack, + FruitSalad + }; + + int getMap() const { return m_map; } + float getMinValue() const { return m_min; } + float getMaxValue() const { return m_max; } + + static int getColourMapCount(); + static QString getColourMapName(int n); + + QColor map(float value) const; + + QColor getContrastingColour() const; // for cursors etc + +protected: + int m_map; + float m_min; + float m_max; +}; + +#endif + diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 layer/SpectrogramLayer.cpp --- a/layer/SpectrogramLayer.cpp Mon Jan 29 18:11:20 2007 +0000 +++ b/layer/SpectrogramLayer.cpp Wed Jan 31 12:13:47 2007 +0000 @@ -22,6 +22,7 @@ #include "base/Pitch.h" #include "base/Preferences.h" #include "base/RangeMapper.h" +#include "ColourMapper.h" #include #include @@ -53,7 +54,7 @@ m_maxFrequency(8000), m_initialMaxFrequency(8000), m_colourScale(dBColourScale), - m_colourScheme(DefaultColours), + m_colourScheme(0), m_frequencyScale(LinearFrequencyScale), m_binDisplay(AllBins), m_normalizeColumns(false), @@ -248,9 +249,9 @@ } else if (name == "Colour") { *min = 0; - *max = 6; - - deft = (int)m_colourScheme; + *max = ColourMapper::getColourMapCount() - 1; + + deft = m_colourScheme; } else if (name == "Window Size") { @@ -343,16 +344,7 @@ int value) const { if (name == "Colour") { - switch (value) { - default: - case 0: return tr("Default"); - case 1: return tr("White on Black"); - case 2: return tr("Black on White"); - case 3: return tr("Red on Blue"); - case 4: return tr("Yellow on Black"); - case 5: return tr("Blue on Black"); - case 6: return tr("Fruit Salad"); - } + return ColourMapper::getColourMapName(value); } if (name == "Colour Scale") { switch (value) { @@ -453,16 +445,7 @@ } else if (name == "Colour Rotation") { setColourRotation(value); } else if (name == "Colour") { - switch (value) { - default: - case 0: setColourScheme(DefaultColours); break; - case 1: setColourScheme(WhiteOnBlack); break; - case 2: setColourScheme(BlackOnWhite); break; - case 3: setColourScheme(RedOnBlue); break; - case 4: setColourScheme(YellowOnBlack); break; - case 5: setColourScheme(BlueOnBlack); break; - case 6: setColourScheme(Rainbow); break; - } + setColourScheme(value); } else if (name == "Window Size") { setWindowSize(32 << value); } else if (name == "Window Increment") { @@ -798,7 +781,7 @@ } void -SpectrogramLayer::setColourScheme(ColourScheme scheme) +SpectrogramLayer::setColourScheme(int scheme) { if (m_colourScheme == scheme) return; @@ -810,7 +793,7 @@ emit layerParametersChanged(); } -SpectrogramLayer::ColourScheme +int SpectrogramLayer::getColourScheme() const { return m_colourScheme; @@ -1013,72 +996,21 @@ { int formerRotation = m_colourRotation; - if (m_colourScheme == BlackOnWhite) { + if (m_colourScheme == (int)ColourMapper::BlackOnWhite) { m_colourMap.setColour(NO_VALUE, Qt::white); } else { m_colourMap.setColour(NO_VALUE, Qt::black); } + ColourMapper mapper(m_colourScheme, 1.f, 256.f); + for (int pixel = 1; pixel < 256; ++pixel) { - QColor colour; - int hue, px; - - switch (m_colourScheme) { - - default: - case DefaultColours: - hue = 256 - pixel; - colour = QColor::fromHsv(hue, pixel/2 + 128, pixel); - m_crosshairColour = QColor(255, 150, 50); -// m_crosshairColour = QColor::fromHsv(240, 160, 255); - break; - - case WhiteOnBlack: - colour = QColor(pixel, pixel, pixel); - m_crosshairColour = Qt::red; - break; - - case BlackOnWhite: - colour = QColor(256-pixel, 256-pixel, 256-pixel); - m_crosshairColour = Qt::darkGreen; - break; - - case RedOnBlue: - colour = QColor(pixel > 128 ? (pixel - 128) * 2 : 0, 0, - pixel < 128 ? pixel : (256 - pixel)); - m_crosshairColour = Qt::green; - break; - - case YellowOnBlack: - px = 256 - pixel; - colour = QColor(px < 64 ? 255 - px/2 : - px < 128 ? 224 - (px - 64) : - px < 192 ? 160 - (px - 128) * 3 / 2 : - 256 - px, - pixel, - pixel / 4); - m_crosshairColour = QColor::fromHsv(240, 255, 255); - break; - - case BlueOnBlack: - colour = QColor::fromHsv - (240, pixel > 226 ? 256 - (pixel - 226) * 8 : 255, - (pixel * pixel) / 255); - m_crosshairColour = Qt::red; - break; - - case Rainbow: - hue = 250 - pixel; - if (hue < 0) hue += 256; - colour = QColor::fromHsv(pixel, 255, 255); - m_crosshairColour = Qt::white; - break; - } - - m_colourMap.setColour(pixel, colour); + m_colourMap.setColour(pixel, mapper.map(pixel)); } + m_crosshairColour = mapper.getContrastingColour(); + m_colourRotation = 0; rotateColourmap(m_colourRotation - formerRotation); m_colourRotation = formerRotation; @@ -1734,7 +1666,7 @@ void SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const { - if (m_colourScheme == BlackOnWhite) { + if (m_colourScheme == (int)ColourMapper::BlackOnWhite) { v->setLightBackground(true); } else { v->setLightBackground(false); @@ -3064,8 +2996,7 @@ attributes.value("colourScale").toInt(&ok); if (ok) setColourScale(colourScale); - ColourScheme colourScheme = (ColourScheme) - attributes.value("colourScheme").toInt(&ok); + int colourScheme = attributes.value("colourScheme").toInt(&ok); if (ok) setColourScheme(colourScheme); int colourRotation = attributes.value("colourRotation").toInt(&ok); diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 layer/SpectrogramLayer.h --- a/layer/SpectrogramLayer.h Mon Jan 29 18:11:20 2007 +0000 +++ b/layer/SpectrogramLayer.h Wed Jan 31 12:13:47 2007 +0000 @@ -170,11 +170,8 @@ void setNormalizeVisibleArea(bool n); bool getNormalizeVisibleArea() const; - enum ColourScheme { DefaultColours, WhiteOnBlack, BlackOnWhite, - RedOnBlue, YellowOnBlack, BlueOnBlack, Rainbow }; - - void setColourScheme(ColourScheme scheme); - ColourScheme getColourScheme() const; + void setColourScheme(int scheme); + int getColourScheme() const; /** * Specify the colourmap rotation for the colour scale. @@ -241,7 +238,7 @@ size_t m_maxFrequency; size_t m_initialMaxFrequency; ColourScale m_colourScale; - ColourScheme m_colourScheme; + int m_colourScheme; QColor m_crosshairColour; FrequencyScale m_frequencyScale; BinDisplay m_binDisplay; diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 layer/layer.pro --- a/layer/layer.pro Mon Jan 29 18:11:20 2007 +0000 +++ b/layer/layer.pro Wed Jan 31 12:13:47 2007 +0000 @@ -15,6 +15,7 @@ # Input HEADERS += Colour3DPlotLayer.h \ + ColourMapper.h \ Layer.h \ LayerFactory.h \ NoteLayer.h \ @@ -29,6 +30,7 @@ TimeValueLayer.h \ WaveformLayer.h SOURCES += Colour3DPlotLayer.cpp \ + ColourMapper.cpp \ Layer.cpp \ LayerFactory.cpp \ NoteLayer.cpp \ diff -r 4a3bdde1ef13 -r 22c99c8aa1e0 widgets/SubdividingMenu.cpp --- a/widgets/SubdividingMenu.cpp Mon Jan 29 18:11:20 2007 +0000 +++ b/widgets/SubdividingMenu.cpp Wed Jan 31 12:13:47 2007 +0000 @@ -57,6 +57,7 @@ size_t count = 0; QMenu *chunkMenu = new QMenu(); + chunkMenu->setTearOffEnabled(isTearOffEnabled()); QString firstNameInChunk; QChar firstInitialInChunk; @@ -120,6 +121,7 @@ QMenu::addMenu(chunkMenu); chunkMenu = new QMenu(); + chunkMenu->setTearOffEnabled(isTearOffEnabled()); count = 0; } @@ -244,6 +246,7 @@ { if (!m_entriesSet) { QMenu *menu = new QMenu(name, this); + menu->setTearOffEnabled(isTearOffEnabled()); m_pendingEntries[name] = menu; return menu; }