lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006-2007 Chris Cannam and QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include "PaintAssistant.h" lbajardsilogic@0: lbajardsilogic@0: #include "base/AudioLevel.h" lbajardsilogic@0: #include "system/System.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect, lbajardsilogic@0: float minVal, float maxVal, lbajardsilogic@0: Scale scale, int &mult, lbajardsilogic@0: std::vector *vy) lbajardsilogic@0: { lbajardsilogic@0: static float meterdbs[] = { -40, -30, -20, -15, -10, lbajardsilogic@0: -5, -3, -2, -1, -0.5, 0 }; lbajardsilogic@0: lbajardsilogic@0: int h = rect.height(), w = rect.width(); lbajardsilogic@0: int textHeight = paint.fontMetrics().height(); lbajardsilogic@0: int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1; lbajardsilogic@0: lbajardsilogic@0: int lastLabelledY = -1; lbajardsilogic@0: lbajardsilogic@0: int n = 10; lbajardsilogic@0: if (vy) vy->clear(); lbajardsilogic@0: lbajardsilogic@0: float step = 0; lbajardsilogic@0: mult = 1; lbajardsilogic@0: if (scale == LinearScale) { lbajardsilogic@0: step = (maxVal - minVal) / n; lbajardsilogic@0: int round = 0, limit = 10000000; lbajardsilogic@0: do { lbajardsilogic@0: round = int(minVal + step * mult); lbajardsilogic@0: mult *= 10; lbajardsilogic@0: } while (!round && mult < limit); lbajardsilogic@0: if (round) { lbajardsilogic@0: mult /= 10; lbajardsilogic@0: // std::cerr << "\n\nstep goes from " << step; lbajardsilogic@0: step = float(round) / mult; lbajardsilogic@0: n = lrintf((maxVal - minVal) / step); lbajardsilogic@0: if (mult > 1) { lbajardsilogic@0: mult /= 10; lbajardsilogic@0: } lbajardsilogic@0: // std::cerr << " to " << step << " (n = " << n << ")" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i <= n; ++i) { lbajardsilogic@0: lbajardsilogic@0: float val = 0.0, nval = 0.0; lbajardsilogic@0: QString text = ""; lbajardsilogic@0: lbajardsilogic@0: switch (scale) { lbajardsilogic@0: lbajardsilogic@0: case LinearScale: lbajardsilogic@0: val = (minVal + (i * step)); lbajardsilogic@0: text = QString("%1").arg(mult * val); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case MeterScale: // ... min, max lbajardsilogic@0: val = AudioLevel::dB_to_multiplier(meterdbs[i]); lbajardsilogic@0: text = QString("%1").arg(meterdbs[i]); lbajardsilogic@0: if (i == n) text = "0dB"; lbajardsilogic@0: if (i == 0) { lbajardsilogic@0: text = "-Inf"; lbajardsilogic@0: val = 0.0; lbajardsilogic@0: } lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case dBScale: // ... min, max lbajardsilogic@0: val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10); lbajardsilogic@0: text = QString("%1").arg(-(10*n) + i * 10); lbajardsilogic@0: if (i == n) text = "0dB"; lbajardsilogic@0: if (i == 0) { lbajardsilogic@0: text = "-Inf"; lbajardsilogic@0: val = 0.0; lbajardsilogic@0: } lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (val < minVal || val > maxVal) continue; lbajardsilogic@0: lbajardsilogic@0: int y = getYForValue(scale, val, minVal, maxVal, rect.y(), h); lbajardsilogic@0: lbajardsilogic@0: int ny = y; lbajardsilogic@0: if (nval != 0.0) { lbajardsilogic@0: ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), h); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "PaintAssistant::paintVerticalLevelScale: val = " lbajardsilogic@0: // << val << ", y = " << y << ", h = " << h << std::endl; lbajardsilogic@0: lbajardsilogic@0: bool spaceForLabel = (i == 0 || lbajardsilogic@0: abs(y - lastLabelledY) >= textHeight - 1); lbajardsilogic@0: lbajardsilogic@0: if (spaceForLabel) { lbajardsilogic@0: lbajardsilogic@0: int tx = 3; lbajardsilogic@0: // if (scale != LinearScale) { lbajardsilogic@0: if (paint.fontMetrics().width(text) < w - 10) { lbajardsilogic@0: tx = w - 10 - paint.fontMetrics().width(text); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int ty = y; lbajardsilogic@0: lbajardsilogic@0: if (ty < paint.fontMetrics().ascent()) { lbajardsilogic@0: ty = paint.fontMetrics().ascent(); lbajardsilogic@0: // } else if (ty > rect.y() + h - paint.fontMetrics().descent()) { lbajardsilogic@0: // ty = rect.y() + h - paint.fontMetrics().descent(); lbajardsilogic@0: } else { lbajardsilogic@0: ty += toff; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: paint.drawText(tx, ty, text); lbajardsilogic@0: lbajardsilogic@0: lastLabelledY = ty - toff; lbajardsilogic@0: /* lbajardsilogic@0: if (ny != y) { lbajardsilogic@0: ty = ny; lbajardsilogic@0: if (ty < paint.fontMetrics().ascent()) { lbajardsilogic@0: ty = paint.fontMetrics().ascent(); lbajardsilogic@0: } else if (ty > h - paint.fontMetrics().descent()) { lbajardsilogic@0: ty = h - paint.fontMetrics().descent(); lbajardsilogic@0: } else { lbajardsilogic@0: ty += toff; lbajardsilogic@0: } lbajardsilogic@0: paint.drawText(tx, ty, text); lbajardsilogic@0: } lbajardsilogic@0: */ lbajardsilogic@0: paint.drawLine(w - 7, y, w, y); lbajardsilogic@0: if (vy) vy->push_back(y); lbajardsilogic@0: lbajardsilogic@0: if (ny != y) { lbajardsilogic@0: paint.drawLine(w - 7, ny, w, ny); lbajardsilogic@0: if (vy) vy->push_back(ny); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: paint.drawLine(w - 4, y, w, y); lbajardsilogic@0: if (vy) vy->push_back(y); lbajardsilogic@0: lbajardsilogic@0: if (ny != y) { lbajardsilogic@0: paint.drawLine(w - 4, ny, w, ny); lbajardsilogic@0: if (vy) vy->push_back(ny); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: static int lbajardsilogic@0: dBscale(float sample, int m, float maxVal, float minVal) lbajardsilogic@0: { lbajardsilogic@0: if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal); lbajardsilogic@0: float dB = AudioLevel::multiplier_to_dB(sample); lbajardsilogic@0: float mindB = AudioLevel::multiplier_to_dB(minVal); lbajardsilogic@0: float maxdB = AudioLevel::multiplier_to_dB(maxVal); lbajardsilogic@0: if (dB < mindB) return 0; lbajardsilogic@0: if (dB > 0.0) return m; lbajardsilogic@0: return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: PaintAssistant::getYForValue(Scale scale, float value, lbajardsilogic@0: float minVal, float maxVal, lbajardsilogic@0: int minY, int height) lbajardsilogic@0: { lbajardsilogic@0: int vy = 0; lbajardsilogic@0: lbajardsilogic@0: // int m = height/2; lbajardsilogic@0: // int my = minY + m; lbajardsilogic@0: lbajardsilogic@0: switch (scale) { lbajardsilogic@0: lbajardsilogic@0: case LinearScale: lbajardsilogic@0: // vy = my - int(m * value); lbajardsilogic@0: vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case MeterScale: lbajardsilogic@0: // vy = my - AudioLevel::multiplier_to_preview(value, m); lbajardsilogic@0: vy = minY + height - AudioLevel::multiplier_to_preview lbajardsilogic@0: ((value - minVal) / (maxVal - minVal), height); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case dBScale: lbajardsilogic@0: vy = minY + height - dBscale(value, height, maxVal, minVal); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return vy; lbajardsilogic@0: }