kwave  18.07.70
TrackPixmap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  TrackPixmap.cpp - buffered pixmap for displaying a kwave track
3  -------------------
4  begin : Tue Mar 20 2001
5  copyright : (C) 2001 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <math.h>
21 #include <new>
22 
23 #include <QMutexLocker>
24 #include <QPainter>
25 #include <QPolygon>
26 #include <QTime>
27 
28 #include "libkwave/SampleReader.h"
29 #include "libkwave/Track.h"
30 #include "libkwave/Utils.h"
31 
32 #include "libgui/TrackPixmap.h"
33 
41 #define INTERPOLATION_PRECISION 4
42 
47 #define INTERPOLATION_ZOOM 0.10
48 
49 //***************************************************************************
51  :QObject(), m_pixmap(), m_track(track), m_offset(0), m_zoom(0.0),
52  m_vertical_zoom(1.0), m_minmax_mode(false),
53  m_sample_buffer(), m_min_buffer(), m_max_buffer(),
54  m_modified(false), m_valid(0), m_lock_buffer(),
55  m_interpolation_order(0), m_interpolation_alpha(),
56  m_colors(Kwave::Colors::Normal)
57 {
58  // connect all the notification signals of the track
59  connect(&track,
60  SIGNAL(sigSamplesInserted(Kwave::Track *, sample_index_t,
61  sample_index_t)), this,
64  connect(&track, SIGNAL(sigSamplesDeleted(Kwave::Track *, sample_index_t,
67  connect(&track, SIGNAL(sigSamplesModified(Kwave::Track *, sample_index_t,
70  connect(&track, SIGNAL(sigSelectionChanged(bool)),
71  this, SLOT(selectionChanged()));
72 }
73 
74 //***************************************************************************
76 {
77  QMutexLocker lock(&m_lock_buffer);
78  m_interpolation_alpha.clear();
79 }
80 
81 //***************************************************************************
83 {
84  QMutexLocker lock(&m_lock_buffer);
85  if (offset == m_offset) return; // no change
86  const unsigned int buflen = m_valid.size();
87 
88  if (m_minmax_mode) {
89  // move content of min and max buffer
90  // one buffer element = one screen pixel
91  Q_ASSERT(buflen == m_min_buffer.size());
92  Q_ASSERT(buflen == m_max_buffer.size());
93  if ((buflen != m_min_buffer.size()) ||
94  (buflen != m_max_buffer.size()))
95  {
96  qDebug("TrackPixmap::setOffset(): buflen = %u", buflen);
97  qDebug("TrackPixmap::setOffset(): min_buffer : %u",
98  m_min_buffer.size());
99  qDebug("TrackPixmap::setOffset(): max_buffer : %u",
100  m_max_buffer.size());
101  }
102 
103  // check for misaligned offset changes
104  if (( offset % static_cast<sample_index_t>(ceil(m_zoom))) !=
105  (m_offset % static_cast<sample_index_t>(ceil(m_zoom)))) {
106 
107 #ifdef CURRENTLY_UNUSED
108 // this will become interesting later, with the offset/zoom optimizations
109  qWarning("TrackPixmap::setOffset(): oh nooo, "\
110  "offset %u is misaligned by %u sample(s), please fix this!",
111  offset, offset % pixels2samples(1));
112  qWarning("TrackPixmap::setOffset(): "\
113  "now I have to throw away the whole buffer :-((");
114 
115  qDebug("TrackPixmap::setOffset(%u): "\
116  "misaligned->invalidating buffer", offset);
117 #endif
119  } else if (offset > m_offset) {
120  // move left
121  int diff = samples2pixels(offset - m_offset);
122 // qDebug("TrackPixmap::setOffset(): moving left (min/max): %u",diff);
123  Q_ASSERT(diff);
124  Q_ASSERT(buflen);
125  if (diff && buflen) {
126  unsigned int src = Kwave::toUint(diff);
127  unsigned int dst = 0;
128  while (src < buflen) {
129  m_min_buffer[dst] = m_min_buffer[src];
130  m_max_buffer[dst] = m_max_buffer[src];
131  m_valid[dst++] = m_valid[src++];
132  }
133  while (dst < buflen) m_valid.clearBit(dst++);
134  }
135  } else {
136  // move right
137  int diff = Kwave::toInt(samples2pixels(m_offset - offset));
138 // qDebug("TrackPixmap::setOffset(): moving right (min/max): %u",diff);
139  Q_ASSERT(diff);
140  Q_ASSERT(buflen);
141  if (diff && buflen) {
142  int dst = buflen - 1;
143  while (dst >= diff) {
144  int src = dst - diff;
145  m_min_buffer[dst] = m_min_buffer[src];
146  m_max_buffer[dst] = m_max_buffer[src];
147  m_valid[dst--] = m_valid[src--];
148  }
149  diff = dst + 1;
150  while (diff--) m_valid.clearBit(dst--);
151  }
152  }
153  } else {
154  // move content of sample buffer
155  // one buffer element = one sample
156  Q_ASSERT(buflen == m_sample_buffer.size());
157 
158  if (offset > m_offset) {
159  // move left
160 // qDebug("TrackPixmap::setOffset(): moving left (normal)");
161  unsigned int diff = Kwave::toUint(offset - m_offset);
162  unsigned int src = Kwave::toUint(diff);
163  unsigned int dst = 0;
164  while (src < buflen) {
165  m_sample_buffer[dst] = m_sample_buffer[src];
166  m_valid[dst++] = m_valid[src++];
167  }
168  while (dst < buflen) m_valid.clearBit(dst++);
169  } else {
170  // move right
171 // qDebug("TrackPixmap::setOffset(): moving right (normal)");
172  int diff = Kwave::toInt(m_offset - offset);
173  Q_ASSERT(buflen);
174  if (buflen) {
175  int dst = buflen - 1;
176  while (dst >= diff) {
177  int src = dst - diff;
178  m_sample_buffer[dst] = m_sample_buffer[src];
179  m_valid[dst--] = m_valid[src];
180  }
181  diff = dst + 1;
182  while (diff--) m_valid.clearBit(dst--);
183  }
184  }
185  }
186 
187  m_offset = offset;
188  m_modified = true;
189 }
190 
191 //***************************************************************************
193 {
194  bool ok = true;
195  int buflen;
196  int oldlen = m_valid.size();
197  int w = width();
198  Q_ASSERT(w >= 0);
199 
200  if (m_minmax_mode) {
201  // one buffer index == one screen pixel
202  buflen = w;
203  ok &= m_min_buffer.resize(buflen);
204  Q_ASSERT(ok);
205  ok &= m_max_buffer.resize(buflen);
206  Q_ASSERT(ok);
207  } else {
208  // one buffer index == one sample
209  buflen = Kwave::toInt(pixels2samples(w));
210  ok &= m_sample_buffer.resize(buflen);
211  Q_ASSERT(ok);
212  }
213  m_valid.resize(buflen);
214  while (oldlen < buflen) m_valid.clearBit(oldlen++);
215 }
216 
217 //***************************************************************************
219 {
220  QMutexLocker lock(&m_lock_buffer);
221 
222  Q_ASSERT(zoom >= 0.0);
223  if (qFuzzyCompare(zoom, m_zoom)) return; // no change
224 
225 // qDebug("TrackPixmap::setZoom(%0.3f)", zoom);
226  if ((zoom > 1.0) && !m_minmax_mode) {
227  // switch to min/max mode
228 // qDebug("TrackPixmap::setZoom(): switch to min/max mode");
230  m_minmax_mode = true;
231  } else if ((zoom <= 1.0) && m_minmax_mode) {
232  // switch to normal mode
233 // qDebug("TrackPixmap::setZoom(): switch to normal mode");
235  m_minmax_mode = false;
236  }
237 
238  // take the new zoom and resize the buffer
239  m_zoom = zoom;
240  if (m_minmax_mode) {
241  // TODO: some clever caching instead of throwing away everything
242  resizeBuffer();
244  } else {
245  resizeBuffer();
246  }
247 
248  m_modified = true;
249 }
250 
251 //***************************************************************************
253 {
254  QMutexLocker lock(&m_lock_buffer);
255 
256  int old_width = m_pixmap.width();
257  int old_height = m_pixmap.height();
258  if ((old_width == width) && (old_height == height)) return; // no change
259 
260  m_pixmap = QPixmap(width, height);
261  if (width != old_width) resizeBuffer();
262 
263  m_modified = true;
264 }
265 
266 //***************************************************************************
268 {
269  m_valid.fill(false);
270  m_modified = true;
271 }
272 
273 //***************************************************************************
275 {
276  int first = 0;
277  int last = 0;
278  int buflen = m_valid.size();
279 
280  sample_index_t left = m_offset;
281  sample_index_t right = (m_track.length()) ? (m_track.length() - 1) : 0;
283  Kwave::SinglePassForward, left, right);
284  Q_ASSERT(reader);
285  if (!reader) return false;
286 
287  if (m_minmax_mode) {
288  Q_ASSERT(Kwave::toInt(m_min_buffer.size()) == buflen);
289  Q_ASSERT(Kwave::toInt(m_max_buffer.size()) == buflen);
290  } else {
291  Q_ASSERT(Kwave::toInt(m_sample_buffer.size()) == buflen);
292  }
293 
294  // work-around for missing extra buffer, delete the whole buffer
295  // instead. this should not do any harm, in this mode we only
296  // have few samples and redrawing will be fast
298 
299  while (first < buflen) {
300  // find the first invalid index
301  for (first = last; (first < buflen) && m_valid.testBit(first);
302  ++first)
303  {}
304 
305  // break if the first index is out of range
306  if (first >= buflen) {
307  delete reader;
308  return false; // buffer is already ok
309  }
310 
311  // find the last invalid index
312  for (last = first; (last < buflen) && !m_valid[last]; ++last) {
313  }
314 
315  if (last >= buflen) last = buflen - 1;
316  if ((last > first) && (m_valid[last])) --last;
317 
318  // fill our array(s) with fresh sample data
319  if (m_minmax_mode) {
320  // indices are in pixels, convert to samples
321 
322  // first sample in first pixel
323  sample_index_t s1 = m_offset +
324  static_cast<sample_index_t>(floor(first * m_zoom));
325  // last sample of last pixel
326  sample_index_t s2 = m_offset +
327  static_cast<sample_index_t>(floor((last+1) * m_zoom)) - 1;
328 
329  while (first <= last) {
330  s2 = m_offset + static_cast<sample_index_t>(
331  floor((first + 1) * m_zoom));
332 
333  // get min/max for interval [s1...s2]
334  sample_t min;
335  sample_t max;
336  reader->minMax(s1, s2, min, max);
337 
338  m_min_buffer[first] = min;
339  m_max_buffer[first] = max;
340  m_valid.setBit(first);
341 
342  // advance to the next position
343  ++first;
344  s1 = s2 + 1;
345  }
346  } else {
347  // each index is one sample
348  // -> read directly into the buffer
349  reader->seek(m_offset + first);
350  unsigned int count = reader->read(m_sample_buffer,
351  first, last - first + 1);
352  while (count) {
353  m_valid.setBit(first++);
354  count--;
355  }
356 
357  // fill the rest with zeroes
358  while (first <= last) {
359  m_valid.setBit(first);
360  m_sample_buffer[first++] = 0;
361  }
362 
363  }
364 
365  Q_ASSERT(first >= last);
366  ++last;
367  }
368 
369 #ifdef DEBUG
370  for (first = 0; first < m_valid.size(); first++) {
371  if (!m_valid[first]) qWarning("TrackPixmap::validateBuffer(): "\
372  "still invalid index: %u", first);
373  }
374 #endif /* DEBUG */
375 
376  delete reader;
377 
378  return true;
379 }
380 
381 //***************************************************************************
383 {
384  QMutexLocker lock(&m_lock_buffer);
385 
386  int w = width();
387  int h = height();
388 
389  if (!w || !h) return; // not valid yet
390 
391  if (m_track.selected()) {
393  } else {
395  }
396 
397  QPainter p(&m_pixmap);
398  p.fillRect(0, 0, w, h, m_colors.background);
399 
400  if (m_zoom > 0) {
401  // first make the buffer valid
402  validateBuffer();
403 
404  // then draw the samples
405  if (m_minmax_mode) {
406  drawOverview(p, h >> 1, h, 0, w - 1);
407  } else {
408  if (m_zoom < INTERPOLATION_ZOOM) {
409  drawInterpolatedSignal(p, w, h >> 1, h);
410  } else {
411  drawPolyLineSignal(p, w, h >> 1, h);
412  }
413  }
414 
415  // draw the zero-line
416  int last = (m_track.length() > m_offset) ?
417  samples2pixels(m_track.length() - 1 - m_offset) : 0;
418  p.setPen(m_colors.zero);
419  if (last >= w) {
420  p.drawLine(0, h >> 1, w - 1, h >> 1);
421  } else {
422  p.drawLine(0, h >> 1, last, h >> 1);
423  p.setPen(m_colors.zero_unused);
424  p.drawLine(last, h >> 1, w, h >> 1);
425  }
426  }
427 
428  // now we are no longer "modified"
429  m_modified = false;
430 }
431 
432 //***************************************************************************
434 {
435  QMutexLocker lock(&m_lock_buffer);
436 
437  if (qFuzzyCompare(zoom, m_vertical_zoom)) return;
438  m_vertical_zoom = zoom;
439  m_modified = true;
440 }
441 
442 //***************************************************************************
444 {
445  QMutexLocker lock(&m_lock_buffer);
446  return m_modified;
447 }
448 
449 //***************************************************************************
451 {
452  QMutexLocker lock(&m_lock_buffer);
453  m_modified = true;
454 }
455 
456 //***************************************************************************
457 void Kwave::TrackPixmap::drawOverview(QPainter &p, int middle, int height,
458  int first, int last)
459 {
460  const Kwave::SampleArray &min_buffer = m_min_buffer;
461  const Kwave::SampleArray &max_buffer = m_max_buffer;
462 
463  Q_ASSERT(m_minmax_mode);
464  Q_ASSERT(width() <= Kwave::toInt(min_buffer.size()));
465  Q_ASSERT(width() <= Kwave::toInt(max_buffer.size()));
466 
467  // scale_y: pixels per unit
468  double scale_y = (m_vertical_zoom * height) / (1 << SAMPLE_BITS);
469 
470  p.setPen(m_colors.sample);
471  int last_min = Kwave::toInt(min_buffer[first] * scale_y);
472  int last_max = Kwave::toInt(max_buffer[first] * scale_y);
473  for (int i = first; i <= last; i++) {
474  Q_ASSERT(m_valid[i]);
475  int max = Kwave::toInt(max_buffer[i] * scale_y);
476  int min = Kwave::toInt(min_buffer[i] * scale_y);
477 
478  // make sure there is a connection between this
479  // section and the one before, avoid gaps
480  if (min > last_max + 1) min = last_max + 1;
481  if (max + 1 < last_min) max = last_min - 1;
482 
483  p.drawLine(i, middle - max, i, middle - min);
484 
485  last_min = min;
486  last_max = max;
487  }
488 }
489 
490 //***************************************************************************
492 {
493  double f;
494  double Fg;
495  int k;
496  int N;
497 
498 // qDebug("TrackPixmap::calculateInterpolation()");
499 
500  // remove all previous coefficents and signal buffer
501  m_interpolation_alpha.clear();
502 
503  Q_ASSERT(!qFuzzyIsNull(m_zoom));
504  if (qFuzzyIsNull(m_zoom)) return;
505 
506  // offset: index of first visible sample (left) [0...length-1]
507  // m_zoom: number of samples / pixel
508 
509  // approximate the 3dB frequency of the low pass as
510  // Fg = f_g / f_a
511  // f_a: current "sample rate" of display (pixels) = 1.0
512  // f_g: signal rate = (m_zoom/2)
513  Fg = m_zoom / 2;
514 
515  // N: order of the filter, at least 2 * (1 / m_zoom)
517  N |= 0x01; // make N an odd number !
518 
519  // allocate a buffer for the coefficients
520  m_interpolation_alpha = QVector<double>(N + 1);
522 
523  Q_ASSERT(m_interpolation_alpha.count() == (N + 1));
524  if (m_interpolation_alpha.count() != (N + 1)) return;
525 
526  // calculate the raw coefficients and
527  // apply a Hamming window
528  //
529  // sin( (2k-N) * Pi * Fg ) 2kPi
530  // alpha_k = 2 * Fg * ----------------------- * [ 0,54 - 0,46 * cos ---- ]
531  // (2k - N) * Pi * Fg N
532  //
533  f = 0.0; // (store the sum of all coefficients in "f")
534  for (k = 0; k <= N; ++k) {
536  sin((2 * k - N) * M_PI * Fg) / ((2 * k - N) * M_PI * Fg);
537  m_interpolation_alpha[k] *= (0.54 - 0.46 * cos(2 * k * M_PI / N));
538  f += m_interpolation_alpha[k];
539  }
540  // norm the coefficients to 1.0 / m_zoom
541  f *= m_zoom;
542  for (k = 0; k <= N; ++k)
543  m_interpolation_alpha[k] /= f;
544 
545 }
546 
547 //***************************************************************************
549  int middle, int height)
550 {
551  float *sig;
552  float *sig_buffer;
553  float scale_y;
554  int i;
555  int k;
556  int N;
557  int sample;
558  int x;
559  int buflen = m_valid.size();
560  const Kwave::SampleArray &sample_buffer = m_sample_buffer;
561 
562 // qDebug("TrackPixmap::drawInterpolatedSignal()");
563 
564  Q_ASSERT(m_zoom > 0);
565  if (m_zoom <= 0) return;
566 
567  // scale_y: pixels per unit
568  scale_y = static_cast<float>(m_vertical_zoom * height) /
569  static_cast<float>((SAMPLE_MAX + 1) << 1);
570 
571  // N: order of the filter, at least 2 * (1/m_zoom)
573  N |= 0x01; // make N an odd number !
574 
575  // re-calculate the interpolation's filter and buffers
576  // if the current order has changed
577  if (m_interpolation_order != N) {
580  }
581 
582  Q_ASSERT(m_interpolation_alpha.count() == (N + 1));
583  if (m_interpolation_alpha.count() != (N + 1)) return;
584 
585  // buffer for intermediate resampled data
586  sig_buffer = new(std::nothrow) float[width + N + 2];
587  Q_ASSERT(sig_buffer);
588  if (!sig_buffer) return;
589 
590  // fill the sample buffer with zeroes
591  for (i = 0; i < width + N + 2; ++i)
592  sig_buffer[i] = 0.0;
593 
594  // resample
595  x = -1 * samples2pixels(2);
596  sample = -2; // start some samples left of the window
597  sig = sig_buffer + (N / 2);
598  while (x <= width + N / 2) {
599  if ((x >= -N / 2) && (sample > 0) && (sample < buflen)) {
600  sig[x] = static_cast<float>(sample_buffer[sample] * scale_y);
601  }
602  sample++;
603  x = Q_LIKELY(sample >= 0) ?
604  samples2pixels(sample) :
605  (-1 * samples2pixels(-1 * sample));
606  }
607 
608  // array with sample points
609  QPolygon points;
610 
611  // pass the signal data through the filter
612  for (i = 0; i < width; ++i) {
613  sig = sig_buffer + (i + N);
614  float y = 0.0;
615  for (k = 0; k <= N; ++k, --sig)
616  y += (*sig) * static_cast<float>(m_interpolation_alpha[k]);
617  points.append(QPoint(i, middle - Kwave::toInt(y)));
618  }
619 
620  // display the filter's interpolated output
621  p.setPen(m_colors.interpolated);
622  p.drawPolyline(points);
623 
624  // display the original samples
625  sample = 0;
626  x = samples2pixels(sample);
627  sig = sig_buffer + (N / 2);
628  p.setPen(m_colors.sample);
629  i = 0;
630  points.clear();
631  while (x < width) {
632  if ((x >= 0) && (x < width)) {
633  // mark original samples
634  points.append(QPoint(x, middle - Kwave::toInt(sig[x])));
635  }
636  sample++;
637  x = samples2pixels(sample);
638  }
639  p.drawPoints(points);
640 
641  delete[] sig_buffer;
642 }
643 
644 //***************************************************************************
646  int middle, int height)
647 {
648  const Kwave::SampleArray &sample_buffer = m_sample_buffer;
649  double scale_y;
650  unsigned int sample;
651  unsigned int buflen = sample_buffer.size();
652 
653  // scale_y: pixels per unit
654  scale_y = (m_vertical_zoom * static_cast<double>(height)) /
655  static_cast<double>((SAMPLE_MAX + 1) << 1);
656 
657  // array with sample points
658  QPolygon points;
659 
660  // display the original samples
661  sample = 0;
662  int x = 0;
663  int y = 0;
664  while (x < width) {
665  // mark original samples
666  sample_t value = (sample < buflen) ? sample_buffer[sample] : 0;
667  y = Kwave::toInt(value * scale_y);
668  points.append(QPoint(x, middle - y));
669 
670  sample++;
671  x = samples2pixels(sample);
672  }
673 
674  // interpolate the rest of the display if necessary
675  if (samples2pixels(sample - 1) <= width) {
676  int x1;
677  int x2;
678  float y1;
679  float y2;
680 
681  x1 = samples2pixels(sample - 1);
682  x2 = samples2pixels(sample);
683 
684  y1 = ((sample) && (sample <= buflen)) ?
685  Kwave::toInt(scale_y * sample_buffer[sample - 1]) : 0.0;
686  y2 = (sample < buflen) ?
687  Kwave::toInt(scale_y * sample_buffer[sample ]) : 0.0;
688 
689  x = width - 1;
690  y = Kwave::toInt(static_cast<float>(x - x1) *
691  static_cast<float>(y2 - y1) / static_cast<float>(x2 - x1));
692 
693  points.append(QPoint(x, middle - y));
694  }
695 
696  if (m_zoom >= 1.0) {
697  // show only poly-line (bright)
698  p.setPen(Qt::white);
699  p.drawPolyline(points);
700  } else {
701  // show the poly-line (dark)
702  p.setPen(Qt::darkGray);
703  p.drawPolyline(points);
704 
705  // show the original points (bright)
706  p.setPen(Qt::white);
707  p.drawPoints(points);
708  }
709 }
710 
711 //***************************************************************************
713  sample_index_t offset,
714  sample_index_t length)
715 {
716  {
717  QMutexLocker lock(&m_lock_buffer);
718 
719  convertOverlap(offset, length);
720  if (!length) return; // false alarm
721 
722  // mark all positions from here to right end as "invalid"
723  const int first = Kwave::toInt(offset);
724  const int last = m_valid.size();
725  Q_ASSERT(first < m_valid.size());
726  Q_ASSERT(last > first);
727  m_valid.fill(false, first, last);
728 
729  // repaint of the signal is needed
730  m_modified = true;
731  }
732 
733  // notify our owner about changed data -> screen refresh?
734  emit sigModified();
735 }
736 
737 //***************************************************************************
739  sample_index_t offset,
740  sample_index_t length)
741 {
742  {
743  QMutexLocker lock(&m_lock_buffer);
744 
745  convertOverlap(offset, length);
746  if (!length) return; // false alarm
747 
748  // mark all positions from here to right end as "invalid"
749  const int first = Kwave::toInt(offset);
750  const int last = m_valid.size();
751  Q_ASSERT(first < m_valid.size());
752  Q_ASSERT(last > first);
753  m_valid.fill(false, first, last);
754 
755  // repaint of the signal is needed
756  m_modified = true;
757  }
758 
759  // notify our owner about changed data -> screen refresh?
760  emit sigModified();
761 }
762 
763 //***************************************************************************
765  sample_index_t offset,
766  sample_index_t length)
767 {
768  {
769  QMutexLocker lock(&m_lock_buffer);
770 
771  convertOverlap(offset, length);
772  if (!length) return; // false alarm
773 
774  // mark all overlapping positions as "invalid"
775  const int first = Kwave::toInt(offset);
776  const int last = Kwave::toInt(offset + length);
777  Q_ASSERT(first < m_valid.size());
778  Q_ASSERT(last > first);
779  m_valid.fill(false, first, last);
780 
781  // repaint of the signal is needed
782  m_modified = true;
783  }
784 
785  // notify our owner about changed data -> screen refresh?
786  emit sigModified();
787 }
788 
789 //***************************************************************************
791  sample_index_t &length)
792 {
793  if (m_zoom <= 0.0) length = 0;
794  if (!length) return;
795  if ((offset + length) <= m_offset) {
796  length = 0;
797  return; // not yet in view
798  }
799 
800  unsigned int buflen = m_valid.size();
801  if (!buflen) {
802  offset = 0;
803  length = 0;
804  return;
805  }
806 
807  // calculate the length
808  if (m_minmax_mode) {
809  // attention: round up the length int this mode!
810  if (offset >= m_offset + static_cast<sample_index_t>(
811  ceil(buflen * m_zoom)))
812  {
813  length = 0; // out of view
814  return;
815  } else {
816  length = static_cast<sample_index_t>(ceil(length / m_zoom));
817  }
818  } else {
819  if (offset >= m_offset + buflen) {
820  length = 0; // out of view
821  return;
822  }
823  }
824 
825  // convert the offset
826  offset = (offset > m_offset) ? offset - m_offset : 0;
827  if (m_minmax_mode) {
828  // attention: round down in this mode!
829  sample_index_t ofs = static_cast<sample_index_t>(floor(offset / m_zoom));
830 
831  // if offset was rounded down, increment length
832  if (ofs != static_cast<sample_index_t>(ceil(offset / m_zoom)))
833  length++;
834  offset = ofs;
835  }
836 
837  // limit the offset (maybe something happened when rounding)
838  if (offset >= buflen) offset = buflen - 1;
839 
840  // limit the length to the end of the buffer
841  if (offset + length > buflen) length = buflen - offset;
842 
843  Q_ASSERT(length);
844 }
845 
846 //***************************************************************************
847 //***************************************************************************
bool selected() const
Definition: Track.h:137
virtual int width() const
Definition: TrackPixmap.h:90
sample_index_t m_offset
Definition: TrackPixmap.h:304
Definition: App.h:33
static Q_DECL_EXPORT ColorSet Disabled
Definition: Colors.h:52
void drawInterpolatedSignal(QPainter &p, int width, int middle, int height)
virtual ~TrackPixmap()
Definition: TrackPixmap.cpp:75
void slotSamplesInserted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
virtual void repaint()
virtual int height() const
Definition: TrackPixmap.h:96
void calculateInterpolation()
Kwave::SampleReader * openReader(Kwave::ReaderMode mode, sample_index_t left=0, sample_index_t right=SAMPLE_INDEX_MAX)
Definition: Track.cpp:274
quint64 sample_index_t
Definition: Sample.h:28
virtual void setVerticalZoom(double zoom)
TrackPixmap(Kwave::Track &track)
Definition: TrackPixmap.cpp:50
void setOffset(sample_index_t offset)
Definition: TrackPixmap.cpp:82
virtual void resize(int width, int height)
void slotSamplesDeleted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
void convertOverlap(sample_index_t &offset, sample_index_t &length)
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
Kwave::SampleArray m_sample_buffer
Definition: TrackPixmap.h:328
void seek(sample_index_t pos)
void minMax(sample_index_t first, sample_index_t last, sample_t &min, sample_t &max)
Kwave::Colors::ColorSet m_colors
Definition: TrackPixmap.h:367
QVector< double > m_interpolation_alpha
Definition: TrackPixmap.h:364
#define INTERPOLATION_ZOOM
Definition: TrackPixmap.cpp:47
Kwave::SampleArray m_min_buffer
Definition: TrackPixmap.h:333
#define INTERPOLATION_PRECISION
Definition: TrackPixmap.cpp:41
int toInt(T x)
Definition: Utils.h:127
Kwave::Track & m_track
Definition: TrackPixmap.h:297
sample_index_t pixels2samples(int pixels)
Definition: TrackPixmap.h:262
int samples2pixels(sample_index_t samples)
Definition: TrackPixmap.h:270
Kwave::SampleArray m_max_buffer
Definition: TrackPixmap.h:338
void slotSamplesModified(Kwave::Track *src, sample_index_t offset, sample_index_t length)
void drawPolyLineSignal(QPainter &p, int width, int middle, int height)
virtual bool isModified()
#define SAMPLE_MAX
Definition: Sample.h:52
unsigned int size() const
unsigned int read(Kwave::SampleArray &buffer, unsigned int dstoff, unsigned int length)
unsigned int toUint(T x)
Definition: Utils.h:109
void setZoom(double zoom)
#define SAMPLE_BITS
Definition: Sample.h:43
bool resize(unsigned int size) Q_REQUIRED_RESULT
static Q_DECL_EXPORT ColorSet Normal
Definition: Colors.h:49
sample_index_t length()
Definition: Track.cpp:173
qint32 sample_t
Definition: Sample.h:37
void drawOverview(QPainter &p, int middle, int height, int first, int last)