kwave  18.07.70
Stripe.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  Stripe.cpp - continuous block of samples
3  -------------------
4  begin : Feb 10 2001
5  copyright : (C) 2001 by Thomas Eschenbacher
6  email : Thomas Eschenbacher <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 <new>
21 #include <string.h> // for some speed-ups like memmove, memcpy ...
22 
23 #include "libkwave/Stripe.h"
24 #include "libkwave/Utils.h"
25 #include "libkwave/memcpy.h"
26 
27 // define this for using only slow Qt array functions
28 #undef STRICTLY_QT
29 
30 //***************************************************************************
31 //***************************************************************************
33  :m_stripe(stripe), m_storage(Q_NULLPTR), m_length(stripe.length())
34 {
36  if (!m_storage) m_length = 0;
38 }
39 
40 //***************************************************************************
42 {
43  if (m_length) resetRawData();
45 }
46 
47 //***************************************************************************
48 unsigned int Kwave::Stripe::MappedArray::copy(unsigned int dst,
49  unsigned int src,
50  unsigned int cnt)
51 {
52 // qDebug(" Stripe::MappedArray::copy(%u, %u, %u)", dst, src, cnt);
53  if (!m_length) return 0;
54 
55 #ifdef STRICTLY_QT
56  unsigned int rest = cnt;
57  while (rest--) {
58  (*this)[dst++] = (*this)[src++];
59  }
60 #else
61  sample_t *_samples = m_storage;
62  if (!_samples) return 0;
63  // no MEMCPY here !
64  memmove(&(_samples[dst]), &(_samples[src]), cnt * sizeof(sample_t));
65 #endif
66 
67  return cnt;
68 }
69 
70 //***************************************************************************
72  unsigned int dstoff, unsigned int offset, unsigned int length)
73 {
74 // qDebug(" Stripe::MappedArray::read(..., %u, %u, %u)", dstoff,
75 // offset, length);
76  if (!m_length) return 0;
77 
78 #ifdef STRICTLY_QT
79  unsigned int cnt = length;
80  while (cnt--) {
81  buffer[dstoff++] = (*this)[offset++];
82  }
83 #else
84  sample_t *_samples = m_storage;
85  if (!_samples) return 0;
86  MEMCPY(&(buffer[dstoff]), &(_samples[offset]), length * sizeof(sample_t));
87 
88 #endif
89  return length;
90 }
91 
92 //***************************************************************************
93 //***************************************************************************
95  :QSharedData(), m_start(0), m_length(0), m_storage(0), m_lock(),
96  m_map_count(0), m_mapped_storage(Q_NULLPTR)
97 {
98 }
99 
100 //***************************************************************************
102  :QSharedData(other), m_start(other.m_start), m_length(other.m_length),
103  m_storage(0), m_lock(), m_map_count(0), m_mapped_storage(Q_NULLPTR)
104 {
105 // qDebug("StripeStorage(%p) - DEEP COPY %u,%u from %p",
106 // static_cast<void *>(this),
107 // m_start, m_length,
108 // static_cast<const void *>(&other)
109 // );
110 
111  if (other.m_storage) {
112  // allocate memory for the copy
114  m_storage = mem.allocate(m_length * sizeof(sample_t));
115  if (!m_storage) {
116  // allocation failed
117  qWarning("StripeStorage: DEEP COPY (%u) FAILED - OOM!", m_length);
118  m_length = 0;
119  return;
120  }
121 
122  // copy the data from the original
123  Q_ASSERT(m_storage);
124  void *original = mem.map(other.m_storage);
125  if (original) {
126  mem.writeTo(m_storage, 0, original, m_length * sizeof(sample_t));
127  mem.unmap(other.m_storage);
128  } else {
129  qWarning("StripeStorage: DEEP COPY (%u) MMAP FAILED - "
130  "FALLING BACK TO SLOW COPY!", m_length);
131  // fall back to slow copy algorithm
132  char buf[256]; // use a small buffer on the stack
133  unsigned int remaining = m_length;
134  unsigned int ofs = 0;
135 
136  while (remaining) {
137  unsigned int len = qMin(remaining, Kwave::toUint(sizeof(buf)));
138  unsigned int read = mem.readFrom(other.m_storage, ofs,
139  &buf[0], len);
140  Q_ASSERT(read == len);
141  if (read != len) break;
142  unsigned int written = mem.writeTo(m_storage, ofs,
143  &buf[0], len);
144  Q_ASSERT(written == len);
145  if (written != len) break;
146  remaining -= len;
147  ofs += len;
148  }
149  if (remaining) {
150  qWarning("StripeStorage: DEEP COPY (%u) FAILED - DATA LOST!",
151  m_length);
152  }
153  }
154  }
155 }
156 
157 //***************************************************************************
159 {
160  QMutexLocker lock(&m_lock);
161 
162  if (!m_storage) return Q_NULLPTR;
163 
164  if (!m_map_count) {
166  m_mapped_storage = reinterpret_cast<sample_t *>(
167  mem.map(m_storage));
168  }
169 
171 
172  return m_mapped_storage;
173 }
174 
175 //***************************************************************************
177 {
178  QMutexLocker lock(&m_lock);
179 
180  Q_ASSERT(m_map_count);
181  if (!m_map_count) return;
182 
183  m_map_count--;
184  if (!m_map_count) {
186  mem.unmap(m_storage);
187  m_mapped_storage = Q_NULLPTR;
188  }
189 }
190 
191 //***************************************************************************
193 {
194  Q_ASSERT(!m_map_count);
195  Q_ASSERT(!m_mapped_storage);
196  if (m_storage) {
198  mem.free(m_storage);
199  }
200 }
201 
202 //***************************************************************************
203 //***************************************************************************
205  :m_lock(), m_data(new(std::nothrow) StripeStorage)
206 {
207 }
208 
209 //***************************************************************************
211  :m_lock(), m_data(Q_NULLPTR)
212 {
213  m_data = other.m_data;
214 }
215 
216 //***************************************************************************
218  :m_lock(), m_data(new(std::nothrow) StripeStorage)
219 {
220  if (m_data) m_data->m_start = start;
221 }
222 
223 //***************************************************************************
225  :m_lock(), m_data(new(std::nothrow) StripeStorage)
226 {
227  if (m_data) m_data->m_start = start;
228  if (samples.size()) append(samples, 0, samples.size());
229 }
230 
231 //***************************************************************************
233  Kwave::Stripe &stripe,
234  unsigned int offset)
235  :m_lock(), m_data(new(std::nothrow) StripeStorage)
236 {
237  if (!m_data) return;
238 
239  m_data->m_start = start;
240 
241  Q_ASSERT(offset < stripe.length());
242  if (offset >= stripe.length()) return;
243 
244  unsigned int length = stripe.length() - offset;
245  if (resizeStorage(length) != length) return; // out of memory
246 
247  if (length) {
248  MappedArray _samples(*this);
249  Q_ASSERT(_samples.data());
250  if (!_samples.data()) return; // OOM
251  if (!stripe.read(_samples, 0, offset, length)) resize(0);
252  }
253 }
254 
255 //***************************************************************************
257 {
258  QMutexLocker lock(&m_lock);
259 }
260 
261 //***************************************************************************
263 {
264  return (m_data) ? m_data->m_start : 0;
265 }
266 
267 //***************************************************************************
269 {
270  QMutexLocker lock(&m_lock);
271  m_data.detach();
272  if (m_data) m_data->m_start = start;
273 }
274 
275 //***************************************************************************
276 unsigned int Kwave::Stripe::length() const
277 {
278  return (m_data) ? m_data->m_length : 0;
279 }
280 
281 //***************************************************************************
283 {
284  return (m_data) ? (m_data->m_start +
285  ((m_data->m_length) ? (m_data->m_length - 1) : 0)) : 0;
286 }
287 
288 //***************************************************************************
289 unsigned int Kwave::Stripe::resizeStorage(unsigned int length)
290 {
291  Q_ASSERT(m_data); // (just paranoia)
292 
293  if (m_data->m_length == length) return length; // nothing to do
294 // qDebug("Stripe::resizeStorage(%u)", length);
295 
296  // check: must not be mapped!
297  Q_ASSERT(!m_data->mapCount());
298  if (m_data->mapCount()) return m_data->m_length;
299 
301 
302  // special case: zero length means delete
303  if (length == 0) {
304  // delete the array
305  mem.free(m_data->m_storage);
306  m_data->m_storage = 0;
307  m_data->m_length = 0;
308  return 0;
309  }
310 
311  if (!m_data->m_length || !m_data->m_storage) {
312  // allocate new storage
313  Kwave::Handle new_storage = mem.allocate(length * sizeof(sample_t));
314  if (!new_storage) {
315  // allocation failed
316  qWarning("Stripe::resizeStorage(%u) failed! (1)", length);
317  return m_data->m_length;
318  }
319 
320  Q_ASSERT(!m_data->m_storage);
321  m_data->m_storage = new_storage;
322  m_data->m_length = length;
323  return length;
324  }
325 
326  // resize the array to another size
327  if (!mem.resize(m_data->m_storage, length * sizeof(sample_t))) {
328  // resize failed
329  qWarning("Stripe::resizeStorage(%u) failed! (2)", length);
330  return m_data->m_length;
331  }
332 
333  // succeeded
334  m_data->m_length = length;
335  return length;
336 }
337 
338 //***************************************************************************
339 unsigned int Kwave::Stripe::resize(unsigned int length, bool initialize)
340 {
341  QMutexLocker lock(&m_lock);
342  m_data.detach();
343  if (!m_data) return 0; // OOM when detaching
344 
345  unsigned int old_length = m_data->m_length;
346  if (m_data->m_length == length) return old_length; // nothing to do
347 
348 // qDebug("Stripe::resize() from %d to %d samples", old_length, length);
349  Q_ASSERT(!m_data->mapCount());
350  if (resizeStorage(length) != length) {
351  qWarning("Stripe::resize(%u) failed, out of memory ?", length);
352  return m_data->m_length;
353  }
354 
355  // fill new samples with zero
356  if (initialize && length) {
357  Q_ASSERT(!m_data->mapCount());
358  unsigned int pos = old_length;
359 
360 #ifdef STRICTLY_QT
361  MappedArray _samples(*this);
362  if (_samples.size() != m_data->m_length) return 0;
363 
364  while (pos < length) {
365  _samples[pos++] = 0;
366  }
367 #else
368  MappedArray _map(*this);
369  sample_t *samples = _map.data();
370  if (!samples) return 0;
371  if (pos < length) {
372  memset(&(samples[pos]), 0, (length - pos) * sizeof(sample_t));
373  }
374 #endif
375  }
376 
377  return length;
378 }
379 
380 //***************************************************************************
381 unsigned int Kwave::Stripe::append(const Kwave::SampleArray &samples,
382  unsigned int offset,
383  unsigned int count)
384 {
385  if (!count) return 0; // nothing to do
386  Q_ASSERT(offset + count <= samples.size());
387  if (offset + count > samples.size()) return 0;
388 
389 // qDebug("Stripe::append: adding %d samples", count);
390  QMutexLocker lock(&m_lock);
391  m_data.detach();
392  if (!m_data) return 0; // OOM when detaching
393 
394  unsigned int old_length = m_data->m_length;
395  unsigned int new_length = old_length + count;
396  Q_ASSERT(!m_data->mapCount());
397  if (resizeStorage(new_length) != new_length)
398  return 0; // out of memory
399 
400  // append to the end of the area
401  unsigned int cnt = new_length - old_length;
402  Q_ASSERT(!m_data->mapCount());
403  int bytes_appended = Kwave::MemoryManager::instance().writeTo(
404  m_data->m_storage,
405  old_length * sizeof(sample_t),
406  &(samples[offset]), cnt * sizeof(sample_t)
407  );
408 
409 // qDebug("Stripe::append(): resized to %d", m_length);
410  return (bytes_appended > 0) ? (bytes_appended / sizeof(sample_t)) : 0;
411 }
412 
413 //***************************************************************************
414 void Kwave::Stripe::deleteRange(unsigned int offset, unsigned int length)
415 {
416 // qDebug(" Stripe::deleteRange(offset=%u, length=%u)", offset, length);
417  if (!length) return; // nothing to do
418 
419  QMutexLocker lock(&m_lock);
420  m_data.detach();
421  if (!m_data) return; // OOM when detaching
422 
423  const unsigned int size = m_data->m_length;
424  if (!size) return;
425 
426  unsigned int first = offset;
427  unsigned int last = offset + length - 1;
428 // qDebug(" Stripe::deleteRange, me=[%u ... %u] del=[%u ... %u]",
429 // m_start, m_start+size-1, m_start + first, m_start + last);
430 
431  Q_ASSERT(first < size);
432  if (first >= size) return;
433 
434  // put first/last into our area
435  if (last >= size) last = size - 1;
436  Q_ASSERT(last >= first);
437  if (last < first) return;
438 
439  // move all samples after the deleted area to the left
440  unsigned int dst = first;
441  unsigned int src = last+1;
442  unsigned int len = size - src;
443 // qDebug(" Stripe: deleting %u ... %u", dst, src-1);
444  if (len) {
445  MappedArray _samples(*this);
446 
447  Q_ASSERT(src + len <= size);
448  Q_ASSERT(dst + len <= size);
449  if (!_samples.copy(dst, src, len)) return;
450  }
451 
452  // resize the buffer to it's new size
453  resizeStorage(size - length);
454 }
455 
456 //***************************************************************************
457 bool Kwave::Stripe::combine(unsigned int offset, Kwave::Stripe &other)
458 {
459  QMutexLocker lock(&m_lock);
460  m_data.detach();
461  if (!m_data) return false; // OOM when detaching
462 
463  if (m_data->mapCount()) return false; // data is mapped
464 
465  const unsigned int old_len = m_data->m_length;
466  const unsigned int combined_len = offset + other.length();
467  if (old_len < combined_len) {
468  // resize the storage if necessary
469  if (resizeStorage(combined_len) != combined_len)
470  return false; // resizing failed, maybe OOM ?
471  }
472 
473  // copy the data from the other stripe
474  MappedArray _src(other);
475  MappedArray _dst(*this);
476  const sample_t *src = _src.constData();
477  sample_t *dst = _dst.data();
478  unsigned int len = _src.size() * sizeof(sample_t);
479  if (!src || !dst) return false; // mmap of src or dst failed
480 
481  MEMCPY(dst + offset, src, len);
482 
483  return true;
484 }
485 
486 //***************************************************************************
487 void Kwave::Stripe::overwrite(unsigned int offset,
488  const Kwave::SampleArray &source,
489  unsigned int srcoff, unsigned int srclen)
490 {
491  QMutexLocker lock(&m_lock);
492  m_data.detach();
493  if (!m_data) return; // OOM when detaching
494 
495  Q_ASSERT(!m_data->mapCount());
497  offset * sizeof(sample_t),
498  &(source[srcoff]), srclen * sizeof(sample_t));
499 }
500 
501 //***************************************************************************
503  unsigned int dstoff,
504  unsigned int offset,
505  unsigned int length)
506 {
507  QMutexLocker lock(&m_lock);
508  if (!length || !m_data) return 0; // nothing to do !?
509 
510 // for (unsigned int x=dstoff; (dstoff+x < length) && (x < buffer.size()); x++)
511 // buffer[x] = -(SAMPLE_MAX >> 2);
512 
513 // qDebug("Stripe::read(), me=[%u ... %u] (size=%u), offset=%u, length=%u",
514 // m_start, m_start+m_length-1, m_length, offset, length);
515 
516  Q_ASSERT(offset < m_data->m_length);
517  if (offset >= m_data->m_length) return 0;
518  if ((offset + length) > m_data->m_length)
519  length = m_data->m_length - offset;
520  Q_ASSERT(length);
521 // if (!length) qDebug("--- [%u ... %u] (%u), offset=%u",
522 // m_start, m_start+m_length-1, m_length, offset);
523  if (!length) return 0;
524 
525  // read directly through the memory manager, fastest path
526  int bytes_read = Kwave::MemoryManager::instance().readFrom(
527  m_data->m_storage,
528  offset * sizeof(sample_t),
529  &buffer[dstoff], length * sizeof(sample_t)
530  );
531 
532 // qDebug("read done, length=%u", read_len);
533  return (bytes_read > 0) ? (bytes_read / sizeof(sample_t)) : 0;
534 }
535 
536 //***************************************************************************
537 void Kwave::Stripe::minMax(unsigned int first, unsigned int last,
538  sample_t &min, sample_t &max)
539 {
540  QMutexLocker lock(&m_lock);
541  if (!m_data) return;
542 
543  MappedArray _samples(*this);
544  const sample_t *buffer = _samples.constData();
545  if (!buffer) return;
546 
547  // loop over the mapped storage to get min/max
548  sample_t lo = min;
549  sample_t hi = max;
550  Q_ASSERT(first < m_data->m_length);
551  Q_ASSERT(first <= last);
552  Q_ASSERT(last < m_data->m_length);
553  buffer += first;
554  unsigned int remaining = last - first + 1;
555 
556  // speedup: process a block of 8 samples at once, to allow loop unrolling
557  const unsigned int block = 8;
558  while (Q_LIKELY(remaining >= block)) {
559  for (unsigned int count = 0; Q_LIKELY(count < block); count++) {
560  sample_t s = *(buffer++);
561  if (Q_UNLIKELY(s < lo)) lo = s;
562  if (Q_UNLIKELY(s > hi)) hi = s;
563  }
564  remaining -= block;
565  }
566  while (Q_LIKELY(remaining)) {
567  sample_t s = *(buffer++);
568  if (Q_UNLIKELY(s < lo)) lo = s;
569  if (Q_UNLIKELY(s > hi)) hi = s;
570  remaining--;
571  }
572  min = lo;
573  max = hi;
574 }
575 
576 //***************************************************************************
578 {
579  unsigned int appended = append(samples, 0, samples.size());
580  if (appended != samples.size()) {
581  qWarning("Stripe::operator << FAILED");
582  }
583  return *this;
584 }
585 
586 //***************************************************************************
588 {
589  return ((start() == other.start()) &&
590  (end() == other.end()));
591 }
592 
593 //***************************************************************************
595 {
596  m_data = other.m_data;
597  return *this;
598 }
599 
600 //***************************************************************************
602 {
603  return (m_data) ? m_data->map() : Q_NULLPTR;
604 }
605 
606 //***************************************************************************
608 {
609  if (m_data) m_data->unmap();
610 }
611 
612 //***************************************************************************
613 //***************************************************************************
bool combine(unsigned int offset, Kwave::Stripe &other)
Definition: Stripe.cpp:457
unsigned int append(const Kwave::SampleArray &samples, unsigned int offset, unsigned int count)
Definition: Stripe.cpp:381
unsigned int length() const
Definition: Stripe.cpp:276
int readFrom(Kwave::Handle handle, unsigned int offset, void *buffer, unsigned int length) Q_DECL_EXPORT
unsigned int read(Kwave::SampleArray &buffer, unsigned int dstoff, unsigned int offset, unsigned int length)
Definition: Stripe.cpp:502
static MemoryManager & instance() Q_DECL_EXPORT
void overwrite(unsigned int offset, const Kwave::SampleArray &source, unsigned int srcoff, unsigned int srclen)
Definition: Stripe.cpp:487
sample_t * m_mapped_storage
Definition: Stripe.h:349
unsigned int m_length
Definition: Stripe.h:295
unsigned int read(Kwave::SampleArray &buffer, unsigned int dstoff, unsigned int offset, unsigned int length)
Definition: Stripe.cpp:71
quint64 sample_index_t
Definition: Sample.h:28
Kwave::Handle m_storage
Definition: Stripe.h:338
Stripe & operator<<(const Kwave::SampleArray &samples)
Definition: Stripe.cpp:577
bool operator==(const Stripe &other) const
Definition: Stripe.cpp:587
void deleteRange(unsigned int offset, unsigned int length)
Definition: Stripe.cpp:414
unsigned int resizeStorage(unsigned int length)
Definition: Stripe.cpp:289
void free(Kwave::Handle &handle) Q_DECL_EXPORT
unsigned int resize(unsigned int length, bool initialize=true)
Definition: Stripe.cpp:339
sample_index_t start() const
Definition: Stripe.cpp:262
sample_t * mapStorage()
Definition: Stripe.cpp:601
MappedArray(Stripe &stripe)
Definition: Stripe.cpp:32
sample_index_t end() const
Definition: Stripe.cpp:282
int Handle
Definition: MemoryManager.h:34
QMutex m_lock
Definition: Stripe.h:355
#define MEMCPY
Definition: memcpy.h:37
void unmapStorage()
Definition: Stripe.cpp:607
Stripe & operator=(const Stripe &other)
Definition: Stripe.cpp:594
void setRawData(sample_t *data, unsigned int size)
Definition: SampleArray.cpp:47
virtual ~Stripe()
Definition: Stripe.cpp:256
void setStart(sample_index_t start)
Definition: Stripe.cpp:268
const sample_t * constData() const
Definition: SampleArray.h:54
unsigned int copy(unsigned int dst, unsigned int src, unsigned int cnt)
Definition: Stripe.cpp:48
void unmap(Kwave::Handle handle) Q_DECL_EXPORT
unsigned int size() const
void * map(Kwave::Handle handle) Q_DECL_EXPORT
int writeTo(Kwave::Handle handle, unsigned int offset, const void *buffer, unsigned int length) Q_DECL_EXPORT
Kwave::Handle allocate(size_t size) Q_DECL_EXPORT
unsigned int toUint(T x)
Definition: Utils.h:109
sample_t * data()
Definition: SampleArray.h:62
sample_index_t m_start
Definition: Stripe.h:332
qint32 sample_t
Definition: Sample.h:37
void minMax(unsigned int first, unsigned int last, sample_t &min, sample_t &max)
Definition: Stripe.cpp:537
QExplicitlySharedDataPointer< StripeStorage > m_data
Definition: Stripe.h:358