kwave  18.07.70
Kwave::LevelMeter Class Reference

#include <LevelMeter.h>

Inheritance diagram for Kwave::LevelMeter:
Inheritance graph
Collaboration diagram for Kwave::LevelMeter:
Collaboration graph

Public Slots

virtual void setTracks (unsigned int tracks)
 
virtual void setSampleRate (double rate)
 
virtual void updateTrack (unsigned int track, const Kwave::SampleArray &buffer)
 
virtual void reset ()
 
virtual void drawContents ()
 

Public Member Functions

 LevelMeter (QWidget *parent)
 
virtual ~LevelMeter () Q_DECL_OVERRIDE
 
virtual void paintEvent (QPaintEvent *) Q_DECL_OVERRIDE
 
virtual void resizeEvent (QResizeEvent *) Q_DECL_OVERRIDE
 

Protected Slots

virtual void timedUpdate ()
 

Protected Member Functions

virtual void enqueue (unsigned int track, float fast, float peak, unsigned int queue_depth)
 
virtual bool dequeue (unsigned int track, float &fast, float &peak)
 
void drawScale (QPainter &p)
 

Private Attributes

int m_tracks
 
float m_sample_rate
 
QVector< float > m_yf
 
QVector< float > m_yp
 
QVector< QQueue< float > > m_fast_queue
 
QVector< QQueue< float > > m_peak_queue
 
QVector< float > m_current_fast
 
QVector< float > m_current_peak
 
QTimer * m_timer
 
QColor m_color_low
 
QColor m_color_normal
 
QColor m_color_high
 

Detailed Description

Definition at line 39 of file LevelMeter.h.

Constructor & Destructor Documentation

◆ LevelMeter()

Kwave::LevelMeter::LevelMeter ( QWidget *  parent)
explicit

Constructor

Definition at line 54 of file LevelMeter.cpp.

References Kwave::connect(), m_timer, and timedUpdate().

55  :QWidget(parent),
56  m_tracks(0), m_sample_rate(0), m_yf(), m_yp(),
59  m_color_low(Qt::green),
60  m_color_normal(Qt::yellow),
61  m_color_high(Qt::red)
62 {
63  setAttribute(Qt::WA_NoBackground);
64  m_timer = new QTimer(this);
65  Q_ASSERT(m_timer);
66  connect(m_timer, SIGNAL(timeout()),
67  this, SLOT(timedUpdate()));
68 }
QVector< float > m_yp
Definition: LevelMeter.h:135
QVector< float > m_yf
Definition: LevelMeter.h:132
QColor m_color_normal
Definition: LevelMeter.h:156
QVector< float > m_current_fast
Definition: LevelMeter.h:144
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
QVector< QQueue< float > > m_peak_queue
Definition: LevelMeter.h:141
QVector< QQueue< float > > m_fast_queue
Definition: LevelMeter.h:138
QTimer * m_timer
Definition: LevelMeter.h:150
virtual void timedUpdate()
Definition: LevelMeter.cpp:250
QVector< float > m_current_peak
Definition: LevelMeter.h:147
Here is the call graph for this function:

◆ ~LevelMeter()

Kwave::LevelMeter::~LevelMeter ( )
virtual

Destructor

Definition at line 71 of file LevelMeter.cpp.

References setTracks().

72 {
73  setTracks(0);
74 }
virtual void setTracks(unsigned int tracks)
Definition: LevelMeter.cpp:89
Here is the call graph for this function:

Member Function Documentation

◆ dequeue()

bool Kwave::LevelMeter::dequeue ( unsigned int  track,
float &  fast,
float &  peak 
)
protectedvirtual

Dequeue a pair of fast and peek value of a track.

Parameters
trackindex of the track [0...m_tracks-1]
fastreceives the value of the fast level bar [0.0 ... 1.0]
peakreceives value of the peak level [0.0 ... 1.0]
Returns
true if there was something to dequeue, false if the queue was empty.
Note
fast and peak will not be modified if the queue was empty

Definition at line 226 of file LevelMeter.cpp.

References m_fast_queue, m_peak_queue, m_tracks, and Kwave::toInt().

Referenced by timedUpdate().

227 {
228  Q_ASSERT(m_peak_queue.size() == m_fast_queue.size());
229  Q_ASSERT(m_fast_queue.size() >= m_tracks);
230  Q_ASSERT(m_peak_queue.size() >= m_tracks);
231  if ((Kwave::toInt(track) >= m_tracks) ||
232  (m_fast_queue.size() < m_tracks) ||
233  (m_peak_queue.size() < m_tracks)) return false;
234  Q_ASSERT(m_peak_queue[track].size() == m_fast_queue[track].size());
235  if (m_peak_queue[track].size() != m_fast_queue[track].size())
236  return false;
237 
238  // check if the queues are empty
239  if (m_fast_queue[track].isEmpty()) return false;
240  if (m_peak_queue[track].isEmpty()) return false;
241 
242  // get the values from the front of the queue
243  fast = m_fast_queue[track].dequeue();
244  peak = m_peak_queue[track].dequeue();
245 
246  return true;
247 }
QVector< QQueue< float > > m_peak_queue
Definition: LevelMeter.h:141
QVector< QQueue< float > > m_fast_queue
Definition: LevelMeter.h:138
int toInt(T x)
Definition: Utils.h:127
Here is the call graph for this function:
Here is the caller graph for this function:

◆ drawContents

void Kwave::LevelMeter::drawContents ( )
virtualslot

Redraws the whole widget

Author
(original idea taken from) Rik Hemsley (rikkus) rik@k.nosp@m.de.o.nosp@m.rg Copyright 2002

Definition at line 344 of file LevelMeter.cpp.

References background, drawScale(), m_color_high, m_color_low, m_color_normal, m_current_fast, m_current_peak, m_tracks, rect(), and Kwave::toUint().

Referenced by paintEvent().

345 {
346  QPainter p;
347  int track;
348 
349  Q_ASSERT(width() > 0);
350  Q_ASSERT(height() > 0);
351 
352  p.begin(this);
353 
354  // fill the background
355  p.fillRect(rect(), palette().background().color());
356 
357  const unsigned int border = 4;
358  const unsigned int cell = 3;
359  const unsigned int w = width() - (border * 2) - (cell * 2);
360  const unsigned int h = (height() - border) / (m_tracks ? m_tracks : 1);
361 
362  const unsigned int w_low = Kwave::toUint(w * 0.7); // -3 dB
363  const unsigned int w_high = Kwave::toUint(w * 0.85); // -1.5dB
364 
365  for (track = 0; track < m_tracks; ++track) {
366  // show a bar up to the "fast" value
367  const unsigned int fast = Kwave::toUint(m_current_fast[track] * w);
368  for (unsigned int i = 0; i < w; i += cell * 2) {
369  QColor color;
370  if (i >= w_high)
371  color = m_color_high;
372  else if (i >= w_low)
373  color = m_color_normal;
374  else
375  color = m_color_low;
376 
377  p.fillRect(
378  border + cell + i,
379  border + (track * h),
380  cell, h-border,
381  (i > fast) ? color.dark() : color
382  );
383  }
384 
385  // draw the peak value
386  unsigned int peak = Kwave::toUint(m_current_peak[track] * w);
387  QColor peak_color;
388  if (peak >= w_high)
389  peak_color = m_color_high;
390  else if (peak >= w_low)
391  peak_color = m_color_normal;
392  else
393  peak_color = m_color_low;
394 
395  p.fillRect(
396  border + cell + peak,
397  border + (track * h),
398  cell, h - border,
399  peak_color.light()
400  );
401  }
402 
403  // draw the scale / dB numbers
404  drawScale(p);
405 
406  p.end();
407 }
QColor m_color_normal
Definition: LevelMeter.h:156
QVector< float > m_current_fast
Definition: LevelMeter.h:144
static const char * background[]
unsigned int toUint(T x)
Definition: Utils.h:109
QVector< float > m_current_peak
Definition: LevelMeter.h:147
static double rect(double param)
Definition: Functions.cpp:29
void drawScale(QPainter &p)
Definition: LevelMeter.cpp:272
Here is the call graph for this function:
Here is the caller graph for this function:

◆ drawScale()

void Kwave::LevelMeter::drawScale ( QPainter &  p)
protected

Draw some scale into the meter, using 3dB steps

Parameters
pan already opened QPainter

Definition at line 272 of file LevelMeter.cpp.

References background, rect(), and Kwave::toInt().

Referenced by drawContents().

273 {
274  // draw the levels in 3dB steps, like -12dB -9dB -6dB -3dB and 0dB
275  QFontMetrics fm = p.fontMetrics();
276  QRect rect = fm.boundingRect(i18n("%1 dB", -999));
277 
278  const int border = 4;
279  const int w = width() - 2 * border;
280  const int h = height();
281  const int tw = rect.width();
282  const int th = rect.height();
283  const int y = ((height() - th) / 2);
284  const int r = 5;
285  int db = 0;
286  int right = width();
287  const QColor textcolor = palette().buttonText().color();
288  const QBrush brush(palette().background().color());
289 
290  Q_ASSERT(th);
291  if (!th) return;
292 
293  p.setBrush(brush);
294  while (right > tw + border) {
295  // find the first position in dB which is not overlapping
296  // the last output position
297  QString txt;
298  int x;
299  do {
300  txt = i18n("%1 dB", db);
301  x = Kwave::toInt(static_cast<double>(w) *
302  pow(10.0, static_cast<double>(db) / 20.0));
303  db -= 3; // one step left == -3dB
304  } while ((x > right) && (x >= tw));
305  if (x < tw) break;
306 
307  // calculate the text position
308  int text_width = fm.boundingRect(txt).width();
309  x += border;
310  x -= text_width + 3;
311 
312  // dim the text background area
313  p.setOpacity(0.66);
314  p.setPen(Qt::NoPen);
315  p.drawRoundRect(x - r, y - r, text_width + 2 * r, th + 2 * r,
316  (200 * r) / th, (200 * r) / th);
317 
318  // draw the text, right/center aligned
319  p.setOpacity(1.0);
320  p.setPen(textcolor);
321  p.drawText(x, 1, text_width, h, Qt::AlignCenter, txt);
322 
323  // new right border == one character left from last one
324  right = x - th;
325  }
326 
327 }
static const char * background[]
int toInt(T x)
Definition: Utils.h:127
static double rect(double param)
Definition: Functions.cpp:29
Here is the call graph for this function:
Here is the caller graph for this function:

◆ enqueue()

void Kwave::LevelMeter::enqueue ( unsigned int  track,
float  fast,
float  peak,
unsigned int  queue_depth 
)
protectedvirtual

Enqueue a pair of fast and peak value of a track for later timed update. If the queue already contains the maximum number of elements, the oldest ones will be removed.

Parameters
trackindex of the track [0...m_tracks-1]
fastvalue of the fast level bar [0.0 ... 1.0]
peakvalue of the peak level [0.0 ... 1.0]
queue_depthmaximum number of elements to queue

Definition at line 192 of file LevelMeter.cpp.

References m_fast_queue, m_peak_queue, m_timer, m_tracks, Kwave::toInt(), and UPDATES_PER_SECOND.

Referenced by updateTrack().

194 {
195  Q_ASSERT(Kwave::toInt(track) < m_tracks);
196  Q_ASSERT(m_peak_queue.size() == m_fast_queue.size());
197  Q_ASSERT(m_fast_queue.size() >= m_tracks);
198  Q_ASSERT(m_peak_queue.size() >= m_tracks);
199  if ((Kwave::toInt(track) >= m_tracks) ||
200  (m_fast_queue.size() < Kwave::toInt(m_tracks)) ||
201  (m_peak_queue.size() < m_tracks)) return;
202  Q_ASSERT(m_peak_queue[track].size() == m_fast_queue[track].size());
203  if (m_peak_queue[track].size() != m_fast_queue[track].size()) return;
204 
205  // remove old entries
206  while (m_fast_queue[track].size() > Kwave::toInt(queue_depth)) {
207 // qDebug("LevelMeter::enqueue(): purging old entry (%u/%u)",
208 // m_fast_queue.size(), queue_depth);
209  m_fast_queue[track].dequeue();
210  m_peak_queue[track].dequeue();
211  }
212 
213  // put into the queue
214  m_fast_queue[track].enqueue(fast);
215  m_peak_queue[track].enqueue(peak);
216 
217  // restart the timer if necessary
218  if (m_timer && !m_timer->isActive()) {
219  m_timer->setInterval(Kwave::toInt(1000 / UPDATES_PER_SECOND));
220  m_timer->setSingleShot(false);
221  m_timer->start();
222  }
223 }
static const float UPDATES_PER_SECOND
Definition: LevelMeter.cpp:39
QVector< QQueue< float > > m_peak_queue
Definition: LevelMeter.h:141
QVector< QQueue< float > > m_fast_queue
Definition: LevelMeter.h:138
QTimer * m_timer
Definition: LevelMeter.h:150
int toInt(T x)
Definition: Utils.h:127
Here is the call graph for this function:
Here is the caller graph for this function:

◆ paintEvent()

void Kwave::LevelMeter::paintEvent ( QPaintEvent *  )
virtual
See also
QWidget::paintEvent

Definition at line 77 of file LevelMeter.cpp.

References drawContents().

78 {
79  drawContents();
80 }
virtual void drawContents()
Definition: LevelMeter.cpp:344
Here is the call graph for this function:

◆ reset

void Kwave::LevelMeter::reset ( )
virtualslot

Resets all meters to zero

Definition at line 174 of file LevelMeter.cpp.

References m_current_fast, m_current_peak, m_fast_queue, m_peak_queue, m_timer, m_tracks, m_yf, and m_yp.

Referenced by setTracks().

175 {
176  if (m_timer && m_timer->isActive()) m_timer->stop();
177 
178  m_yf.resize(m_tracks);
179  m_yf.fill(0.0);
180  m_fast_queue.resize(m_tracks);
181  m_current_fast.resize(m_tracks);
182  m_current_fast.fill(0.0);
183 
184  m_yp.resize(m_tracks);
185  m_yp.fill(0.0);
186  m_peak_queue.resize(m_tracks);
187  m_current_peak.resize(m_tracks);
188  m_current_peak.fill(0.0);
189 }
QVector< float > m_yp
Definition: LevelMeter.h:135
QVector< float > m_yf
Definition: LevelMeter.h:132
QVector< float > m_current_fast
Definition: LevelMeter.h:144
QVector< QQueue< float > > m_peak_queue
Definition: LevelMeter.h:141
QVector< QQueue< float > > m_fast_queue
Definition: LevelMeter.h:138
QTimer * m_timer
Definition: LevelMeter.h:150
QVector< float > m_current_peak
Definition: LevelMeter.h:147
Here is the caller graph for this function:

◆ resizeEvent()

void Kwave::LevelMeter::resizeEvent ( QResizeEvent *  )
virtual
See also
QWidget::resizeEvent

Definition at line 83 of file LevelMeter.cpp.

84 {
85  repaint();
86 }

◆ setSampleRate

void Kwave::LevelMeter::setSampleRate ( double  rate)
virtualslot

sets the sample rate for interpreting the samples used for updating the display.

Definition at line 97 of file LevelMeter.cpp.

References m_sample_rate.

98 {
99  if (qFuzzyCompare(static_cast<float>(rate), m_sample_rate)) return;
100  m_sample_rate = static_cast<float>(rate);
101 }

◆ setTracks

void Kwave::LevelMeter::setTracks ( unsigned int  tracks)
virtualslot

sets the number of tracks that the display should use

Definition at line 89 of file LevelMeter.cpp.

References m_tracks, reset(), and Kwave::toInt().

Referenced by ~LevelMeter().

90 {
91  if (Kwave::toInt(tracks) == m_tracks) return;
92  m_tracks = tracks;
93  reset(); // re-create all arrays etc.
94 }
int toInt(T x)
Definition: Utils.h:127
virtual void reset()
Definition: LevelMeter.cpp:174
Here is the call graph for this function:
Here is the caller graph for this function:

◆ timedUpdate

void Kwave::LevelMeter::timedUpdate ( )
protectedvirtualslot

Called via m_timer to update the bar(s)

Definition at line 250 of file LevelMeter.cpp.

References dequeue(), m_current_fast, m_current_peak, and m_tracks.

Referenced by LevelMeter().

251 {
252  float fast;
253  float peak;
254  bool need_update = false;
255 
256  for (int track=0; track < m_tracks; track++) {
257  if (dequeue(track, fast, peak)) {
258  // set the new "current" values
259  m_current_fast[track] = fast;
260  m_current_peak[track] = peak;
261 
262  // remember that we have to update the display
263  need_update = true;
264  }
265  }
266 
267  // refresh the display if needed
268  if (need_update) repaint();
269 }
QVector< float > m_current_fast
Definition: LevelMeter.h:144
virtual bool dequeue(unsigned int track, float &fast, float &peak)
Definition: LevelMeter.cpp:226
QVector< float > m_current_peak
Definition: LevelMeter.h:147
Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateTrack

void Kwave::LevelMeter::updateTrack ( unsigned int  track,
const Kwave::SampleArray buffer 
)
virtualslot

Updates a apecific track

Parameters
trackindex of the track
bufferarray with samples

Definition at line 104 of file LevelMeter.cpp.

References enqueue(), F_FAST_DECAY, F_FAST_RISE, F_PEAK_DECAY, F_PEAK_RISE, m_sample_rate, m_tracks, m_yf, m_yp, sample2float(), Kwave::SampleArray::size(), Kwave::toInt(), Kwave::toUint(), and UPDATES_PER_SECOND.

106 {
107  Q_ASSERT(Kwave::toInt(track) < m_tracks);
108  if (Kwave::toInt(track) >= m_tracks) return;
109 
110  // calculate the number of samples per update (approx)
111  const unsigned int samples = buffer.size();
112  const unsigned int samples_per_update = Kwave::toUint(
113  rintf(ceilf(m_sample_rate / UPDATES_PER_SECOND)));
114  unsigned int next_fraction = samples_per_update;
115  const unsigned int queue_depth = ((samples / samples_per_update) + 2);
116 
117  /* fast update: rise */
118  float Fg = F_FAST_RISE / m_sample_rate;
119  float n = 1.0f / tanf(float(M_PI) * Fg);
120  const float a0_fr = 1.0f / (1.0f + n);
121  const float b1_fr = (1.0f - n) / (1.0f + n);
122 
123  /* fast update: decay */
125  n = 1.0f / tanf(float(M_PI) * Fg);
126  const float a0_fd = 1.0f / (1.0f + n);
127  const float b1_fd = (1.0f - n) / (1.0f + n);
128 
129  /* peak value: rise */
130  Fg = F_PEAK_RISE / m_sample_rate;
131  n = 1.0f / tanf(float(M_PI) * Fg);
132  const float a0_pr = 1.0f / (1.0f + n);
133  const float b1_pr = (1.0f - n) / (1.0f + n);
134 
135  /* peak value: decay */
137  n = 1.0f / tanf(float(M_PI) * Fg);
138  const float a0_pd = 1.0f / (1.0f + n);
139  const float b1_pd = (1.0f - n) / (1.0f + n);
140 
141  float yf = m_yf[track];
142  float yp = m_yp[track];
143  float last_x = yf;
144  for (unsigned int t = 0; t < samples; ++t) {
145  float x = fabsf(sample2float(buffer[t])); /* rectifier */
146 
147  /* fast value */
148  if (x > yf) yf = (a0_fr * x) + (a0_fr * last_x) - (b1_fr * yf); // rise
149  yf = (a0_fd * x) + (a0_fd * last_x) - (b1_fd * yf); // decay
150 
151  /* peak value */
152  if (x > yp) yp = (a0_pr * x) + (a0_pr * last_x) - (b1_pr * yp); // rise
153  yp = (a0_pd * x) + (a0_pd * last_x) - (b1_pd * yp); // decay
154 
155  // remember x[t-1]
156  last_x = x;
157 
158  // enqueue new values if limit reached
159  if ((t > next_fraction) || (t == samples-1)) {
160  next_fraction += samples_per_update;
161 
162  // merge the last fractional part to the last normal part
163  if ((next_fraction + samples_per_update) > samples)
164  next_fraction = samples-1;
165 
166  enqueue(track, yf, yp, queue_depth);
167  }
168  }
169  m_yf[track] = yf;
170  m_yp[track] = yp;
171 }
virtual void enqueue(unsigned int track, float fast, float peak, unsigned int queue_depth)
Definition: LevelMeter.cpp:192
static const float F_FAST_RISE
Definition: LevelMeter.cpp:42
static const float UPDATES_PER_SECOND
Definition: LevelMeter.cpp:39
QVector< float > m_yp
Definition: LevelMeter.h:135
QVector< float > m_yf
Definition: LevelMeter.h:132
static const float F_FAST_DECAY
Definition: LevelMeter.cpp:45
static const float F_PEAK_DECAY
Definition: LevelMeter.cpp:51
int toInt(T x)
Definition: Utils.h:127
static float sample2float(const sample_t s)
Definition: Sample.h:65
unsigned int size() const
unsigned int toUint(T x)
Definition: Utils.h:109
static const float F_PEAK_RISE
Definition: LevelMeter.cpp:48
Here is the call graph for this function:

Member Data Documentation

◆ m_color_high

QColor Kwave::LevelMeter::m_color_high
private

color high levels, above -1.5dB

Definition at line 159 of file LevelMeter.h.

Referenced by drawContents().

◆ m_color_low

QColor Kwave::LevelMeter::m_color_low
private

color for low levels, below -3dB

Definition at line 153 of file LevelMeter.h.

Referenced by drawContents().

◆ m_color_normal

QColor Kwave::LevelMeter::m_color_normal
private

color for normal levels, -3dB...-1.5dB

Definition at line 156 of file LevelMeter.h.

Referenced by drawContents().

◆ m_current_fast

QVector<float> Kwave::LevelMeter::m_current_fast
private

current fast value for each track

Definition at line 144 of file LevelMeter.h.

Referenced by drawContents(), reset(), and timedUpdate().

◆ m_current_peak

QVector<float> Kwave::LevelMeter::m_current_peak
private

current peak value for each track

Definition at line 147 of file LevelMeter.h.

Referenced by drawContents(), reset(), and timedUpdate().

◆ m_fast_queue

QVector< QQueue<float> > Kwave::LevelMeter::m_fast_queue
private

queues with fast update values for each track

Definition at line 138 of file LevelMeter.h.

Referenced by dequeue(), enqueue(), and reset().

◆ m_peak_queue

QVector< QQueue<float> > Kwave::LevelMeter::m_peak_queue
private

queues with peak values for each track

Definition at line 141 of file LevelMeter.h.

Referenced by dequeue(), enqueue(), and reset().

◆ m_sample_rate

float Kwave::LevelMeter::m_sample_rate
private

sample rate used for interpreting the received buffers

Definition at line 129 of file LevelMeter.h.

Referenced by setSampleRate(), and updateTrack().

◆ m_timer

QTimer* Kwave::LevelMeter::m_timer
private

timer for display updates

Definition at line 150 of file LevelMeter.h.

Referenced by enqueue(), LevelMeter(), and reset().

◆ m_tracks

int Kwave::LevelMeter::m_tracks
private

number of tracks

Definition at line 126 of file LevelMeter.h.

Referenced by dequeue(), drawContents(), enqueue(), reset(), setTracks(), timedUpdate(), and updateTrack().

◆ m_yf

QVector<float> Kwave::LevelMeter::m_yf
private

last output value of the filter for fast updates

Definition at line 132 of file LevelMeter.h.

Referenced by reset(), and updateTrack().

◆ m_yp

QVector<float> Kwave::LevelMeter::m_yp
private

last output value of the filter for peak updates

Definition at line 135 of file LevelMeter.h.

Referenced by reset(), and updateTrack().


The documentation for this class was generated from the following files: