annotate layer/ColourScale.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents ea5ae9dd10ba
children 371320c9f8d9
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@1068 22
Chris@1068 23 int ColourScale::m_maxPixel = 255;
Chris@1068 24
Chris@1070 25 ColourScale::ColourScale(Parameters parameters) :
Chris@1070 26 m_params(parameters),
Chris@1070 27 m_mapper(m_params.colourMap, 1.f, double(m_maxPixel))
Chris@1068 28 {
Chris@1070 29 if (m_params.minValue >= m_params.maxValue) {
Chris@1068 30 throw std::logic_error("maxValue must be greater than minValue");
Chris@1068 31 }
Chris@1068 32
Chris@1070 33 m_mappedMin = m_params.minValue;
Chris@1070 34 m_mappedMax = m_params.maxValue;
Chris@1068 35
Chris@1127 36 if (m_mappedMin < m_params.threshold) {
Chris@1127 37 m_mappedMin = m_params.threshold;
Chris@1127 38 }
Chris@1127 39
Chris@1105 40 if (m_params.scale == ColourScaleType::Log) {
Chris@1068 41
Chris@1068 42 LogRange::mapRange(m_mappedMin, m_mappedMax);
Chris@1068 43
Chris@1105 44 } else if (m_params.scale == ColourScaleType::PlusMinusOne) {
Chris@1068 45
Chris@1068 46 m_mappedMin = -1.0;
Chris@1068 47 m_mappedMax = 1.0;
Chris@1068 48
Chris@1105 49 } else if (m_params.scale == ColourScaleType::Absolute) {
Chris@1068 50
Chris@1068 51 m_mappedMin = fabs(m_mappedMin);
Chris@1068 52 m_mappedMax = fabs(m_mappedMax);
Chris@1068 53 if (m_mappedMin >= m_mappedMax) {
Chris@1068 54 std::swap(m_mappedMin, m_mappedMax);
Chris@1068 55 }
Chris@1068 56 }
Chris@1068 57
Chris@1068 58 if (m_mappedMin >= m_mappedMax) {
Chris@1068 59 throw std::logic_error("maxValue must be greater than minValue [after mapping]");
Chris@1068 60 }
Chris@1068 61 }
Chris@1068 62
Chris@1071 63 ColourScale::~ColourScale()
Chris@1071 64 {
Chris@1071 65 }
Chris@1071 66
Chris@1105 67 ColourScaleType
Chris@1079 68 ColourScale::getScale() const
Chris@1079 69 {
Chris@1079 70 return m_params.scale;
Chris@1079 71 }
Chris@1079 72
Chris@1068 73 int
Chris@1079 74 ColourScale::getPixel(double value) const
Chris@1068 75 {
Chris@1068 76 double maxPixF = m_maxPixel;
Chris@1068 77
Chris@1105 78 if (m_params.scale == ColourScaleType::Phase) {
Chris@1068 79 double half = (maxPixF - 1.f) / 2.f;
Chris@1068 80 return 1 + int((value * half) / M_PI + half);
Chris@1068 81 }
Chris@1068 82
Chris@1070 83 value *= m_params.gain;
Chris@1068 84
Chris@1070 85 if (value < m_params.threshold) return 0;
Chris@1068 86
Chris@1068 87 double mapped = value;
Chris@1068 88
Chris@1105 89 if (m_params.scale == ColourScaleType::Log) {
Chris@1068 90 mapped = LogRange::map(value);
Chris@1105 91 } else if (m_params.scale == ColourScaleType::PlusMinusOne) {
Chris@1068 92 if (mapped < -1.f) mapped = -1.f;
Chris@1068 93 if (mapped > 1.f) mapped = 1.f;
Chris@1105 94 } else if (m_params.scale == ColourScaleType::Absolute) {
Chris@1068 95 if (mapped < 0.f) mapped = -mapped;
Chris@1068 96 }
Chris@1068 97
Chris@1068 98 if (mapped < m_mappedMin) {
Chris@1068 99 mapped = m_mappedMin;
Chris@1068 100 }
Chris@1068 101 if (mapped > m_mappedMax) {
Chris@1068 102 mapped = m_mappedMax;
Chris@1068 103 }
Chris@1068 104
Chris@1068 105 double proportion = (mapped - m_mappedMin) / (m_mappedMax - m_mappedMin);
Chris@1068 106
Chris@1068 107 int pixel = 0;
Chris@1068 108
Chris@1105 109 if (m_params.scale == ColourScaleType::Meter) {
Chris@1068 110 pixel = AudioLevel::multiplier_to_preview(proportion, m_maxPixel-1) + 1;
Chris@1068 111 } else {
Chris@1068 112 pixel = int(proportion * maxPixF) + 1;
Chris@1068 113 }
Chris@1068 114
Chris@1070 115 if (pixel < 0) {
Chris@1070 116 pixel = 0;
Chris@1070 117 }
Chris@1070 118 if (pixel > m_maxPixel) {
Chris@1070 119 pixel = m_maxPixel;
Chris@1070 120 }
Chris@1068 121 return pixel;
Chris@1068 122 }
Chris@1068 123
Chris@1068 124 QColor
Chris@1079 125 ColourScale::getColourForPixel(int pixel, int rotation) const
Chris@1068 126 {
Chris@1068 127 if (pixel < 0) {
Chris@1068 128 pixel = 0;
Chris@1068 129 }
Chris@1068 130 if (pixel > m_maxPixel) {
Chris@1068 131 pixel = m_maxPixel;
Chris@1068 132 }
Chris@1068 133 if (pixel == 0) {
Chris@1068 134 if (m_mapper.hasLightBackground()) {
Chris@1068 135 return Qt::white;
Chris@1068 136 } else {
Chris@1068 137 return Qt::black;
Chris@1068 138 }
Chris@1068 139 } else {
Chris@1068 140 int target = int(pixel) + rotation;
Chris@1068 141 while (target < 1) target += m_maxPixel;
Chris@1068 142 while (target > m_maxPixel) target -= m_maxPixel;
Chris@1068 143 return m_mapper.map(double(target));
Chris@1068 144 }
Chris@1068 145 }