svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-2007 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 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 // cerr << "\n\nstep goes from " << step; 00056 step = float(round) / mult; 00057 n = lrintf((maxVal - minVal) / step); 00058 if (mult > 1) { 00059 mult /= 10; 00060 } 00061 // cerr << " to " << step << " (n = " << n << ")" << endl; 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: // ... min, max 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: // ... min, max 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 // SVDEBUG << "PaintAssistant::paintVerticalLevelScale: val = " 00108 // << val << ", y = " << y << ", h = " << h << endl; 00109 00110 bool spaceForLabel = (i == 0 || 00111 abs(y - lastLabelledY) >= textHeight - 1); 00112 00113 if (spaceForLabel) { 00114 00115 int tx = 3; 00116 // if (scale != LinearScale) { 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 // } else if (ty > rect.y() + h - paint.fontMetrics().descent()) { 00126 // ty = rect.y() + h - paint.fontMetrics().descent(); 00127 } else { 00128 ty += toff; 00129 } 00130 00131 paint.drawText(tx, ty, text); 00132 00133 lastLabelledY = ty - toff; 00134 /* 00135 if (ny != y) { 00136 ty = ny; 00137 if (ty < paint.fontMetrics().ascent()) { 00138 ty = paint.fontMetrics().ascent(); 00139 } else if (ty > h - paint.fontMetrics().descent()) { 00140 ty = h - paint.fontMetrics().descent(); 00141 } else { 00142 ty += toff; 00143 } 00144 paint.drawText(tx, ty, text); 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 // int m = height/2; 00188 // int my = minY + m; 00189 00190 switch (scale) { 00191 00192 case LinearScale: 00193 // vy = my - int(m * value); 00194 vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height); 00195 break; 00196 00197 case MeterScale: 00198 // vy = my - AudioLevel::multiplier_to_preview(value, m); 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 }