00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "PaintAssistant.h"
00017
00018 #include "base/AudioLevel.h"
00019
00020 #include <QPaintDevice>
00021 #include <QPainter>
00022
00023 #include <iostream>
00024 #include <cmath>
00025
00026 void
00027 PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect,
00028 float minVal, float maxVal,
00029 Scale scale, int &mult,
00030 std::vector<int> *vy)
00031 {
00032 static float meterdbs[] = { -40, -30, -20, -15, -10,
00033 -5, -3, -2, -1, -0.5, 0 };
00034
00035 int h = rect.height(), w = rect.width();
00036 int textHeight = paint.fontMetrics().height();
00037 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
00038
00039 int lastLabelledY = -1;
00040
00041 int n = 10;
00042 if (vy) vy->clear();
00043
00044 float step = 0;
00045 mult = 1;
00046 if (scale == LinearScale) {
00047 step = (maxVal - minVal) / n;
00048 int round = 0, limit = 10000000;
00049 do {
00050 round = int(minVal + step * mult);
00051 mult *= 10;
00052 } while (!round && mult < limit);
00053 if (round) {
00054 mult /= 10;
00055
00056 step = float(round) / mult;
00057 n = lrintf((maxVal - minVal) / step);
00058 if (mult > 1) {
00059 mult /= 10;
00060 }
00061
00062 }
00063 }
00064
00065 for (int i = 0; i <= n; ++i) {
00066
00067 float val = 0.0, nval = 0.0;
00068 QString text = "";
00069
00070 switch (scale) {
00071
00072 case LinearScale:
00073 val = (minVal + (i * step));
00074 text = QString("%1").arg(mult * val);
00075 break;
00076
00077 case MeterScale:
00078 val = AudioLevel::dB_to_multiplier(meterdbs[i]);
00079 text = QString("%1").arg(meterdbs[i]);
00080 if (i == n) text = "0dB";
00081 if (i == 0) {
00082 text = "-Inf";
00083 val = 0.0;
00084 }
00085 break;
00086
00087 case dBScale:
00088 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10);
00089 text = QString("%1").arg(-(10*n) + i * 10);
00090 if (i == n) text = "0dB";
00091 if (i == 0) {
00092 text = "-Inf";
00093 val = 0.0;
00094 }
00095 break;
00096 }
00097
00098 if (val < minVal || val > maxVal) continue;
00099
00100 int y = getYForValue(scale, val, minVal, maxVal, rect.y(), h);
00101
00102 int ny = y;
00103 if (nval != 0.0) {
00104 ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), h);
00105 }
00106
00107
00108
00109
00110 bool spaceForLabel = (i == 0 ||
00111 abs(y - lastLabelledY) >= textHeight - 1);
00112
00113 if (spaceForLabel) {
00114
00115 int tx = 3;
00116
00117 if (paint.fontMetrics().width(text) < w - 10) {
00118 tx = w - 10 - paint.fontMetrics().width(text);
00119 }
00120
00121 int ty = y;
00122
00123 if (ty < paint.fontMetrics().ascent()) {
00124 ty = paint.fontMetrics().ascent();
00125
00126
00127 } else {
00128 ty += toff;
00129 }
00130
00131 paint.drawText(tx, ty, text);
00132
00133 lastLabelledY = ty - toff;
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 paint.drawLine(w - 7, y, w, y);
00148 if (vy) vy->push_back(y);
00149
00150 if (ny != y) {
00151 paint.drawLine(w - 7, ny, w, ny);
00152 if (vy) vy->push_back(ny);
00153 }
00154
00155 } else {
00156
00157 paint.drawLine(w - 4, y, w, y);
00158 if (vy) vy->push_back(y);
00159
00160 if (ny != y) {
00161 paint.drawLine(w - 4, ny, w, ny);
00162 if (vy) vy->push_back(ny);
00163 }
00164 }
00165 }
00166 }
00167
00168 static int
00169 dBscale(float sample, int m, float maxVal, float minVal)
00170 {
00171 if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal);
00172 float dB = AudioLevel::multiplier_to_dB(sample);
00173 float mindB = AudioLevel::multiplier_to_dB(minVal);
00174 float maxdB = AudioLevel::multiplier_to_dB(maxVal);
00175 if (dB < mindB) return 0;
00176 if (dB > 0.0) return m;
00177 return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1);
00178 }
00179
00180 int
00181 PaintAssistant::getYForValue(Scale scale, float value,
00182 float minVal, float maxVal,
00183 int minY, int height)
00184 {
00185 int vy = 0;
00186
00187
00188
00189
00190 switch (scale) {
00191
00192 case LinearScale:
00193
00194 vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height);
00195 break;
00196
00197 case MeterScale:
00198
00199 vy = minY + height - AudioLevel::multiplier_to_preview
00200 ((value - minVal) / (maxVal - minVal), height);
00201 break;
00202
00203 case dBScale:
00204 vy = minY + height - dBscale(value, height, maxVal, minVal);
00205 break;
00206 }
00207
00208 return vy;
00209 }