kwave  18.07.70
Kwave::Track Class Reference

#include <Track.h>

Inheritance diagram for Kwave::Track:
Inheritance graph
Collaboration diagram for Kwave::Track:
Collaboration graph

Public Slots

void toggleSelection ()
 
void defragment ()
 

Signals

void sigSamplesInserted (Kwave::Track *src, sample_index_t offset, sample_index_t length)
 
void sigSamplesDeleted (Kwave::Track *src, sample_index_t offset, sample_index_t length)
 
void sigSamplesModified (Kwave::Track *src, sample_index_t offset, sample_index_t length)
 
void sigSelectionChanged (bool selected)
 

Public Member Functions

 Track ()
 
 Track (sample_index_t length, QUuid *uuid)
 
virtual ~Track ()
 
sample_index_t length ()
 
Kwave::WriteropenWriter (Kwave::InsertMode mode, sample_index_t left=0, sample_index_t right=0)
 
Kwave::SampleReaderopenReader (Kwave::ReaderMode mode, sample_index_t left=0, sample_index_t right=SAMPLE_INDEX_MAX)
 
Kwave::Stripe::List stripes (sample_index_t left, sample_index_t right)
 
bool mergeStripes (const Kwave::Stripe::List &stripes)
 
void deleteRange (sample_index_t offset, sample_index_t length, bool make_gap=false)
 
bool insertSpace (sample_index_t offset, sample_index_t shift)
 
bool selected () const
 
void select (bool select)
 
const QUuid & uuid () const
 

Protected Member Functions

bool writeSamples (Kwave::InsertMode mode, sample_index_t offset, const Kwave::SampleArray &buffer, unsigned int buf_offset, unsigned int length)
 
void use ()
 
void release ()
 

Private Member Functions

sample_index_t unlockedLength ()
 
void unlockedDelete (sample_index_t offset, sample_index_t length, bool make_gap=false)
 
bool appendAfter (Stripe *stripe, sample_index_t offset, const Kwave::SampleArray &buffer, unsigned int buf_offset, unsigned int length)
 
void moveRight (sample_index_t offset, sample_index_t shift)
 
void appendStripe (sample_index_t length)
 
Stripe splitStripe (Stripe &stripe, unsigned int offset)
 
bool mergeStripe (Kwave::Stripe &stripe)
 
void dump ()
 
StripenewStripe (sample_index_t start, unsigned int length)
 

Private Attributes

QMutex m_lock
 
QReadWriteLock m_lock_usage
 
QList< Stripem_stripes
 
bool m_selected
 
QUuid m_uuid
 

Friends

class Kwave::TrackWriter
 

Detailed Description

Definition at line 44 of file Track.h.

Constructor & Destructor Documentation

◆ Track() [1/2]

Kwave::Track::Track ( )

Default constructor. Creates a new and empty track with zero-length, no stripes and new uuid

Definition at line 58 of file Track.cpp.

59  :m_lock(QMutex::Recursive), m_lock_usage(), m_stripes(), m_selected(true),
60  m_uuid(QUuid::createUuid())
61 {
62 }
QMutex m_lock
Definition: Track.h:308
QUuid m_uuid
Definition: Track.h:320
QList< Stripe > m_stripes
Definition: Track.h:314
QReadWriteLock m_lock_usage
Definition: Track.h:311
bool m_selected
Definition: Track.h:317

◆ Track() [2/2]

Kwave::Track::Track ( sample_index_t  length,
QUuid *  uuid 
)

Constructor. Creates an empty track with a specified length.

Parameters
lengththe length in samples
uuidunique ID of the track, can be null

Definition at line 65 of file Track.cpp.

References appendStripe(), Kwave::Stripe::length(), m_stripes, Kwave::Stripe::resize(), STRIPE_LENGTH_MAXIMUM, and STRIPE_LENGTH_OPTIMAL.

66  :m_lock(QMutex::Recursive), m_lock_usage(), m_stripes(), m_selected(true),
67  m_uuid((uuid) ? *uuid : QUuid::createUuid())
68 {
71  } else {
72  Stripe s(length - STRIPE_LENGTH_OPTIMAL);
73  s.resize(STRIPE_LENGTH_OPTIMAL);
74  if (s.length()) m_stripes.append(s);
75  }
76 }
QMutex m_lock
Definition: Track.h:308
QUuid m_uuid
Definition: Track.h:320
QList< Stripe > m_stripes
Definition: Track.h:314
const QUuid & uuid() const
Definition: Track.h:143
#define STRIPE_LENGTH_MAXIMUM
Definition: Track.cpp:46
#define STRIPE_LENGTH_OPTIMAL
Definition: Track.cpp:37
QReadWriteLock m_lock_usage
Definition: Track.h:311
bool m_selected
Definition: Track.h:317
sample_index_t length()
Definition: Track.cpp:173
void appendStripe(sample_index_t length)
Definition: Track.cpp:92
Here is the call graph for this function:

◆ ~Track()

Kwave::Track::~Track ( )
virtual

Destructor.

Definition at line 79 of file Track.cpp.

References m_lock, m_lock_usage, and m_stripes.

80 {
81  // wait until all readers are finished
82  QWriteLocker lock_usage(&m_lock_usage);
83 
84  // don't allow any further operation
85  QMutexLocker lock(&m_lock);
86 
87  // delete all stripes
88  m_stripes.clear();
89 }
QMutex m_lock
Definition: Track.h:308
QList< Stripe > m_stripes
Definition: Track.h:314
QReadWriteLock m_lock_usage
Definition: Track.h:311

Member Function Documentation

◆ appendAfter()

bool Kwave::Track::appendAfter ( Stripe stripe,
sample_index_t  offset,
const Kwave::SampleArray buffer,
unsigned int  buf_offset,
unsigned int  length 
)
private

Append samples after a given stripe.

Parameters
stripethe stripe after which to instert. Null pointer is allowed, in this case a new stripe is created
offsetposition where the new data should start
bufferarray with samples
buf_offsetoffset within the buffer
lengthnumber of samples to write
Returns
true if successful, false if failed (e.g. out of memory)

Definition at line 478 of file Track.cpp.

References Kwave::Stripe::append(), Kwave::Stripe::end(), length(), Kwave::Stripe::length(), m_stripes, Kwave::SampleArray::size(), STRIPE_LENGTH_MAXIMUM, and Kwave::toUint().

Referenced by writeSamples().

481 {
482  Q_ASSERT(buf_offset + length <= buffer.size());
483  if (buf_offset + length > buffer.size()) return false;
484 
485  // append to the last stripe if one exists and it's not full
486  // and the offset is immediately after the last stripe
487  if ((stripe) && (stripe->end()+1 == offset) &&
488  (stripe->length() < STRIPE_LENGTH_MAXIMUM))
489  {
490  unsigned int len = length;
491  if (len + stripe->length() > STRIPE_LENGTH_MAXIMUM)
492  len = STRIPE_LENGTH_MAXIMUM - stripe->length();
493 
494 // qDebug("Kwave::Track::appendAfter(): appending %u samples to %p",
495 // len, stripe);
496  if (!stripe->append(buffer, buf_offset, len))
497  return false; // out of memory
498 
499  offset += len;
500  length -= len;
501  buf_offset += len;
502  }
503 
504  int index_before = (stripe) ? (m_stripes.indexOf(*stripe)) : -1;
505 
506  // append new stripes as long as there is something remaining
507  while (length) {
508  unsigned int len = Kwave::toUint(qMin<sample_index_t>(
510 
511 // qDebug("Kwave::Track::appendAfter: new stripe, ofs=%u, len=%u",
512 // offset, len);
513  Stripe new_stripe(offset);
514 
515  // append to the new stripe
516  if (!new_stripe.append(buffer, buf_offset, len)) {
517  qWarning("Kwave::Track::appendAfter FAILED / OOM");
518  return false; /* out of memory */
519  }
520  Q_ASSERT(new_stripe.length() == len);
521 
522 // qDebug("new stripe: [%u ... %u] (%u)", new_stripe->start(),
523 // new_stripe->end(), new_stripe->length());
524 
525  if (index_before >= 0) {
526  // insert after the last one
527  index_before++;
528 // qDebug("Kwave::Track::appendAfter: insert after %p [%10u - %10u]",
529 // stripe, stripe->start(), stripe->end());
530  m_stripes.insert(index_before, new_stripe);
531  } else {
532  // the one and only or insert before all others
533 // qDebug("Kwave::Track::appendAfter: prepending");
534  m_stripes.prepend(new_stripe);
535  index_before = 0;
536  }
537  offset += len;
538  length -= len;
539  buf_offset += len;
540  }
541 
542  return true;
543 }
QList< Stripe > m_stripes
Definition: Track.h:314
#define STRIPE_LENGTH_MAXIMUM
Definition: Track.cpp:46
unsigned int size() const
unsigned int toUint(T x)
Definition: Utils.h:109
sample_index_t length()
Definition: Track.cpp:173
Here is the call graph for this function:
Here is the caller graph for this function:

◆ appendStripe()

void Kwave::Track::appendStripe ( sample_index_t  length)
private

Append a new stripe with a given length.

Parameters
lengthnumber of samples, zero is allowed

Definition at line 92 of file Track.cpp.

References m_stripes, Kwave::Stripe::resize(), sigSamplesInserted(), STRIPE_LENGTH_MAXIMUM, Kwave::toUint(), and unlockedLength().

Referenced by Track().

93 {
95  do {
96  unsigned int len = Kwave::toUint(
97  qMin<sample_index_t>(STRIPE_LENGTH_MAXIMUM, length));
98 
99  Stripe s(start);
100  s.resize(len);
101  if (len) emit sigSamplesInserted(this, start, len);
102 
103  length -= len;
104  start += len;
105  m_stripes.append(s);
106  } while (length);
107 
108 }
void sigSamplesInserted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
sample_index_t unlockedLength()
Definition: Track.cpp:180
#define STRIPE_LENGTH_MAXIMUM
Definition: Track.cpp:46
unsigned int toUint(T x)
Definition: Utils.h:109
sample_index_t length()
Definition: Track.cpp:173
Here is the call graph for this function:
Here is the caller graph for this function:

◆ defragment

void Kwave::Track::defragment ( )
slot

do some defragmentation of stripes

Definition at line 696 of file Track.cpp.

References Kwave::Stripe::combine(), Kwave::Stripe::end(), Kwave::Stripe::length(), m_lock, m_stripes, Kwave::Stripe::start(), STRIPE_LENGTH_MAXIMUM, STRIPE_LENGTH_MINIMUM, and Kwave::toUint().

Referenced by deleteRange(), mergeStripes(), and openWriter().

697 {
698 
699  if (!m_lock.tryLock()) {
700  // this could happen when there are two or more writers
701 // qDebug("Track::defragment() - busy");
702  return;
703  }
704 
705  if (m_stripes.count() > 1)
706  {
707 // qDebug("Track::defragment(), state before:");
708 // dump();
709 
710 // unsigned int index = 0;
711  Kwave::Stripe *before = Q_NULLPTR;
712  Kwave::Stripe *stripe = Q_NULLPTR;
713 
714  // use a quick and simple algorithm:
715  // iterate over all stripes and analyze pairwise
716  QMutableListIterator<Kwave::Stripe> it(m_stripes);
717  while (it.hasNext()) {
718  before = stripe;
719  stripe = &(it.next());
720  if (!before) continue; // skip the first entry
721 // index++;
722 
723 // qDebug("Track::defragment(), checking #%u [%llu..%llu] (%u)",
724 // index, stripe->start(), stripe->end(), stripe->length());
725 
726  const sample_index_t before_start = before->start();
727  const sample_index_t stripe_end = stripe->end();
728  const sample_index_t combined_len = stripe_end - before_start + 1;
729 
730  if (combined_len > STRIPE_LENGTH_MAXIMUM)
731  continue; // would be too large
732 
733  if ((before->length() < STRIPE_LENGTH_MINIMUM) ||
734  (stripe->length() < STRIPE_LENGTH_MINIMUM)) {
735 // qDebug("Track::defragment(), combine #%u [%llu..%llu] & "
736 // "#%u [%llu..%llu] => [%llu..%llu] (%llu)",
737 // index - 1, before->start(), before->end(),
738 // index, stripe->start(), stripe->end(),
739 // before->start(), stripe->end(), combined_len);
740 
741  // try to resize the stripe before to contain the
742  // combined length
743  const unsigned int offset = Kwave::toUint(
744  stripe->start() - before_start);
745  if (!before->combine(offset, *stripe))
746  continue; // not possible, maybe OOM ?
747 
748  // remove the current stripe, to avoid an overlap
749  it.remove();
750  stripe = before;
751 // index--;
752  }
753  }
754 
755 // qDebug("Track::defragment(), state after:");
756 // dump();
757  }
758 
759  m_lock.unlock();
760 }
bool combine(unsigned int offset, Kwave::Stripe &other)
Definition: Stripe.cpp:457
QMutex m_lock
Definition: Track.h:308
unsigned int length() const
Definition: Stripe.cpp:276
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
sample_index_t start() const
Definition: Stripe.cpp:262
#define STRIPE_LENGTH_MAXIMUM
Definition: Track.cpp:46
sample_index_t end() const
Definition: Stripe.cpp:282
#define STRIPE_LENGTH_MINIMUM
Definition: Track.cpp:55
unsigned int toUint(T x)
Definition: Utils.h:109
Here is the call graph for this function:
Here is the caller graph for this function:

◆ deleteRange()

void Kwave::Track::deleteRange ( sample_index_t  offset,
sample_index_t  length,
bool  make_gap = false 
)

Deletes a range of samples

Parameters
offsetindex of the first sample
lengthnumber of samples
make_gapif true, make a gap into the list of stripes instead of moving the stuff from right to left
Note
triggers a defragmentation if make_gap is false

Definition at line 293 of file Track.cpp.

References defragment(), m_lock, sigSamplesDeleted(), and unlockedDelete().

Referenced by Kwave::Signal::deleteRange().

295 {
296  if (!length) return;
297 
298 // qDebug("Kwave::Track::deleteRange() [%u ... %u] (%u)",
299 // offset, offset + length - 1, length);
300 
301  {
302  QMutexLocker lock(&m_lock);
303  unlockedDelete(offset, length, make_gap);
304  }
305 
306  // deletion without gap might have left some fragments
307  if (!make_gap)
308  defragment();
309 
310  emit sigSamplesDeleted(this, offset, length);
311 }
QMutex m_lock
Definition: Track.h:308
void defragment()
Definition: Track.cpp:696
void sigSamplesDeleted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
void unlockedDelete(sample_index_t offset, sample_index_t length, bool make_gap=false)
Definition: Track.cpp:360
sample_index_t length()
Definition: Track.cpp:173
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dump()

void Kwave::Track::dump ( )
private

dump the list of stripes, for debugging

for debugging only

Definition at line 775 of file Track.cpp.

References Kwave::Stripe::end(), Kwave::Stripe::length(), m_stripes, and Kwave::Stripe::start().

776 {
777  qDebug("------------------------------------");
778  unsigned int index = 0;
779  sample_index_t last_end = 0;
780  foreach (const Stripe &s, m_stripes) {
781  sample_index_t start = s.start();
782  if (index && (start <= last_end))
783  qDebug("--- OVERLAP ---");
784  if (start > last_end+1)
785  qDebug(" : GAP [%10lu - %10lu] (%10lu)",
786  static_cast<unsigned long int>(last_end + ((index) ? 1 : 0)),
787  static_cast<unsigned long int>(start - 1),
788  static_cast<unsigned long int>(start - last_end -
789  ((index) ? 1 : 0)));
790  qDebug("#%6d: %p - [%10lu - %10lu] (%10lu)",
791  index++, static_cast<const void *>(&s),
792  static_cast<unsigned long int>(s.start()),
793  static_cast<unsigned long int>(s.end()),
794  static_cast<unsigned long int>(s.length()));
795  last_end = s.end();
796  }
797  qDebug("------------------------------------");
798 }
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
Here is the call graph for this function:

◆ insertSpace()

bool Kwave::Track::insertSpace ( sample_index_t  offset,
sample_index_t  shift 
)

Inserts space at a given offset by moving all stripes that are are starting at or after the given offset right.

Parameters
offsetposition after which everything is moved right
shiftdistance of the shift [samples]
Returns
true if succeeded, false if failed (OOM?)

Definition at line 314 of file Track.cpp.

References Kwave::Stripe::end(), Kwave::Stripe::length(), m_lock, m_stripes, moveRight(), Kwave::Stripe::resize(), sigSamplesInserted(), splitStripe(), Kwave::Stripe::start(), Kwave::toUint(), and unlockedLength().

Referenced by Kwave::Signal::insertSpace().

315 {
316 // qDebug("Kwave::Track::insertSpace(offset=%u,shift=%u)",offset, shift);
317  if (!shift) return true;
318 
319  {
320  QMutexLocker lock(&m_lock);
322  if (offset < len) {
323  // find out whether the offset is within a stripe and
324  // split that one if necessary
325  QMutableListIterator<Stripe> it(m_stripes);
326  while (it.hasNext()) {
327  Stripe &s = it.next();
328  sample_index_t end = s.end();
329  if (end < offset) continue; // skip, stripe is at left
330 
331  sample_index_t start = s.start();
332  if (start >= offset) break; // not "within" the stripe
333 
334 // qDebug("Kwave::Track::insertSpace => splitting [%u...%u]",start,end);
335  Stripe new_stripe = splitStripe(s,
336  Kwave::toUint(offset - start)
337  );
338  if (!new_stripe.length()) return false; // OOM ?
339  it.insert(new_stripe);
340  break;
341  }
342 
343  // move all stripes that are after the offset right
344 // qDebug("Kwave::Track::insertSpace => moving right");
345  moveRight(offset, shift);
346  } else {
347 // qDebug("Kwave::Track::insertSpace => appending stripe at %u", offset + shift - 1);
348  Stripe s(offset + shift - 1);
349  s.resize(1);
350  if (s.length()) m_stripes.append(s);
351  }
352  }
353 
354 // dump();
355  emit sigSamplesInserted(this, offset, shift);
356  return true;
357 }
QMutex m_lock
Definition: Track.h:308
void sigSamplesInserted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
QList< Stripe > m_stripes
Definition: Track.h:314
Stripe splitStripe(Stripe &stripe, unsigned int offset)
Definition: Track.cpp:111
quint64 sample_index_t
Definition: Sample.h:28
sample_index_t unlockedLength()
Definition: Track.cpp:180
unsigned int toUint(T x)
Definition: Utils.h:109
void moveRight(sample_index_t offset, sample_index_t shift)
Definition: Track.cpp:546
Here is the call graph for this function:
Here is the caller graph for this function:

◆ length()

sample_index_t Kwave::Track::length ( )

Returns the length of the track. This is equivalent to the position of the last sample of the last Stripe.

Definition at line 173 of file Track.cpp.

References m_lock, and unlockedLength().

Referenced by appendAfter(), Kwave::Signal::length(), Kwave::SignalManager::loadFile(), openReader(), Kwave::TrackPixmap::repaint(), unlockedDelete(), and Kwave::TrackPixmap::validateBuffer().

174 {
175  QMutexLocker lock(&m_lock);
176  return unlockedLength();
177 }
QMutex m_lock
Definition: Track.h:308
sample_index_t unlockedLength()
Definition: Track.cpp:180
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mergeStripe()

bool Kwave::Track::mergeStripe ( Kwave::Stripe stripe)
private

Merge a single stripe into the track.

Parameters
stripethe stripe to merge
Returns
true if succeeded, false if failed

Definition at line 133 of file Track.cpp.

References Kwave::Stripe::end(), m_stripes, Kwave::Stripe::start(), and unlockedDelete().

Referenced by mergeStripes().

134 {
135  sample_index_t left = stripe.start();
136  sample_index_t right = stripe.end();
137  int index_before = -1;
138 
139 // qDebug("Track::mergeStripe() [%llu - %llu]", left, right);
140 // dump();
141 
142  // remove all stripes that are overlapped completely by
143  // this stripe and crop stripes that overlap partially
144  unlockedDelete(left, right - left + 1, true);
145 
146 // qDebug("Track::mergeStripe() [%llu - %llu] - after delete", left, right);
147 // dump();
148 
149  // find the stripe after which we have to insert
150  QListIterator<Stripe> it(m_stripes);
151  while (it.hasNext()) {
152  const Stripe &s = it.next();
153  if (left > s.end()) index_before = m_stripes.indexOf(s);
154  }
155 
156  if (index_before >= 0) {
157  // insert after some existing stripe
158 // qDebug("Kwave::Track::mergeStripe: insert after index %d",
159 // index_before);
160  m_stripes.insert(index_before + 1, stripe);
161  } else {
162  // the one and only or insert before all others
163 // qDebug("Kwave::Track::mergeStripe: prepending");
164  m_stripes.prepend(stripe);
165  }
166 
167 // qDebug("Track::mergeStripe() - done");
168 // dump();
169  return true;
170 }
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
sample_index_t start() const
Definition: Stripe.cpp:262
sample_index_t end() const
Definition: Stripe.cpp:282
void unlockedDelete(sample_index_t offset, sample_index_t length, bool make_gap=false)
Definition: Track.cpp:360
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mergeStripes()

bool Kwave::Track::mergeStripes ( const Kwave::Stripe::List stripes)

Merge a list of stripes into the track.

Parameters
stripeslist of stripes
Returns
true if succeeded, false if failed
Note
triggers a defragmentation

Definition at line 251 of file Track.cpp.

References defragment(), Kwave::Stripe::List::left(), m_lock, mergeStripe(), Kwave::Stripe::List::right(), and sigSamplesModified().

Referenced by Kwave::Signal::mergeStripes().

252 {
253  bool succeeded = true;
254  {
255  QMutexLocker lock(&m_lock);
256  foreach (Stripe stripe, stripes) {
257  if (!mergeStripe(stripe)) {
258  succeeded = false;
259  break;
260  }
261  }
262  }
263 
264  // do some defragmentation, to combine the ends of the inserted stripes
265  defragment();
266 
267  const sample_index_t left = stripes.left();
268  const sample_index_t right = stripes.right();
269  emit sigSamplesModified(this, left, right - left + 1);
270  return succeeded;
271 }
QMutex m_lock
Definition: Track.h:308
sample_index_t left() const
Definition: Stripe.h:214
void defragment()
Definition: Track.cpp:696
sample_index_t right() const
Definition: Stripe.h:217
quint64 sample_index_t
Definition: Sample.h:28
bool mergeStripe(Kwave::Stripe &stripe)
Definition: Track.cpp:133
void sigSamplesModified(Kwave::Track *src, sample_index_t offset, sample_index_t length)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ moveRight()

void Kwave::Track::moveRight ( sample_index_t  offset,
sample_index_t  shift 
)
private

Move all stripes after an offset to the right. Only looks at the start position of the stripes, comparing with ">=", if the start of a stripe is at the given offset, it will not be moved!

Parameters
offsetposition after which everything is moved right
shiftdistance of the shift [samples]

Definition at line 546 of file Track.cpp.

References m_stripes, Kwave::Stripe::setStart(), and Kwave::Stripe::start().

Referenced by insertSpace(), and writeSamples().

547 {
548  if (m_stripes.isEmpty()) return;
549  QMutableListIterator<Stripe> it(m_stripes);
550  it.toBack();
551  while (it.hasPrevious()) {
552  Stripe &s = it.previous();
553  sample_index_t start = s.start();
554  if (start < offset) break;
555 
556  s.setStart(start + shift);
557  }
558 }
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
Here is the call graph for this function:
Here is the caller graph for this function:

◆ newStripe()

Stripe* Kwave::Track::newStripe ( sample_index_t  start,
unsigned int  length 
)
private

Creates a new stripe with a start position and a length.

Parameters
startoffset of the first sample
lengthnumber of samples, zero is allowed
Note
this must be private, it does no locking !

◆ openReader()

Kwave::SampleReader * Kwave::Track::openReader ( Kwave::ReaderMode  mode,
sample_index_t  left = 0,
sample_index_t  right = SAMPLE_INDEX_MAX 
)

Opens a stream for reading samples. If the last position is omitted, the value UINT_MAX will be used.

Parameters
moderead mode, see Kwave::ReaderMode
leftfirst offset to be read (default = 0)
rightlast position to read (default = UINT_MAX)

Definition at line 274 of file Track.cpp.

References length(), m_lock, stripes(), and unlockedLength().

Referenced by Kwave::Signal::openReader(), and Kwave::TrackPixmap::validateBuffer().

276 {
277  QMutexLocker lock(&m_lock);
278 
280  if (right >= length) right = (length) ? (length - 1) : 0;
281 
282  // collect all stripes that are in the requested range
283  Kwave::Stripe::List stripe_list = stripes(left, right);
284 
285  // create the input stream
286  Kwave::SampleReader *stream =
287  new(std::nothrow) Kwave::SampleReader(mode, stripe_list);
288  Q_ASSERT(stream);
289  return stream;
290 }
QMutex m_lock
Definition: Track.h:308
quint64 sample_index_t
Definition: Sample.h:28
sample_index_t unlockedLength()
Definition: Track.cpp:180
Kwave::Stripe::List stripes(sample_index_t left, sample_index_t right)
Definition: Track.cpp:209
sample_index_t length()
Definition: Track.cpp:173
Here is the call graph for this function:
Here is the caller graph for this function:

◆ openWriter()

Kwave::Writer * Kwave::Track::openWriter ( Kwave::InsertMode  mode,
sample_index_t  left = 0,
sample_index_t  right = 0 
)

Opens a stream for writing samples, starting at a sample position.

Parameters
modespecifies where and how to insert
leftstart of the input (only useful in insert and overwrite mode)
rightend of the input (only useful with overwrite mode)
See also
InsertMode
Note
destruction of the writer triggers defragmentation

Definition at line 188 of file Track.cpp.

References Kwave::connect(), and defragment().

Referenced by Kwave::Signal::openWriter().

191 {
192  // create the input stream
193  Kwave::Writer *stream =
194  new(std::nothrow) Kwave::TrackWriter(*this, mode, left, right);
195  Q_ASSERT(stream);
196 
197  if (stream) {
198  // at the point of time when the writer gets closed we can take
199  // care of fragmentation
200  connect(stream, SIGNAL(destroyed(QObject*)),
201  this, SLOT(defragment()),
202  Qt::DirectConnection);
203  }
204 
205  return stream;
206 }
void defragment()
Definition: Track.cpp:696
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
Here is the call graph for this function:
Here is the caller graph for this function:

◆ release()

void Kwave::Track::release ( )
protected

decrements the usage counter (read lock to m_lock_usage)

Definition at line 769 of file Track.cpp.

References m_lock_usage.

Referenced by Kwave::TrackWriter::~TrackWriter().

770 {
771  m_lock_usage.unlock();
772 }
QReadWriteLock m_lock_usage
Definition: Track.h:311
Here is the caller graph for this function:

◆ select()

void Kwave::Track::select ( bool  select)

Sets the "selected" flag.

Definition at line 464 of file Track.cpp.

References m_selected, selected(), and sigSelectionChanged().

Referenced by toggleSelection().

465 {
466  if (m_selected == selected) return;
469 }
bool selected() const
Definition: Track.h:137
void sigSelectionChanged(bool selected)
bool m_selected
Definition: Track.h:317
Here is the call graph for this function:
Here is the caller graph for this function:

◆ selected()

bool Kwave::Track::selected ( ) const
inline

Returns the "selected" flag.

Definition at line 137 of file Track.h.

Referenced by Kwave::TrackPixmap::repaint(), select(), toggleSelection(), and Kwave::TrackView::TrackView().

137 { return m_selected; }
bool m_selected
Definition: Track.h:317
Here is the caller graph for this function:

◆ sigSamplesDeleted

void Kwave::Track::sigSamplesDeleted ( Kwave::Track src,
sample_index_t  offset,
sample_index_t  length 
)
signal

Emitted if data has been removed from the track.

Parameters
srcsource track of the signal (*this)
offsetposition from which the data was removed
lengthnumber of samples deleted

Referenced by deleteRange().

Here is the caller graph for this function:

◆ sigSamplesInserted

void Kwave::Track::sigSamplesInserted ( Kwave::Track src,
sample_index_t  offset,
sample_index_t  length 
)
signal

Emitted if the track has grown. This implies a modification of the inserted data, so no extra sigSamplesModified is emitted.

Parameters
srcsource track of the signal (*this)
offsetposition from which the data was inserted
lengthnumber of samples inserted
See also
sigSamplesModified

Referenced by appendStripe(), insertSpace(), and writeSamples().

Here is the caller graph for this function:

◆ sigSamplesModified

void Kwave::Track::sigSamplesModified ( Kwave::Track src,
sample_index_t  offset,
sample_index_t  length 
)
signal

Emitted if some data within the track has been modified.

Parameters
srcsource track of the signal (*this)
offsetposition from which the data was modified
lengthnumber of samples modified

Referenced by mergeStripes(), and writeSamples().

Here is the caller graph for this function:

◆ sigSelectionChanged

void Kwave::Track::sigSelectionChanged ( bool  selected)
signal

Emitted whenever the selection of the track has changed.

Parameters
selectedtrue if selected, false if unselected

Referenced by select().

Here is the caller graph for this function:

◆ splitStripe()

Kwave::Stripe Kwave::Track::splitStripe ( Kwave::Stripe stripe,
unsigned int  offset 
)
private

Split a stripe into two stripes. The new stripe will be created from the right portion of the given stripe and the original stripe will be shrinked to it's new size. The newly created stripe will be inserted into m_stripes after the old one.

Parameters
stripethe stripe to be split
offsetthe offset within the stripe, which becomes the first sample in the new stripe
Returns
the new created stripe

Definition at line 111 of file Track.cpp.

References Kwave::Stripe::length(), Kwave::Stripe::resize(), and Kwave::Stripe::start().

Referenced by insertSpace(), unlockedDelete(), and writeSamples().

113 {
114  Q_ASSERT(offset < stripe.length());
115  Q_ASSERT(offset);
116  if (offset >= stripe.length()) return Stripe();
117  if (!offset) return 0;
118 
119  // create a new stripe with the data that has been split off
120  Stripe s(stripe.start() + offset, stripe, offset);
121  if (!s.length()) return Stripe();
122 
123  // shrink the old stripe
124  stripe.resize(offset);
125 
126 // qDebug("Kwave::Track::splitStripe(%p, %u): new stripe at [%u ... %u] (%u)",
127 // stripe, offset, s->start(), s->end(), s->length());
128 
129  return s;
130 }
unsigned int length() const
Definition: Stripe.cpp:276
sample_index_t start() const
Definition: Stripe.cpp:262
Here is the call graph for this function:
Here is the caller graph for this function:

◆ stripes()

Kwave::Stripe::List Kwave::Track::stripes ( sample_index_t  left,
sample_index_t  right 
)

Get a list of stripes that matches a given range of samples

Parameters
leftoffset of the first sample
rightoffset of the last sample
Returns
a list of stripes that cover the given range between left and right

Definition at line 209 of file Track.cpp.

References Kwave::Stripe::deleteRange(), Kwave::Stripe::end(), Kwave::Stripe::length(), m_lock, m_stripes, Kwave::Stripe::resize(), Kwave::Stripe::setStart(), Kwave::Stripe::start(), and Kwave::toUint().

Referenced by openReader(), and Kwave::Signal::stripes().

211 {
212  QMutexLocker lock(&m_lock);
213 
214  // collect all stripes that are in the requested range
215  Kwave::Stripe::List stripes(left, right);
216  foreach (const Stripe &stripe, m_stripes) {
217  if (!stripe.length()) continue;
218  sample_index_t start = stripe.start();
219  sample_index_t end = stripe.end();
220 
221  if (end < left) continue; // not yet in range
222  if (start > right) break; // done
223 
224  if ((end <= right) && (start >= left)) {
225  // append the stripe as it is, unmodified
226  stripes.append(stripe);
227  continue;
228  }
229 
230  // there is only some overlap, no 100% match
231  // -> make a cropped copy
232  Stripe cropped(stripe);
233 
234  // remove data after the end of the selection
235  if (end > right)
236  cropped.resize(Kwave::toUint(cropped.length() - (end - right)));
237 
238  // remove data before the start of the selection
239  if (start < left) {
240  cropped.deleteRange(0, Kwave::toUint(left - start));
241  cropped.setStart(left);
242  }
243 
244  stripes.append(cropped);
245  }
246 
247  return stripes;
248 }
QMutex m_lock
Definition: Track.h:308
QList< Stripe > m_stripes
Definition: Track.h:314
quint64 sample_index_t
Definition: Sample.h:28
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::Stripe::List stripes(sample_index_t left, sample_index_t right)
Definition: Track.cpp:209
Here is the call graph for this function:
Here is the caller graph for this function:

◆ toggleSelection

void Kwave::Track::toggleSelection ( )
slot

toggles the selection of the slot on/off

Definition at line 472 of file Track.cpp.

References select(), and selected().

473 {
474  select(!selected());
475 }
bool selected() const
Definition: Track.h:137
void select(bool select)
Definition: Track.cpp:464
Here is the call graph for this function:

◆ unlockedDelete()

void Kwave::Track::unlockedDelete ( sample_index_t  offset,
sample_index_t  length,
bool  make_gap = false 
)
private

Deletes a range of samples, used internally by deleteRange()

Parameters
offsetindex of the first sample
lengthnumber of samples
make_gapif true, make a gap into the list of stripes instead of moving the stuff from right to left

Definition at line 360 of file Track.cpp.

References Kwave::Stripe::deleteRange(), Kwave::Stripe::end(), length(), Kwave::Stripe::length(), m_stripes, Kwave::Stripe::setStart(), splitStripe(), Kwave::Stripe::start(), and Kwave::toUint().

Referenced by deleteRange(), mergeStripe(), and writeSamples().

362 {
363  if (!length) return;
364 
365  // add all stripes within the specified range to the list
366  sample_index_t left = offset;
367  sample_index_t right = offset + length - 1;
368 
369  QMutableListIterator<Stripe> it(m_stripes);
370  it.toBack();
371  while (it.hasPrevious()) {
372  Stripe &s = it.previous();
373  sample_index_t start = s.start();
374  sample_index_t end = s.end();
375 
376  if (end < left) break; // done, stripe is at left
377  if (start > right) continue; // skip, stripe is at right
378 
379  if ((left <= start) && (right >= end)) {
380  // case #1: total overlap -> delete whole stripe
381 // qDebug("deleting stripe [%u ... %u]", start, end);
382  it.remove(); // decrements the iterator !!!
383  if (m_stripes.isEmpty()) break;
384  continue;
385  } else /* if ((end >= left) && (start <= right)) */ {
386  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
387  // already checked above
388  // partial stripe overlap
389  sample_index_t ofs = (start < left) ? left : start;
390  if (end > right) end = right;
391 // qDebug("deleting [%u ... %u] (start=%u, ofs-start=%u, len=%u)",
392 // ofs, end, start, ofs-start, end - ofs + 1);
393 
394  if (!make_gap ||
395  ((left <= s.start()) && (right < s.end())) ||
396  ((left > s.start()) && (right >= s.end())))
397  {
398  // case #2: delete without creating a gap
399  // case #3: delete from the left only
400  // case #4: delete from the right only
401 // qDebug(" deleting within the stripe");
402  s.deleteRange(
403  Kwave::toUint(ofs - start),
404  Kwave::toUint(end - ofs + 1)
405  );
406  if (!s.length()) break; // OOM ?
407 
408  // if deleted from start
409  if (left <= s.start()) {
410  // move right, producing a (temporary) gap
411 // qDebug("shifting [%u ... %u] to %u",
412 // start, s.end(), end + 1);
413  s.setStart(end + 1);
414  }
415  } else {
416  // case #5: delete from the middle and produce a gap
417  // by splitting off a new stripe
418 // qDebug(" splitting off to new stripe @ %u (ofs=%u)",
419 // right + 1, right + 1 - start);
420  Stripe new_stripe = splitStripe(s,
421  Kwave::toUint(right + 1 - start));
422  if (!new_stripe.length()) break; // OOM ?
423  it.next(); // right after "s"
424  it.insert(new_stripe);
425  it.previous(); // before new_stripe == after s
426  it.previous(); // before s, like
427 
428  // erase to the end (reduce size)
429  const unsigned int todel = Kwave::toUint(s.end() - ofs + 1);
430 // qDebug("ofs-start=%u, s->end()-ofs+1=%u [%u...%u] (%u)",
431 // ofs-start, todel, s.start(), s.end(), s.length());
432  s.deleteRange(Kwave::toUint(ofs - start), todel);
433 // qDebug("length now: %u [%u ... %u]", s.length(),
434 // s.start(), s.end());
435 // Q_ASSERT(s.length());
436  }
437 // Q_ASSERT(s.length());
438  }
439  }
440 
441  // loop over all remaining stripes and move them left
442  // (maybe we start the search one stripe too left,
443  // but this doesn't matter, we don't care...)
444  if (!make_gap) {
445  if (!it.hasNext()) it.toFront();
446 
447  while (it.hasNext()) {
448  Stripe &s = it.next();
449 // qDebug("checking for shift [%u ... %u]",
450 // s.start(), s.end());
451  Q_ASSERT(s.start() != right);
452  if (s.start() > right) {
453  // move left
454 // qDebug("moving stripe %p [%u...%u] %u samples left",
455 // s, s.start(), s.end(), length);
456  Q_ASSERT(s.start() >= length);
457  s.setStart(s.start() - length);
458  }
459  }
460  }
461 }
QList< Stripe > m_stripes
Definition: Track.h:314
Stripe splitStripe(Stripe &stripe, unsigned int offset)
Definition: Track.cpp:111
quint64 sample_index_t
Definition: Sample.h:28
unsigned int toUint(T x)
Definition: Utils.h:109
sample_index_t length()
Definition: Track.cpp:173
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlockedLength()

sample_index_t Kwave::Track::unlockedLength ( )
private

Returns the current length of the stripe in samples. This function uses no locks and is therefore reserved for internal usage from within locked functions.

Note
this must be private, it does no locking !

Definition at line 180 of file Track.cpp.

References Kwave::Stripe::length(), m_stripes, and Kwave::Stripe::start().

Referenced by appendStripe(), insertSpace(), length(), and openReader().

181 {
182  if (m_stripes.isEmpty()) return 0;
183  const Stripe &s = m_stripes.last();
184  return s.start() + s.length();
185 }
QList< Stripe > m_stripes
Definition: Track.h:314
Here is the call graph for this function:
Here is the caller graph for this function:

◆ use()

void Kwave::Track::use ( )
protected

increments the usage counter (read lock to m_lock_usage)

Definition at line 763 of file Track.cpp.

References m_lock_usage.

Referenced by Kwave::TrackWriter::TrackWriter().

764 {
765  m_lock_usage.lockForRead();
766 }
QReadWriteLock m_lock_usage
Definition: Track.h:311
Here is the caller graph for this function:

◆ uuid()

const QUuid& Kwave::Track::uuid ( ) const
inline

returns the unique ID of this track instance

Definition at line 143 of file Track.h.

Referenced by Kwave::SelectionTracker::slotTrackDeleted(), and Kwave::SelectionTracker::slotTrackInserted().

143 { return m_uuid; }
QUuid m_uuid
Definition: Track.h:320
Here is the caller graph for this function:

◆ writeSamples()

bool Kwave::Track::writeSamples ( Kwave::InsertMode  mode,
sample_index_t  offset,
const Kwave::SampleArray buffer,
unsigned int  buf_offset,
unsigned int  length 
)
protected

Write a block of samples. If necessary it starts, appends to, or splits a stripe.

Parameters
modea InsertMode (append/overwrite/insert)
offsetposition where to start the write operation
bufferarray with samples
buf_offsetoffset within the buffer
lengthnumber of samples to write
Returns
true if successful, false if failed (e.g. out of memory)

Definition at line 561 of file Track.cpp.

References Kwave::Append, appendAfter(), Kwave::Stripe::end(), Kwave::Insert, Kwave::Stripe::length(), m_lock, m_stripes, moveRight(), Kwave::Overwrite, sigSamplesInserted(), sigSamplesModified(), splitStripe(), Kwave::Stripe::start(), Kwave::toUint(), and unlockedDelete().

Referenced by Kwave::TrackWriter::write().

566 {
567  Q_ASSERT(length);
568  if (!length) return true; // nothing to do !?
569 
570  switch (mode) {
571  case Kwave::Append: {
572 // qDebug("writeSamples() - Append");
573  bool appended;
574  {
575  QMutexLocker _lock(&m_lock);
576  appended = appendAfter(
577  m_stripes.isEmpty() ? Q_NULLPTR : &(m_stripes.last()),
578  offset, buffer,
579  buf_offset, length);
580  }
581  if (appended)
582  emit sigSamplesInserted(this, offset, length);
583  else
584  return false; /* out of memory */
585  break;
586  }
587  case Kwave::Insert: {
588  m_lock.lock();
589 
590 // qDebug("Kwave::Track::writeSamples() - Insert @ %u, length=%u",
591 // offset, length);
592 
593  // find the stripe into which we insert
594  Stripe *target_stripe = Q_NULLPTR;
595  Stripe *stripe_before = Q_NULLPTR;
596  QMutableListIterator<Stripe> it(m_stripes);
597  while (it.hasNext()) {
598  Stripe &s = it.next();
599  sample_index_t st = s.start();
600  sample_index_t len = s.length();
601  if (!len) continue; // skip zero-length tracks
602 
603  if (offset >= st + len) stripe_before = &s;
604 
605  if ((offset >= st) && (offset < st+len)) {
606  // match found
607  target_stripe = &s;
608  break;
609  }
610  }
611 
612 // qDebug("stripe_before = %p [%u...%u]", stripe_before,
613 // stripe_before ? stripe_before->start() : 0,
614 // stripe_before ? (stripe_before->start() +
615 // stripe_before->length() - 1) : 0);
616 // qDebug("target_stripe = %p [%u...%u]", target_stripe,
617 // target_stripe ? target_stripe->start() : 0,
618 // target_stripe ? (target_stripe->start() +
619 // target_stripe->length() - 1) : 0);
620 
621  // if insert is requested immediately after the last
622  // sample of the stripe before
623  if (stripe_before && (offset == stripe_before->start()+
624  stripe_before->length()))
625  {
626  // append to the existing stripe
627  moveRight(offset, length);
628  appendAfter(stripe_before, offset, buffer,
629  buf_offset, length);
630  m_lock.unlock();
631  emit sigSamplesInserted(this, offset, length);
632  break;
633  }
634 
635  // if no stripe was found, create a new one and
636  // insert it between the existing ones
637  if (!target_stripe || (offset == target_stripe->start())) {
638  // insert somewhere before, between or after stripes
639  moveRight(offset, length);
640  appendAfter(stripe_before, offset, buffer,
641  buf_offset, length);
642  } else {
643  // split the target stripe and insert the samples
644  // between the two new ones
645  Stripe new_stripe = splitStripe(*target_stripe,
646  Kwave::toUint(offset - target_stripe->start())
647  );
648  if (!new_stripe.length()) {
649  m_lock.unlock();
650  break;
651  }
652  m_stripes.insert(m_stripes.indexOf(*target_stripe) + 1,
653  new_stripe);
654 
655  moveRight(offset, length);
656  appendAfter(target_stripe, offset, buffer,
657  buf_offset, length);
658  }
659 
660  m_lock.unlock();
661  emit sigSamplesInserted(this, offset, length);
662 
663  break;
664  }
665  case Kwave::Overwrite: {
666 // const sample_index_t left = offset;
667 // const sample_index_t right = offset + length - 1;
668 // qDebug("writeSamples() - Overwrite [%u - %u]", left, right);
669 
670  {
671  QMutexLocker _lock(&m_lock);
672 
673  // delete old content, producing a gap
674  unlockedDelete(offset, length, true);
675 
676  // fill in the content of the buffer, append to the stripe
677  // before the gap if possible
678  Stripe *stripe_before = Q_NULLPTR;
679  QMutableListIterator<Stripe> it(m_stripes);
680  while (it.hasNext()) {
681  Stripe &s = it.next();
682  if (s.start() >= offset) break;
683  if (s.end() < offset) stripe_before = &s;
684  }
685  appendAfter(stripe_before, offset, buffer, buf_offset, length);
686  }
687  emit sigSamplesModified(this, offset, length);
688  break;
689  }
690  }
691 
692  return true;
693 }
QMutex m_lock
Definition: Track.h:308
void sigSamplesInserted(Kwave::Track *src, sample_index_t offset, sample_index_t length)
QList< Stripe > m_stripes
Definition: Track.h:314
bool appendAfter(Stripe *stripe, sample_index_t offset, const Kwave::SampleArray &buffer, unsigned int buf_offset, unsigned int length)
Definition: Track.cpp:478
Stripe splitStripe(Stripe &stripe, unsigned int offset)
Definition: Track.cpp:111
quint64 sample_index_t
Definition: Sample.h:28
void sigSamplesModified(Kwave::Track *src, sample_index_t offset, sample_index_t length)
unsigned int toUint(T x)
Definition: Utils.h:109
void unlockedDelete(sample_index_t offset, sample_index_t length, bool make_gap=false)
Definition: Track.cpp:360
sample_index_t length()
Definition: Track.cpp:173
void moveRight(sample_index_t offset, sample_index_t shift)
Definition: Track.cpp:546
Here is the call graph for this function:
Here is the caller graph for this function:

Friends And Related Function Documentation

◆ Kwave::TrackWriter

friend class Kwave::TrackWriter
friend

Definition at line 271 of file Track.h.

Member Data Documentation

◆ m_lock

QMutex Kwave::Track::m_lock
private

lock for access to the whole track

Definition at line 308 of file Track.h.

Referenced by defragment(), deleteRange(), insertSpace(), length(), mergeStripes(), openReader(), stripes(), writeSamples(), and ~Track().

◆ m_lock_usage

QReadWriteLock Kwave::Track::m_lock_usage
private

lock to protect against deletion while the track is in use

Definition at line 311 of file Track.h.

Referenced by release(), use(), and ~Track().

◆ m_selected

bool Kwave::Track::m_selected
private

True if the track is selected

Definition at line 317 of file Track.h.

Referenced by select().

◆ m_stripes

QList<Stripe> Kwave::Track::m_stripes
private

list of stripes (a track actually is a container for stripes)

Definition at line 314 of file Track.h.

Referenced by appendAfter(), appendStripe(), defragment(), dump(), insertSpace(), mergeStripe(), moveRight(), stripes(), Track(), unlockedDelete(), unlockedLength(), writeSamples(), and ~Track().

◆ m_uuid

QUuid Kwave::Track::m_uuid
private

unique ID

Definition at line 320 of file Track.h.


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