Chris@376
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@376
|
2
|
Chris@376
|
3 /*
|
Chris@376
|
4 Sonic Visualiser
|
Chris@376
|
5 An audio file viewer and annotation editor.
|
Chris@376
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@376
|
7 This file copyright 2006-2007 Chris Cannam and QMUL.
|
Chris@376
|
8
|
Chris@376
|
9 This program is free software; you can redistribute it and/or
|
Chris@376
|
10 modify it under the terms of the GNU General Public License as
|
Chris@376
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@376
|
12 License, or (at your option) any later version. See the file
|
Chris@376
|
13 COPYING included with this distribution for more information.
|
Chris@376
|
14 */
|
Chris@376
|
15
|
Chris@376
|
16 #include "ColourMapper.h"
|
Chris@376
|
17
|
Chris@376
|
18 #include <iostream>
|
Chris@376
|
19
|
Chris@376
|
20 #include <cmath>
|
Chris@376
|
21
|
Chris@376
|
22 ColourMapper::ColourMapper(int map, float min, float max) :
|
Chris@376
|
23 QObject(),
|
Chris@376
|
24 m_map(map),
|
Chris@376
|
25 m_min(min),
|
Chris@376
|
26 m_max(max)
|
Chris@376
|
27 {
|
Chris@376
|
28 if (m_min == m_max) {
|
Chris@376
|
29 std::cerr << "WARNING: ColourMapper: min == max (== " << m_min
|
Chris@376
|
30 << "), adjusting" << std::endl;
|
Chris@376
|
31 m_max = m_min + 1;
|
Chris@376
|
32 }
|
Chris@376
|
33 }
|
Chris@376
|
34
|
Chris@376
|
35 ColourMapper::~ColourMapper()
|
Chris@376
|
36 {
|
Chris@376
|
37 }
|
Chris@376
|
38
|
Chris@376
|
39 int
|
Chris@376
|
40 ColourMapper::getColourMapCount()
|
Chris@376
|
41 {
|
Chris@536
|
42 return 12;
|
Chris@376
|
43 }
|
Chris@376
|
44
|
Chris@376
|
45 QString
|
Chris@376
|
46 ColourMapper::getColourMapName(int n)
|
Chris@376
|
47 {
|
Chris@376
|
48 if (n >= getColourMapCount()) return tr("<unknown>");
|
Chris@376
|
49 StandardMap map = (StandardMap)n;
|
Chris@376
|
50
|
Chris@376
|
51 switch (map) {
|
Chris@376
|
52 case DefaultColours: return tr("Default");
|
Chris@376
|
53 case WhiteOnBlack: return tr("White on Black");
|
Chris@376
|
54 case BlackOnWhite: return tr("Black on White");
|
Chris@376
|
55 case RedOnBlue: return tr("Red on Blue");
|
Chris@376
|
56 case YellowOnBlack: return tr("Yellow on Black");
|
Chris@376
|
57 case BlueOnBlack: return tr("Blue on Black");
|
Chris@376
|
58 case Sunset: return tr("Sunset");
|
Chris@376
|
59 case FruitSalad: return tr("Fruit Salad");
|
Chris@376
|
60 case Banded: return tr("Banded");
|
Chris@376
|
61 case Highlight: return tr("Highlight");
|
Chris@376
|
62 case Printer: return tr("Printer");
|
Chris@536
|
63 case HighGain: return tr("High Gain");
|
Chris@376
|
64 }
|
Chris@376
|
65
|
Chris@376
|
66 return tr("<unknown>");
|
Chris@376
|
67 }
|
Chris@376
|
68
|
Chris@376
|
69 QColor
|
Chris@376
|
70 ColourMapper::map(float value) const
|
Chris@376
|
71 {
|
Chris@376
|
72 float norm = (value - m_min) / (m_max - m_min);
|
Chris@376
|
73 if (norm < 0.f) norm = 0.f;
|
Chris@376
|
74 if (norm > 1.f) norm = 1.f;
|
Chris@376
|
75
|
Chris@376
|
76 float h = 0.f, s = 0.f, v = 0.f, r = 0.f, g = 0.f, b = 0.f;
|
Chris@376
|
77 bool hsv = true;
|
Chris@376
|
78
|
Chris@376
|
79 // float red = 0.f, green = 0.3333f;
|
Chris@376
|
80 float blue = 0.6666f, pieslice = 0.3333f;
|
Chris@376
|
81
|
Chris@376
|
82 if (m_map >= getColourMapCount()) return Qt::black;
|
Chris@376
|
83 StandardMap map = (StandardMap)m_map;
|
Chris@376
|
84
|
Chris@376
|
85 switch (map) {
|
Chris@376
|
86
|
Chris@376
|
87 case DefaultColours:
|
Chris@376
|
88 h = blue - norm * 2.f * pieslice;
|
Chris@376
|
89 s = 0.5f + norm/2.f;
|
Chris@376
|
90 v = norm;
|
Chris@376
|
91 break;
|
Chris@376
|
92
|
Chris@376
|
93 case WhiteOnBlack:
|
Chris@376
|
94 r = g = b = norm;
|
Chris@376
|
95 hsv = false;
|
Chris@376
|
96 break;
|
Chris@376
|
97
|
Chris@376
|
98 case BlackOnWhite:
|
Chris@376
|
99 r = g = b = 1.f - norm;
|
Chris@376
|
100 hsv = false;
|
Chris@376
|
101 break;
|
Chris@376
|
102
|
Chris@376
|
103 case RedOnBlue:
|
Chris@376
|
104 h = blue - pieslice/4.f + norm * (pieslice + pieslice/4.f);
|
Chris@376
|
105 s = 1.f;
|
Chris@376
|
106 v = norm;
|
Chris@376
|
107 break;
|
Chris@376
|
108
|
Chris@376
|
109 case YellowOnBlack:
|
Chris@376
|
110 h = 0.15f;
|
Chris@376
|
111 s = 1.f;
|
Chris@376
|
112 v = norm;
|
Chris@376
|
113 break;
|
Chris@376
|
114
|
Chris@376
|
115 case BlueOnBlack:
|
Chris@376
|
116 h = blue;
|
Chris@376
|
117 s = 1.f;
|
Chris@376
|
118 v = norm * 2.f;
|
Chris@376
|
119 if (v > 1.f) {
|
Chris@376
|
120 v = 1.f;
|
Chris@376
|
121 s = 1.f - (sqrtf(norm) - 0.707f) * 3.413f;
|
Chris@376
|
122 if (s < 0.f) s = 0.f;
|
Chris@376
|
123 if (s > 1.f) s = 1.f;
|
Chris@376
|
124 }
|
Chris@376
|
125 break;
|
Chris@376
|
126
|
Chris@376
|
127 case Sunset:
|
Chris@376
|
128 r = (norm - 0.24f) * 2.38f;
|
Chris@376
|
129 if (r > 1.f) r = 1.f;
|
Chris@376
|
130 if (r < 0.f) r = 0.f;
|
Chris@376
|
131 g = (norm - 0.64f) * 2.777f;
|
Chris@376
|
132 if (g > 1.f) g = 1.f;
|
Chris@376
|
133 if (g < 0.f) g = 0.f;
|
Chris@376
|
134 b = (3.6f * norm);
|
Chris@376
|
135 if (norm > 0.277f) b = 2.f - b;
|
Chris@376
|
136 if (b > 1.f) b = 1.f;
|
Chris@376
|
137 if (b < 0.f) b = 0.f;
|
Chris@376
|
138 hsv = false;
|
Chris@376
|
139 break;
|
Chris@376
|
140
|
Chris@376
|
141 case FruitSalad:
|
Chris@376
|
142 h = blue + (pieslice/6.f) - norm;
|
Chris@376
|
143 if (h < 0.f) h += 1.f;
|
Chris@376
|
144 s = 1.f;
|
Chris@376
|
145 v = 1.f;
|
Chris@376
|
146 break;
|
Chris@376
|
147
|
Chris@376
|
148 case Banded:
|
Chris@376
|
149 if (norm < 0.125) return Qt::darkGreen;
|
Chris@376
|
150 else if (norm < 0.25) return Qt::green;
|
Chris@376
|
151 else if (norm < 0.375) return Qt::darkBlue;
|
Chris@376
|
152 else if (norm < 0.5) return Qt::blue;
|
Chris@376
|
153 else if (norm < 0.625) return Qt::darkYellow;
|
Chris@376
|
154 else if (norm < 0.75) return Qt::yellow;
|
Chris@376
|
155 else if (norm < 0.875) return Qt::darkRed;
|
Chris@376
|
156 else return Qt::red;
|
Chris@376
|
157 break;
|
Chris@376
|
158
|
Chris@376
|
159 case Highlight:
|
Chris@376
|
160 if (norm > 0.99) return Qt::white;
|
Chris@376
|
161 else return Qt::darkBlue;
|
Chris@376
|
162
|
Chris@376
|
163 case Printer:
|
Chris@376
|
164 if (norm > 0.8) {
|
Chris@376
|
165 r = 1.f;
|
Chris@376
|
166 } else if (norm > 0.7) {
|
Chris@376
|
167 r = 0.9f;
|
Chris@376
|
168 } else if (norm > 0.6) {
|
Chris@376
|
169 r = 0.8f;
|
Chris@376
|
170 } else if (norm > 0.5) {
|
Chris@376
|
171 r = 0.7f;
|
Chris@376
|
172 } else if (norm > 0.4) {
|
Chris@376
|
173 r = 0.6f;
|
Chris@376
|
174 } else if (norm > 0.3) {
|
Chris@376
|
175 r = 0.5f;
|
Chris@376
|
176 } else if (norm > 0.2) {
|
Chris@376
|
177 r = 0.4f;
|
Chris@376
|
178 } else {
|
Chris@376
|
179 r = 0.f;
|
Chris@376
|
180 }
|
Chris@376
|
181 r = g = b = 1.f - r;
|
Chris@376
|
182 hsv = false;
|
Chris@376
|
183 break;
|
Chris@536
|
184
|
Chris@536
|
185 case HighGain:
|
Chris@536
|
186 if (norm <= 1.f / 256.f) {
|
Chris@536
|
187 norm = 0.f;
|
Chris@536
|
188 } else {
|
Chris@536
|
189 norm = 0.1f + (powf(((norm - 0.5f) * 2.f), 3.f) + 1.f) / 2.081f;
|
Chris@536
|
190 }
|
Chris@536
|
191 // now as for Sunset
|
Chris@536
|
192 r = (norm - 0.24f) * 2.38f;
|
Chris@536
|
193 if (r > 1.f) r = 1.f;
|
Chris@536
|
194 if (r < 0.f) r = 0.f;
|
Chris@536
|
195 g = (norm - 0.64f) * 2.777f;
|
Chris@536
|
196 if (g > 1.f) g = 1.f;
|
Chris@536
|
197 if (g < 0.f) g = 0.f;
|
Chris@536
|
198 b = (3.6f * norm);
|
Chris@536
|
199 if (norm > 0.277f) b = 2.f - b;
|
Chris@536
|
200 if (b > 1.f) b = 1.f;
|
Chris@536
|
201 if (b < 0.f) b = 0.f;
|
Chris@536
|
202 hsv = false;
|
Chris@536
|
203 /*
|
Chris@536
|
204 if (r > 1.f) r = 1.f;
|
Chris@536
|
205 r = g = b = 1.f - r;
|
Chris@536
|
206 hsv = false;
|
Chris@536
|
207 */
|
Chris@536
|
208 break;
|
Chris@376
|
209 }
|
Chris@376
|
210
|
Chris@376
|
211 if (hsv) {
|
Chris@376
|
212 return QColor::fromHsvF(h, s, v);
|
Chris@376
|
213 } else {
|
Chris@376
|
214 return QColor::fromRgbF(r, g, b);
|
Chris@376
|
215 }
|
Chris@376
|
216 }
|
Chris@376
|
217
|
Chris@376
|
218 QColor
|
Chris@376
|
219 ColourMapper::getContrastingColour() const
|
Chris@376
|
220 {
|
Chris@376
|
221 if (m_map >= getColourMapCount()) return Qt::white;
|
Chris@376
|
222 StandardMap map = (StandardMap)m_map;
|
Chris@376
|
223
|
Chris@376
|
224 switch (map) {
|
Chris@376
|
225
|
Chris@376
|
226 case DefaultColours:
|
Chris@376
|
227 return QColor(255, 150, 50);
|
Chris@376
|
228
|
Chris@376
|
229 case WhiteOnBlack:
|
Chris@376
|
230 return Qt::red;
|
Chris@376
|
231
|
Chris@376
|
232 case BlackOnWhite:
|
Chris@376
|
233 return Qt::darkGreen;
|
Chris@376
|
234
|
Chris@376
|
235 case RedOnBlue:
|
Chris@376
|
236 return Qt::green;
|
Chris@376
|
237
|
Chris@376
|
238 case YellowOnBlack:
|
Chris@376
|
239 return QColor::fromHsv(240, 255, 255);
|
Chris@376
|
240
|
Chris@376
|
241 case BlueOnBlack:
|
Chris@376
|
242 return Qt::red;
|
Chris@376
|
243
|
Chris@376
|
244 case Sunset:
|
Chris@376
|
245 return Qt::white;
|
Chris@376
|
246
|
Chris@376
|
247 case FruitSalad:
|
Chris@376
|
248 return Qt::white;
|
Chris@376
|
249
|
Chris@376
|
250 case Banded:
|
Chris@376
|
251 return Qt::cyan;
|
Chris@376
|
252
|
Chris@376
|
253 case Highlight:
|
Chris@376
|
254 return Qt::red;
|
Chris@376
|
255
|
Chris@376
|
256 case Printer:
|
Chris@376
|
257 return Qt::red;
|
Chris@536
|
258
|
Chris@536
|
259 case HighGain:
|
Chris@536
|
260 return Qt::red;
|
Chris@376
|
261 }
|
Chris@376
|
262
|
Chris@376
|
263 return Qt::white;
|
Chris@376
|
264 }
|
Chris@376
|
265
|
Chris@376
|
266 bool
|
Chris@376
|
267 ColourMapper::hasLightBackground() const
|
Chris@376
|
268 {
|
Chris@376
|
269 if (m_map >= getColourMapCount()) return false;
|
Chris@376
|
270 StandardMap map = (StandardMap)m_map;
|
Chris@376
|
271
|
Chris@376
|
272 switch (map) {
|
Chris@376
|
273
|
Chris@376
|
274 case BlackOnWhite:
|
Chris@376
|
275 case Printer:
|
Chris@536
|
276 case HighGain:
|
Chris@376
|
277 return true;
|
Chris@376
|
278
|
Chris@376
|
279 default:
|
Chris@376
|
280 return false;
|
Chris@376
|
281 }
|
Chris@376
|
282 }
|
Chris@376
|
283
|
Chris@376
|
284
|