svgui  1.9
PaintAssistant.cpp
Go to the documentation of this file.
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 }