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