annotate layer/PaintAssistant.cpp @ 959:2633a1d73e39

Address #1214, layer import produces wrong layer type. We needed a more principled approach to making sure the format gets updated properly and the dialog elements are consistent (basically separating making the dialog elements consistent from subsequently updating the format). This change should provide that, though there may be gotchas still.
author Chris Cannam
date Tue, 12 May 2015 12:31:37 +0100
parents b66fb15de477
children ee01a4062747
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@230 24 #include <cmath>
Chris@198 25
Chris@195 26 void
Chris@195 27 PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect,
Chris@905 28 double minVal, double maxVal,
Chris@220 29 Scale scale, int &mult,
Chris@220 30 std::vector<int> *vy)
Chris@195 31 {
Chris@905 32 static double meterdbs[] = { -40, -30, -20, -15, -10,
Chris@195 33 -5, -3, -2, -1, -0.5, 0 };
Chris@195 34
Chris@195 35 int h = rect.height(), w = rect.width();
Chris@195 36 int textHeight = paint.fontMetrics().height();
Chris@195 37 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
Chris@195 38
Chris@195 39 int lastLabelledY = -1;
Chris@195 40
Chris@195 41 int n = 10;
Chris@195 42 if (vy) vy->clear();
Chris@195 43
Chris@905 44 double step = 0;
Chris@220 45 mult = 1;
Chris@220 46 if (scale == LinearScale) {
Chris@220 47 step = (maxVal - minVal) / n;
Chris@220 48 int round = 0, limit = 10000000;
Chris@220 49 do {
Chris@220 50 round = int(minVal + step * mult);
Chris@220 51 mult *= 10;
Chris@220 52 } while (!round && mult < limit);
Chris@220 53 if (round) {
Chris@220 54 mult /= 10;
Chris@682 55 // cerr << "\n\nstep goes from " << step;
Chris@905 56 step = double(round) / mult;
Chris@905 57 n = int(lrint((maxVal - minVal) / step));
Chris@220 58 if (mult > 1) {
Chris@220 59 mult /= 10;
Chris@220 60 }
Chris@682 61 // cerr << " to " << step << " (n = " << n << ")" << endl;
Chris@220 62 }
Chris@220 63 }
Chris@220 64
Chris@195 65 for (int i = 0; i <= n; ++i) {
Chris@195 66
Chris@905 67 double val = 0.0, nval = 0.0;
Chris@195 68 QString text = "";
Chris@195 69
Chris@195 70 switch (scale) {
Chris@195 71
Chris@195 72 case LinearScale:
Chris@220 73 val = (minVal + (i * step));
Chris@220 74 text = QString("%1").arg(mult * val);
Chris@195 75 break;
Chris@195 76
Chris@195 77 case MeterScale: // ... min, max
Chris@195 78 val = AudioLevel::dB_to_multiplier(meterdbs[i]);
Chris@195 79 text = QString("%1").arg(meterdbs[i]);
Chris@195 80 if (i == n) text = "0dB";
Chris@195 81 if (i == 0) {
Chris@195 82 text = "-Inf";
Chris@195 83 val = 0.0;
Chris@195 84 }
Chris@195 85 break;
Chris@195 86
Chris@195 87 case dBScale: // ... min, max
Chris@195 88 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10);
Chris@195 89 text = QString("%1").arg(-(10*n) + i * 10);
Chris@195 90 if (i == n) text = "0dB";
Chris@195 91 if (i == 0) {
Chris@195 92 text = "-Inf";
Chris@195 93 val = 0.0;
Chris@195 94 }
Chris@195 95 break;
Chris@195 96 }
Chris@195 97
Chris@195 98 if (val < minVal || val > maxVal) continue;
Chris@195 99
Chris@198 100 int y = getYForValue(scale, val, minVal, maxVal, rect.y(), h);
Chris@195 101
Chris@195 102 int ny = y;
Chris@195 103 if (nval != 0.0) {
Chris@198 104 ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), h);
Chris@195 105 }
Chris@195 106
Chris@587 107 // SVDEBUG << "PaintAssistant::paintVerticalLevelScale: val = "
Chris@585 108 // << val << ", y = " << y << ", h = " << h << endl;
Chris@198 109
Chris@195 110 bool spaceForLabel = (i == 0 ||
Chris@195 111 abs(y - lastLabelledY) >= textHeight - 1);
Chris@195 112
Chris@195 113 if (spaceForLabel) {
Chris@195 114
Chris@195 115 int tx = 3;
Chris@220 116 // if (scale != LinearScale) {
Chris@220 117 if (paint.fontMetrics().width(text) < w - 10) {
Chris@195 118 tx = w - 10 - paint.fontMetrics().width(text);
Chris@195 119 }
Chris@195 120
Chris@195 121 int ty = y;
Chris@198 122
Chris@195 123 if (ty < paint.fontMetrics().ascent()) {
Chris@195 124 ty = paint.fontMetrics().ascent();
Chris@198 125 // } else if (ty > rect.y() + h - paint.fontMetrics().descent()) {
Chris@198 126 // ty = rect.y() + h - paint.fontMetrics().descent();
Chris@195 127 } else {
Chris@195 128 ty += toff;
Chris@195 129 }
Chris@198 130
Chris@195 131 paint.drawText(tx, ty, text);
Chris@195 132
Chris@195 133 lastLabelledY = ty - toff;
Chris@195 134 /*
Chris@195 135 if (ny != y) {
Chris@195 136 ty = ny;
Chris@195 137 if (ty < paint.fontMetrics().ascent()) {
Chris@195 138 ty = paint.fontMetrics().ascent();
Chris@195 139 } else if (ty > h - paint.fontMetrics().descent()) {
Chris@195 140 ty = h - paint.fontMetrics().descent();
Chris@195 141 } else {
Chris@195 142 ty += toff;
Chris@195 143 }
Chris@195 144 paint.drawText(tx, ty, text);
Chris@195 145 }
Chris@195 146 */
Chris@195 147 paint.drawLine(w - 7, y, w, y);
Chris@195 148 if (vy) vy->push_back(y);
Chris@195 149
Chris@195 150 if (ny != y) {
Chris@195 151 paint.drawLine(w - 7, ny, w, ny);
Chris@195 152 if (vy) vy->push_back(ny);
Chris@195 153 }
Chris@195 154
Chris@195 155 } else {
Chris@195 156
Chris@195 157 paint.drawLine(w - 4, y, w, y);
Chris@195 158 if (vy) vy->push_back(y);
Chris@195 159
Chris@195 160 if (ny != y) {
Chris@195 161 paint.drawLine(w - 4, ny, w, ny);
Chris@195 162 if (vy) vy->push_back(ny);
Chris@195 163 }
Chris@195 164 }
Chris@195 165 }
Chris@195 166 }
Chris@195 167
Chris@195 168 static int
Chris@905 169 dBscale(double sample, int m, double maxVal, double minVal)
Chris@195 170 {
Chris@195 171 if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal);
Chris@905 172 double dB = AudioLevel::multiplier_to_dB(sample);
Chris@905 173 double mindB = AudioLevel::multiplier_to_dB(minVal);
Chris@905 174 double maxdB = AudioLevel::multiplier_to_dB(maxVal);
Chris@195 175 if (dB < mindB) return 0;
Chris@195 176 if (dB > 0.0) return m;
Chris@195 177 return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1);
Chris@195 178 }
Chris@195 179
Chris@195 180 int
Chris@905 181 PaintAssistant::getYForValue(Scale scale, double value,
Chris@905 182 double minVal, double maxVal,
Chris@195 183 int minY, int height)
Chris@195 184 {
Chris@195 185 int vy = 0;
Chris@195 186
Chris@195 187 // int m = height/2;
Chris@195 188 // int my = minY + m;
Chris@195 189
Chris@195 190 switch (scale) {
Chris@195 191
Chris@195 192 case LinearScale:
Chris@195 193 // vy = my - int(m * value);
Chris@195 194 vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height);
Chris@195 195 break;
Chris@195 196
Chris@195 197 case MeterScale:
Chris@195 198 // vy = my - AudioLevel::multiplier_to_preview(value, m);
Chris@195 199 vy = minY + height - AudioLevel::multiplier_to_preview
Chris@195 200 ((value - minVal) / (maxVal - minVal), height);
Chris@195 201 break;
Chris@195 202
Chris@195 203 case dBScale:
Chris@195 204 vy = minY + height - dBscale(value, height, maxVal, minVal);
Chris@195 205 break;
Chris@195 206 }
Chris@195 207
Chris@195 208 return vy;
Chris@195 209 }