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 }
|