lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7 This file copyright 2006-2007 Chris Cannam and QMUL.
|
lbajardsilogic@0
|
8
|
lbajardsilogic@0
|
9 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
10 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
11 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
12 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
13 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
14 */
|
lbajardsilogic@0
|
15
|
lbajardsilogic@0
|
16 #include "PaintAssistant.h"
|
lbajardsilogic@0
|
17
|
lbajardsilogic@0
|
18 #include "base/AudioLevel.h"
|
lbajardsilogic@0
|
19 #include "system/System.h"
|
lbajardsilogic@0
|
20
|
lbajardsilogic@0
|
21 #include <QPaintDevice>
|
lbajardsilogic@0
|
22 #include <QPainter>
|
lbajardsilogic@0
|
23
|
lbajardsilogic@0
|
24 #include <iostream>
|
lbajardsilogic@0
|
25 #include <cmath>
|
lbajardsilogic@0
|
26
|
lbajardsilogic@0
|
27 void
|
lbajardsilogic@0
|
28 PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect,
|
lbajardsilogic@0
|
29 float minVal, float maxVal,
|
lbajardsilogic@0
|
30 Scale scale, int &mult,
|
lbajardsilogic@0
|
31 std::vector<int> *vy)
|
lbajardsilogic@0
|
32 {
|
lbajardsilogic@0
|
33 static float meterdbs[] = { -40, -30, -20, -15, -10,
|
lbajardsilogic@0
|
34 -5, -3, -2, -1, -0.5, 0 };
|
lbajardsilogic@0
|
35
|
lbajardsilogic@0
|
36 int h = rect.height(), w = rect.width();
|
lbajardsilogic@0
|
37 int textHeight = paint.fontMetrics().height();
|
lbajardsilogic@0
|
38 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
|
lbajardsilogic@0
|
39
|
lbajardsilogic@0
|
40 int lastLabelledY = -1;
|
lbajardsilogic@0
|
41
|
lbajardsilogic@0
|
42 int n = 10;
|
lbajardsilogic@0
|
43 if (vy) vy->clear();
|
lbajardsilogic@0
|
44
|
lbajardsilogic@0
|
45 float step = 0;
|
lbajardsilogic@0
|
46 mult = 1;
|
lbajardsilogic@0
|
47 if (scale == LinearScale) {
|
lbajardsilogic@0
|
48 step = (maxVal - minVal) / n;
|
lbajardsilogic@0
|
49 int round = 0, limit = 10000000;
|
lbajardsilogic@0
|
50 do {
|
lbajardsilogic@0
|
51 round = int(minVal + step * mult);
|
lbajardsilogic@0
|
52 mult *= 10;
|
lbajardsilogic@0
|
53 } while (!round && mult < limit);
|
lbajardsilogic@0
|
54 if (round) {
|
lbajardsilogic@0
|
55 mult /= 10;
|
lbajardsilogic@0
|
56 // std::cerr << "\n\nstep goes from " << step;
|
lbajardsilogic@0
|
57 step = float(round) / mult;
|
lbajardsilogic@0
|
58 n = lrintf((maxVal - minVal) / step);
|
lbajardsilogic@0
|
59 if (mult > 1) {
|
lbajardsilogic@0
|
60 mult /= 10;
|
lbajardsilogic@0
|
61 }
|
lbajardsilogic@0
|
62 // std::cerr << " to " << step << " (n = " << n << ")" << std::endl;
|
lbajardsilogic@0
|
63 }
|
lbajardsilogic@0
|
64 }
|
lbajardsilogic@0
|
65
|
lbajardsilogic@0
|
66 for (int i = 0; i <= n; ++i) {
|
lbajardsilogic@0
|
67
|
lbajardsilogic@0
|
68 float val = 0.0, nval = 0.0;
|
lbajardsilogic@0
|
69 QString text = "";
|
lbajardsilogic@0
|
70
|
lbajardsilogic@0
|
71 switch (scale) {
|
lbajardsilogic@0
|
72
|
lbajardsilogic@0
|
73 case LinearScale:
|
lbajardsilogic@0
|
74 val = (minVal + (i * step));
|
lbajardsilogic@0
|
75 text = QString("%1").arg(mult * val);
|
lbajardsilogic@0
|
76 break;
|
lbajardsilogic@0
|
77
|
lbajardsilogic@0
|
78 case MeterScale: // ... min, max
|
lbajardsilogic@0
|
79 val = AudioLevel::dB_to_multiplier(meterdbs[i]);
|
lbajardsilogic@0
|
80 text = QString("%1").arg(meterdbs[i]);
|
lbajardsilogic@0
|
81 if (i == n) text = "0dB";
|
lbajardsilogic@0
|
82 if (i == 0) {
|
lbajardsilogic@0
|
83 text = "-Inf";
|
lbajardsilogic@0
|
84 val = 0.0;
|
lbajardsilogic@0
|
85 }
|
lbajardsilogic@0
|
86 break;
|
lbajardsilogic@0
|
87
|
lbajardsilogic@0
|
88 case dBScale: // ... min, max
|
lbajardsilogic@0
|
89 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10);
|
lbajardsilogic@0
|
90 text = QString("%1").arg(-(10*n) + i * 10);
|
lbajardsilogic@0
|
91 if (i == n) text = "0dB";
|
lbajardsilogic@0
|
92 if (i == 0) {
|
lbajardsilogic@0
|
93 text = "-Inf";
|
lbajardsilogic@0
|
94 val = 0.0;
|
lbajardsilogic@0
|
95 }
|
lbajardsilogic@0
|
96 break;
|
lbajardsilogic@0
|
97 }
|
lbajardsilogic@0
|
98
|
lbajardsilogic@0
|
99 if (val < minVal || val > maxVal) continue;
|
lbajardsilogic@0
|
100
|
lbajardsilogic@0
|
101 int y = getYForValue(scale, val, minVal, maxVal, rect.y(), h);
|
lbajardsilogic@0
|
102
|
lbajardsilogic@0
|
103 int ny = y;
|
lbajardsilogic@0
|
104 if (nval != 0.0) {
|
lbajardsilogic@0
|
105 ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), h);
|
lbajardsilogic@0
|
106 }
|
lbajardsilogic@0
|
107
|
lbajardsilogic@0
|
108 // std::cerr << "PaintAssistant::paintVerticalLevelScale: val = "
|
lbajardsilogic@0
|
109 // << val << ", y = " << y << ", h = " << h << std::endl;
|
lbajardsilogic@0
|
110
|
lbajardsilogic@0
|
111 bool spaceForLabel = (i == 0 ||
|
lbajardsilogic@0
|
112 abs(y - lastLabelledY) >= textHeight - 1);
|
lbajardsilogic@0
|
113
|
lbajardsilogic@0
|
114 if (spaceForLabel) {
|
lbajardsilogic@0
|
115
|
lbajardsilogic@0
|
116 int tx = 3;
|
lbajardsilogic@0
|
117 // if (scale != LinearScale) {
|
lbajardsilogic@0
|
118 if (paint.fontMetrics().width(text) < w - 10) {
|
lbajardsilogic@0
|
119 tx = w - 10 - paint.fontMetrics().width(text);
|
lbajardsilogic@0
|
120 }
|
lbajardsilogic@0
|
121
|
lbajardsilogic@0
|
122 int ty = y;
|
lbajardsilogic@0
|
123
|
lbajardsilogic@0
|
124 if (ty < paint.fontMetrics().ascent()) {
|
lbajardsilogic@0
|
125 ty = paint.fontMetrics().ascent();
|
lbajardsilogic@0
|
126 // } else if (ty > rect.y() + h - paint.fontMetrics().descent()) {
|
lbajardsilogic@0
|
127 // ty = rect.y() + h - paint.fontMetrics().descent();
|
lbajardsilogic@0
|
128 } else {
|
lbajardsilogic@0
|
129 ty += toff;
|
lbajardsilogic@0
|
130 }
|
lbajardsilogic@0
|
131
|
lbajardsilogic@0
|
132 paint.drawText(tx, ty, text);
|
lbajardsilogic@0
|
133
|
lbajardsilogic@0
|
134 lastLabelledY = ty - toff;
|
lbajardsilogic@0
|
135 /*
|
lbajardsilogic@0
|
136 if (ny != y) {
|
lbajardsilogic@0
|
137 ty = ny;
|
lbajardsilogic@0
|
138 if (ty < paint.fontMetrics().ascent()) {
|
lbajardsilogic@0
|
139 ty = paint.fontMetrics().ascent();
|
lbajardsilogic@0
|
140 } else if (ty > h - paint.fontMetrics().descent()) {
|
lbajardsilogic@0
|
141 ty = h - paint.fontMetrics().descent();
|
lbajardsilogic@0
|
142 } else {
|
lbajardsilogic@0
|
143 ty += toff;
|
lbajardsilogic@0
|
144 }
|
lbajardsilogic@0
|
145 paint.drawText(tx, ty, text);
|
lbajardsilogic@0
|
146 }
|
lbajardsilogic@0
|
147 */
|
lbajardsilogic@0
|
148 paint.drawLine(w - 7, y, w, y);
|
lbajardsilogic@0
|
149 if (vy) vy->push_back(y);
|
lbajardsilogic@0
|
150
|
lbajardsilogic@0
|
151 if (ny != y) {
|
lbajardsilogic@0
|
152 paint.drawLine(w - 7, ny, w, ny);
|
lbajardsilogic@0
|
153 if (vy) vy->push_back(ny);
|
lbajardsilogic@0
|
154 }
|
lbajardsilogic@0
|
155
|
lbajardsilogic@0
|
156 } else {
|
lbajardsilogic@0
|
157
|
lbajardsilogic@0
|
158 paint.drawLine(w - 4, y, w, y);
|
lbajardsilogic@0
|
159 if (vy) vy->push_back(y);
|
lbajardsilogic@0
|
160
|
lbajardsilogic@0
|
161 if (ny != y) {
|
lbajardsilogic@0
|
162 paint.drawLine(w - 4, ny, w, ny);
|
lbajardsilogic@0
|
163 if (vy) vy->push_back(ny);
|
lbajardsilogic@0
|
164 }
|
lbajardsilogic@0
|
165 }
|
lbajardsilogic@0
|
166 }
|
lbajardsilogic@0
|
167 }
|
lbajardsilogic@0
|
168
|
lbajardsilogic@0
|
169 static int
|
lbajardsilogic@0
|
170 dBscale(float sample, int m, float maxVal, float minVal)
|
lbajardsilogic@0
|
171 {
|
lbajardsilogic@0
|
172 if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal);
|
lbajardsilogic@0
|
173 float dB = AudioLevel::multiplier_to_dB(sample);
|
lbajardsilogic@0
|
174 float mindB = AudioLevel::multiplier_to_dB(minVal);
|
lbajardsilogic@0
|
175 float maxdB = AudioLevel::multiplier_to_dB(maxVal);
|
lbajardsilogic@0
|
176 if (dB < mindB) return 0;
|
lbajardsilogic@0
|
177 if (dB > 0.0) return m;
|
lbajardsilogic@0
|
178 return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1);
|
lbajardsilogic@0
|
179 }
|
lbajardsilogic@0
|
180
|
lbajardsilogic@0
|
181 int
|
lbajardsilogic@0
|
182 PaintAssistant::getYForValue(Scale scale, float value,
|
lbajardsilogic@0
|
183 float minVal, float maxVal,
|
lbajardsilogic@0
|
184 int minY, int height)
|
lbajardsilogic@0
|
185 {
|
lbajardsilogic@0
|
186 int vy = 0;
|
lbajardsilogic@0
|
187
|
lbajardsilogic@0
|
188 // int m = height/2;
|
lbajardsilogic@0
|
189 // int my = minY + m;
|
lbajardsilogic@0
|
190
|
lbajardsilogic@0
|
191 switch (scale) {
|
lbajardsilogic@0
|
192
|
lbajardsilogic@0
|
193 case LinearScale:
|
lbajardsilogic@0
|
194 // vy = my - int(m * value);
|
lbajardsilogic@0
|
195 vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height);
|
lbajardsilogic@0
|
196 break;
|
lbajardsilogic@0
|
197
|
lbajardsilogic@0
|
198 case MeterScale:
|
lbajardsilogic@0
|
199 // vy = my - AudioLevel::multiplier_to_preview(value, m);
|
lbajardsilogic@0
|
200 vy = minY + height - AudioLevel::multiplier_to_preview
|
lbajardsilogic@0
|
201 ((value - minVal) / (maxVal - minVal), height);
|
lbajardsilogic@0
|
202 break;
|
lbajardsilogic@0
|
203
|
lbajardsilogic@0
|
204 case dBScale:
|
lbajardsilogic@0
|
205 vy = minY + height - dBscale(value, height, maxVal, minVal);
|
lbajardsilogic@0
|
206 break;
|
lbajardsilogic@0
|
207 }
|
lbajardsilogic@0
|
208
|
lbajardsilogic@0
|
209 return vy;
|
lbajardsilogic@0
|
210 }
|