annotate layer/PaintAssistant.cpp @ 221:9e739f92c0b8

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