annotate layer/ColourScale.cpp @ 1135:628cd329c241 spectrogram-minor-refactor

Use a count of bins rather than min and max bins (because the name maxbin tells us nothing about whether the range is inclusive or not)
author Chris Cannam
date Wed, 03 Aug 2016 14:20:27 +0100
parents 371320c9f8d9
children 4e7ed3252d80
rev   line source
Chris@1068 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1068 2
Chris@1068 3 /*
Chris@1068 4 Sonic Visualiser
Chris@1068 5 An audio file viewer and annotation editor.
Chris@1068 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1068 7 This file copyright 2006-2016 Chris Cannam and QMUL.
Chris@1068 8
Chris@1068 9 This program is free software; you can redistribute it and/or
Chris@1068 10 modify it under the terms of the GNU General Public License as
Chris@1068 11 published by the Free Software Foundation; either version 2 of the
Chris@1068 12 License, or (at your option) any later version. See the file
Chris@1068 13 COPYING included with this distribution for more information.
Chris@1068 14 */
Chris@1068 15
Chris@1068 16 #include "ColourScale.h"
Chris@1068 17
Chris@1068 18 #include "base/AudioLevel.h"
Chris@1068 19 #include "base/LogRange.h"
Chris@1068 20
Chris@1068 21 #include <cmath>
Chris@1129 22 #include <iostream>
Chris@1129 23
Chris@1129 24 using namespace std;
Chris@1068 25
Chris@1068 26 int ColourScale::m_maxPixel = 255;
Chris@1068 27
Chris@1070 28 ColourScale::ColourScale(Parameters parameters) :
Chris@1070 29 m_params(parameters),
Chris@1070 30 m_mapper(m_params.colourMap, 1.f, double(m_maxPixel))
Chris@1068 31 {
Chris@1070 32 if (m_params.minValue >= m_params.maxValue) {
Chris@1129 33 cerr << "ERROR: ColourScale::ColourScale: minValue = "
Chris@1129 34 << m_params.minValue << ", maxValue = " << m_params.maxValue << endl;
Chris@1068 35 throw std::logic_error("maxValue must be greater than minValue");
Chris@1068 36 }
Chris@1068 37
Chris@1070 38 m_mappedMin = m_params.minValue;
Chris@1070 39 m_mappedMax = m_params.maxValue;
Chris@1068 40
Chris@1127 41 if (m_mappedMin < m_params.threshold) {
Chris@1127 42 m_mappedMin = m_params.threshold;
Chris@1127 43 }
Chris@1127 44
Chris@1105 45 if (m_params.scale == ColourScaleType::Log) {
Chris@1068 46
Chris@1068 47 LogRange::mapRange(m_mappedMin, m_mappedMax);
Chris@1068 48
Chris@1105 49 } else if (m_params.scale == ColourScaleType::PlusMinusOne) {
Chris@1068 50
Chris@1068 51 m_mappedMin = -1.0;
Chris@1068 52 m_mappedMax = 1.0;
Chris@1068 53
Chris@1105 54 } else if (m_params.scale == ColourScaleType::Absolute) {
Chris@1068 55
Chris@1068 56 m_mappedMin = fabs(m_mappedMin);
Chris@1068 57 m_mappedMax = fabs(m_mappedMax);
Chris@1068 58 if (m_mappedMin >= m_mappedMax) {
Chris@1068 59 std::swap(m_mappedMin, m_mappedMax);
Chris@1068 60 }
Chris@1068 61 }
Chris@1068 62
Chris@1068 63 if (m_mappedMin >= m_mappedMax) {
Chris@1129 64 cerr << "ERROR: ColourScale::ColourScale: minValue = " << m_params.minValue
Chris@1129 65 << ", maxValue = " << m_params.maxValue
Chris@1129 66 << ", threshold = " << m_params.threshold
Chris@1129 67 << ", scale = " << int(m_params.scale)
Chris@1129 68 << " resulting in mapped minValue = " << m_mappedMin
Chris@1129 69 << ", mapped maxValue = " << m_mappedMax << endl;
Chris@1068 70 throw std::logic_error("maxValue must be greater than minValue [after mapping]");
Chris@1068 71 }
Chris@1068 72 }
Chris@1068 73
Chris@1071 74 ColourScale::~ColourScale()
Chris@1071 75 {
Chris@1071 76 }
Chris@1071 77
Chris@1105 78 ColourScaleType
Chris@1079 79 ColourScale::getScale() const
Chris@1079 80 {
Chris@1079 81 return m_params.scale;
Chris@1079 82 }
Chris@1079 83
Chris@1068 84 int
Chris@1079 85 ColourScale::getPixel(double value) const
Chris@1068 86 {
Chris@1068 87 double maxPixF = m_maxPixel;
Chris@1068 88
Chris@1105 89 if (m_params.scale == ColourScaleType::Phase) {
Chris@1068 90 double half = (maxPixF - 1.f) / 2.f;
Chris@1068 91 return 1 + int((value * half) / M_PI + half);
Chris@1068 92 }
Chris@1068 93
Chris@1070 94 value *= m_params.gain;
Chris@1068 95
Chris@1070 96 if (value < m_params.threshold) return 0;
Chris@1068 97
Chris@1068 98 double mapped = value;
Chris@1068 99
Chris@1105 100 if (m_params.scale == ColourScaleType::Log) {
Chris@1068 101 mapped = LogRange::map(value);
Chris@1105 102 } else if (m_params.scale == ColourScaleType::PlusMinusOne) {
Chris@1068 103 if (mapped < -1.f) mapped = -1.f;
Chris@1068 104 if (mapped > 1.f) mapped = 1.f;
Chris@1105 105 } else if (m_params.scale == ColourScaleType::Absolute) {
Chris@1068 106 if (mapped < 0.f) mapped = -mapped;
Chris@1068 107 }
Chris@1068 108
Chris@1068 109 if (mapped < m_mappedMin) {
Chris@1068 110 mapped = m_mappedMin;
Chris@1068 111 }
Chris@1068 112 if (mapped > m_mappedMax) {
Chris@1068 113 mapped = m_mappedMax;
Chris@1068 114 }
Chris@1068 115
Chris@1068 116 double proportion = (mapped - m_mappedMin) / (m_mappedMax - m_mappedMin);
Chris@1068 117
Chris@1068 118 int pixel = 0;
Chris@1068 119
Chris@1105 120 if (m_params.scale == ColourScaleType::Meter) {
Chris@1068 121 pixel = AudioLevel::multiplier_to_preview(proportion, m_maxPixel-1) + 1;
Chris@1068 122 } else {
Chris@1068 123 pixel = int(proportion * maxPixF) + 1;
Chris@1068 124 }
Chris@1068 125
Chris@1070 126 if (pixel < 0) {
Chris@1070 127 pixel = 0;
Chris@1070 128 }
Chris@1070 129 if (pixel > m_maxPixel) {
Chris@1070 130 pixel = m_maxPixel;
Chris@1070 131 }
Chris@1068 132 return pixel;
Chris@1068 133 }
Chris@1068 134
Chris@1068 135 QColor
Chris@1079 136 ColourScale::getColourForPixel(int pixel, int rotation) const
Chris@1068 137 {
Chris@1068 138 if (pixel < 0) {
Chris@1068 139 pixel = 0;
Chris@1068 140 }
Chris@1068 141 if (pixel > m_maxPixel) {
Chris@1068 142 pixel = m_maxPixel;
Chris@1068 143 }
Chris@1068 144 if (pixel == 0) {
Chris@1068 145 if (m_mapper.hasLightBackground()) {
Chris@1068 146 return Qt::white;
Chris@1068 147 } else {
Chris@1068 148 return Qt::black;
Chris@1068 149 }
Chris@1068 150 } else {
Chris@1068 151 int target = int(pixel) + rotation;
Chris@1068 152 while (target < 1) target += m_maxPixel;
Chris@1068 153 while (target > m_maxPixel) target -= m_maxPixel;
Chris@1068 154 return m_mapper.map(double(target));
Chris@1068 155 }
Chris@1068 156 }