kwave  18.07.70
MetaDataList.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  MetaDataList.cpp - list with meta data objects
3  -------------------
4  begin : Sat Mar 06 2010
5  copyright : (C) 2010 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 <algorithm>
21 
22 #include "libkwave/MetaDataList.h"
23 #include "libkwave/String.h"
24 #include "libkwave/Utils.h"
25 
26 //***************************************************************************
28  :QMap<QString, Kwave::MetaData>()
29 {
30 }
31 
32 //***************************************************************************
34  :QMap<QString, Kwave::MetaData>()
35 {
36  add(meta);
37 }
38 
39 //***************************************************************************
41 {
42 }
43 
44 //***************************************************************************
45 static bool isLessThan(const Kwave::MetaData &m1, const Kwave::MetaData &m2)
46 {
47  return m1.firstSample() < m2.firstSample();
48 }
49 
50 //***************************************************************************
51 QList<Kwave::MetaData> Kwave::MetaDataList::toSortedList() const
52 {
53  QList<Kwave::MetaData> list = this->values();
54 
55  if (!list.isEmpty())
56  std::stable_sort(list.begin(), list.end(), isLessThan);
57 
58  return list;
59 }
60 
61 //***************************************************************************
63 {
65 }
66 
67 //***************************************************************************
69  MetaData::Scope scope) const
70 {
72 
73  Iterator it(*this);
74  while (it.hasNext()) {
75  it.next();
76  const Kwave::MetaData &m = it.value();
77  if (m.scope() == scope)
78  list.add(m);
79  }
80  return list;
81 }
82 
83 //***************************************************************************
85  const QList<unsigned int> &tracks) const
86 {
88  Iterator it(*this);
89  while (it.hasNext()) {
90  // iterate over all meta data items
91  it.next();
92  const Kwave::MetaData &m = it.value();
93  bool match = true;
95  // iterate over the list of tracks of the item
96  match = false;
97  QList<QVariant> track_list =
99  foreach (const QVariant &v, track_list) {
100  bool ok = false;
101  unsigned int t = v.toUInt(&ok);
102  Q_ASSERT(ok);
103  if (ok && (tracks.contains(t))) {
104  match = true;
105  break;
106  }
107  }
108  }
109  if (match) {
110  Q_ASSERT(!list.keys().contains(m.id()));
111  if (!list.keys().contains(m.id())) list.add(m);
112  }
113  }
114  return list;
115 }
116 
117 //***************************************************************************
119  sample_index_t first, sample_index_t last) const
120 {
121  Kwave::MetaDataList list;
122 
123  Iterator it(*this);
124  while (it.hasNext()) {
125  it.next();
126  const Kwave::MetaData &m = it.value();
127  if (m.scope() == Kwave::MetaData::Range) {
130  {
131  // check for overlap with a meta data that has a range
132  bool start_ok = false, end_ok = false;
133  const sample_index_t start =
134  m[Kwave::MetaData::STDPROP_START].toULongLong(&start_ok);
135  const sample_index_t end =
136  m[Kwave::MetaData::STDPROP_END].toULongLong(&end_ok);
137  if (!start_ok || !end_ok) continue;
138 
139  if ((start <= last) && (end >= first))
140  list.add(m);
141  }
142  }
143  else if (m.scope() == Kwave::MetaData::Position) {
145  // check for position within the range
146  bool pos_ok = false;
147  const sample_index_t pos =
148  m[Kwave::MetaData::STDPROP_POS].toLongLong(&pos_ok);
149  if (pos_ok && (pos >= first) && (pos <= last))
150  list.add(m);
151  }
152  }
153  }
154  return list;
155 }
156 
157 //***************************************************************************
159  sample_index_t pos) const
160 {
161  Kwave::MetaDataList list;
162 
163  Iterator it(*this);
164  while (it.hasNext()) {
165  it.next();
166  const Kwave::MetaData &m = it.value();
167  if (m.scope() == Kwave::MetaData::Position) {
169  // check for position within the range
170  bool pos_ok = false;
171  const sample_index_t p =
172  m[Kwave::MetaData::STDPROP_POS].toLongLong(&pos_ok);
173  if (pos_ok && (p == pos))
174  list.add(m);
175  }
176  }
177  }
178  return list;
179 }
180 
181 //***************************************************************************
183  const QString &property) const
184 {
185  Kwave::MetaDataList list;
186 
187  Iterator it(*this);
188  while (it.hasNext()) {
189  it.next();
190  const Kwave::MetaData &m = it.value();
191  if (m.hasProperty(property))
192  list.add(m);
193  }
194  return list;
195 }
196 
197 //***************************************************************************
199  const QString &property, QVariant value) const
200 {
201  Kwave::MetaDataList list;
202 
203  Iterator it(*this);
204  while (it.hasNext()) {
205  it.next();
206  const Kwave::MetaData &m = it.value();
207  if (m.hasProperty(property) && (m[property] == value))
208  list.add(m);
209  }
210  return list;
211 }
212 
213 //***************************************************************************
215 {
216  QString id = metadata.id();
217 
218  Iterator it(*this);
219  while (it.hasNext()) {
220  it.next();
221  const Kwave::MetaData &m = it.value();
222  if (m.id() == id)
223  return true;
224  }
225  return false;
226 }
227 
228 //***************************************************************************
230 {
231  if (list.isEmpty()) return;
232 
233  // find out which meta data types are affected
234  QStringList types;
235  foreach (const Kwave::MetaData &meta, list) {
236  QString type = meta[Kwave::MetaData::STDPROP_TYPE].toString();
237  if (!types.contains(type)) {
238  // remember this type in our list
239  types.append(type);
240 
241  // remove all elements of that type that are not in the new list
242  MutableIterator it(*this);
243  while (it.hasNext()) {
244  it.next();
245  Kwave::MetaData &m = it.value();
246  if (m[Kwave::MetaData::STDPROP_TYPE] == type) {
247  if (!list.contains(m)) {
248  it.remove();
249  }
250  }
251  }
252  }
253  }
254 
255  // now the same as in add() has to be done
256  add(list);
257 }
258 
259 //***************************************************************************
261 {
262  if (!metadata.isNull())
263  (*this)[metadata.id()] = metadata;
264  else
265  remove(metadata);
266 }
267 
268 //***************************************************************************
270 {
271  foreach (const Kwave::MetaData &metadata, list)
272  add(metadata);
273 }
274 
275 //***************************************************************************
277 {
278  if (contains(metadata))
279  QMap<QString, Kwave::MetaData>::remove(metadata.id());
280 }
281 
282 //***************************************************************************
284 {
285  foreach (const Kwave::MetaData &metadata, list)
286  remove(metadata);
287 }
288 
289 //***************************************************************************
291  sample_index_t last)
292 {
293 
294  MutableIterator it(*this);
295  while (it.hasNext()) {
296  it.next();
297  Kwave::MetaData &m = it.value();
298 
299  if (m.scope() & Kwave::MetaData::Position) {
300  // if the meta data is bound to a position, remove it if
301  // it is out of scope and adjust the position if it is
302  // within the selection
303  const QVariant v_pos = m[Kwave::MetaData::STDPROP_POS];
304  bool ok = false;
305  sample_index_t pos = static_cast<sample_index_t>(
306  v_pos.toULongLong(&ok));
307  if (!ok) continue;
308 
309  if ((pos < first) || (pos > last)) {
310  // out of the selected area -> remove
311  it.remove();
312  continue;
313  }
314  } else if (m.scope() & Kwave::MetaData::Range) {
315  // if the meta data is bound to a scope, remove it if
316  // it does not overlap with the current selection,
317  // otherwise clip it to the bounds of the current selection
318  const QVariant v_start = m[Kwave::MetaData::STDPROP_START];
319  bool ok = false;
320  sample_index_t start = static_cast<sample_index_t>(
321  v_start.toULongLong(&ok));
322  if (!ok) continue;
323 
324  const QVariant v_end = m[Kwave::MetaData::STDPROP_END];
325  ok = false;
326  sample_index_t end = static_cast<sample_index_t>(
327  v_start.toULongLong(&ok));
328  if (!ok) continue;
329 
330  if ((end < start) || (start >= last)) {
331  // out of the selected area -> remove
332  it.remove();
333  continue;
334  } else {
335  // clip to the seleced range
336  if (start < first) start = first;
337  if (end > last) end = last;
338 
339  // adjust start and end
342  }
343 
344  }
345  }
346 
347 }
348 
349 //***************************************************************************
350 void Kwave::MetaDataList::cropByTracks(const QList<unsigned int> &tracks)
351 {
352  MutableIterator it(*this);
353  while (it.hasNext()) {
354  it.next();
355  const Kwave::MetaData &m = it.value();
356 
357  if (m.scope() & Kwave::MetaData::Track) {
359  // convert the track list into a usable list of unsigned int
360  QList<QVariant> v_track_list =
362  QList<unsigned int> bound_tracks;
363  foreach (const QVariant &v, v_track_list) {
364  bool ok = false;
365  unsigned int t = v.toUInt(&ok);
366  if (ok) bound_tracks += t;
367  }
368 
369  foreach (unsigned int t, bound_tracks)
370  if (!tracks.contains(t)) bound_tracks.removeAll(t);
371  if (bound_tracks.isEmpty()) {
372  // no overlapping track indices -> remove
373  it.remove();
374  continue;
375  }
376 
377  // do the renumbering
378  v_track_list.clear();
379  for (int i = 0; i < bound_tracks.count(); i++)
380  v_track_list.append(Kwave::toUint(i));
381 
382  // set a new track list
383  m[Kwave::MetaData::STDPROP_TRACKS] = v_track_list;
384  }
385  }
386  }
387 }
388 
389 //***************************************************************************
391  sample_index_t length, const QList<unsigned int> &tracks) const
392 {
393  if (!length)
394  return Kwave::MetaDataList(); // no range selected - empty list
395 
396  Kwave::MetaDataList list(*this);
397  list.cropByRange(offset, offset + length - 1);
398  list.cropByTracks(tracks);
399  return list;
400 }
401 
402 //***************************************************************************
404 {
405  if (meta_data.isEmpty())
406  return; // shortcut: bail out if empty
407 
408  const QStringList position_bound_properties =
410 
411  foreach (const Kwave::MetaData &meta, meta_data) {
412  // check if some meta data with the same type already
413  // exists at an overlapping position
414  bool found = false;
416  MutableIterator it(*this);
417  while (it.hasNext()) {
418  it.next();
419  Kwave::MetaData &other = it.value();
420 
421  /* --- analysis phase --- */
422 
423  // check: both have the same type?
425  continue;
426  if (other[Kwave::MetaData::STDPROP_TYPE] !=
428  continue;
429 
430  // check: sampe scope?
431  if (!(meta.scope() == other.scope()))
432  continue;
433 
434  // check: ranges overlap or touch?
435  sample_index_t meta_first = meta.firstSample();
436  sample_index_t meta_last = meta.lastSample();
437  sample_index_t other_first = other.firstSample();
438  sample_index_t other_last = other.lastSample();
439  if ((meta_last < other_first) && (meta_last + 1 != other_first))
440  continue;
441  if ((meta_first > other_last) && (meta_first != other_last + 1))
442  continue;
443 
444  // determine list of overlapping/non-overlapping tracks
445  QList<unsigned int> overlapping_tracks;
446  QList<unsigned int> non_overlapping_tracks;
449  {
450  QList<unsigned int> meta_tracks = meta.boundTracks();
451  QList<unsigned int> other_tracks = other.boundTracks();
452 
453  foreach (unsigned int t, meta_tracks) {
454  if (other_tracks.contains(t))
455  overlapping_tracks.append(t);
456  else
457  non_overlapping_tracks.append(t);
458  }
459  }
460 
461  // check: no overlapping tracks?
462  if (overlapping_tracks.isEmpty())
463  continue;
464 
465  // check: all non-positional properties have to match
466  bool match = true;
467  foreach (const QString &p, meta.keys()) {
468  if (!other.hasProperty(p)) {
469  match = false;
470  break;
471  }
472 
473  // ignore internal properties
475  continue;
476  if (position_bound_properties.contains(p))
477  continue;
478 
479  if (meta[p] != other[p]) {
480  match = false;
481  break;
482  }
483  }
484  if (!match) continue;
485 
486  /* --- merge phase --- */
487 
488  found = true;
489 
490  // split all data bound to non-overlapping tracks into
491  // a separate meta data object
492  if (!non_overlapping_tracks.isEmpty()) {
493  Kwave::MetaData copy = other;
494 
495  QVariantList list;
496  foreach (unsigned int t, non_overlapping_tracks)
497  list.append(QVariant(t));
499 
500  list.clear();
501  foreach (unsigned int t, overlapping_tracks)
502  list.append(QVariant(t));
504 
505  add(copy);
506  }
507 
508  // merge range
510  other.setProperty(
512  qMin(meta_first, other_first));
513  }
515  other.setProperty(
517  qMax(meta_last, other_last));
518  }
519  }
520  }
521 
522  // no matching meta data item for merging found => add as new one
523  if (!found) {
524  add(meta);
525  }
526  }
527 }
528 
529 //***************************************************************************
531  sample_index_t length,
532  const QList<unsigned int> &tracks)
533 {
534  const sample_index_t del_first = offset;
535  const sample_index_t del_last = offset + length - 1;
536 
537  if (!length) return;
538 
539  MutableIterator it(*this);
540  while (it.hasNext()) {
541  it.next();
542  Kwave::MetaData &meta = it.value();
543 
544  sample_index_t meta_first = meta.firstSample();
545  sample_index_t meta_last = meta.lastSample();
546 
547  // check: range overlap?
548  if ((meta_first > del_last) || (meta_last < del_first))
549  continue;
550 
551  // only operate on the matching tracks:
552  if (!tracks.isEmpty() &&
554 
555  // determine list of overlapping/non-overlapping tracks
556  QList<unsigned int> overlapping_tracks;
557  QList<unsigned int> non_overlapping_tracks;
558  QList<unsigned int> meta_tracks = meta.boundTracks();
559 
560  foreach (unsigned int t, meta_tracks) {
561  if (tracks.contains(t))
562  overlapping_tracks.append(t);
563  else
564  non_overlapping_tracks.append(t);
565  }
566 
567  // skip if no overlap
568  if (overlapping_tracks.isEmpty())
569  continue;
570 
571  // split all data bound to non-overlapping tracks into
572  // a separate meta data object
573  if (!non_overlapping_tracks.isEmpty()) {
574  Kwave::MetaData copy = meta;
575 
576  QVariantList list;
577  foreach (unsigned int t, overlapping_tracks)
578  list.append(QVariant(t));
580 
581  list.clear();
582  foreach (unsigned int t, non_overlapping_tracks)
583  list.append(QVariant(t));
585 
586  add(copy);
587  }
588  }
589 
590  /* --- we have a position/range/track overlap --- */
591 
592  // position bound -> remove completely
594  it.remove();
595  continue;
596  }
597 
598  // complete overlap -> remove completely
599  if ((meta.scope() & Kwave::MetaData::Range) &&
600  (meta_first >= del_first) && (meta_last <= del_last)) {
601  it.remove();
602  continue;
603  }
604 
605  // check: no range -> no adjustment
608  continue;
609  }
610 
611  // cut out a piece from the middle -> adjust right
612  if ((del_first > meta_first) && (del_last < meta_last)) {
613  meta_last -= length;
614  meta[Kwave::MetaData::STDPROP_END] = QVariant(meta_last);
615  continue;
616  }
617 
618  // cut away a part from left
619  if (del_last < meta_last) {
620  meta[Kwave::MetaData::STDPROP_START] = QVariant(del_last + 1);
621  continue;
622  }
623 
624  // cut away a part from right
625  if (del_first > meta_first) {
626  meta[Kwave::MetaData::STDPROP_END] = QVariant(del_first - 1);
627  continue;
628  }
629 
630  Q_ASSERT(false); // we should never reach this, no overlap?
631  }
632 }
633 
634 //***************************************************************************
636  const QList<unsigned int> &tracks)
637 {
638  MutableIterator it(*this);
639  while (it.hasNext()) {
640  it.next();
641  Kwave::MetaData &meta = it.value();
642 
643  sample_index_t meta_first = meta.firstSample();
644  sample_index_t meta_last = meta.lastSample();
645 
646  // check: is it before the offset ?
647  if (meta_first < offset)
648  continue;
649 
650  // only operate on the matching tracks:
651  if (!tracks.isEmpty() &&
653 
654  // determine list of overlapping/non-overlapping tracks
655  QList<unsigned int> overlapping_tracks;
656  QList<unsigned int> non_overlapping_tracks;
657  QList<unsigned int> meta_tracks = meta.boundTracks();
658 
659  foreach (unsigned int t, meta_tracks) {
660  if (tracks.contains(t))
661  overlapping_tracks.append(t);
662  else
663  non_overlapping_tracks.append(t);
664  }
665 
666  // skip if no overlap
667  if (overlapping_tracks.isEmpty())
668  continue;
669 
670  // split all data bound to non-overlapping tracks into
671  // a separate meta data object
672  if (!non_overlapping_tracks.isEmpty()) {
673  Kwave::MetaData copy = meta;
674 
675  QVariantList list;
676  foreach (unsigned int t, overlapping_tracks)
677  list.append(QVariant(t));
679 
680  list.clear();
681  foreach (unsigned int t, non_overlapping_tracks)
682  list.append(QVariant(t));
684 
685  add(copy);
686  }
687  }
688 
689  /* --- we have a position/range/track overlap --- */
690 
691  // position bound -> move position
693  bool ok = false;
694  sample_index_t pos = static_cast<sample_index_t>(
695  meta[Kwave::MetaData::STDPROP_POS].toULongLong(&ok));
696  if (!ok) continue;
697 
698  if (pos >= shift) {
699  // shift position left
700  meta[Kwave::MetaData::STDPROP_POS] = pos - shift;
701  } else {
702  // do not produce negative coordinates
703  // -> moving into negative means deleting!
704  it.remove();
705  }
706  continue;
707  }
708 
709  // check: no range -> no adjustment
712  continue;
713  }
714 
715  // check: moving into negative
716  Q_ASSERT(meta_last >= shift);
717  if (meta_last < shift) {
718  it.remove();
719  continue;
720  }
721 
722  // move to the left, clip start to zero
723  Q_ASSERT(meta_first >= shift);
724  meta_first = (meta_first >= shift) ? (meta_first - shift) : 0;
725  meta_last -= shift;
726 
728  meta[Kwave::MetaData::STDPROP_START] = QVariant(meta_first);
730  meta[Kwave::MetaData::STDPROP_END] = QVariant(meta_last);
731  }
732 }
733 
734 //***************************************************************************
736  const QList<unsigned int> &tracks)
737 {
738  MutableIterator it(*this);
739  it.toBack();
740  while (it.hasPrevious()) {
741  it.previous();
742  Kwave::MetaData &meta = it.value();
743 
744  sample_index_t meta_first = meta.firstSample();
745  sample_index_t meta_last = meta.lastSample();
746 
747  // check: is it before the offset ?
748  if (meta_last < offset)
749  continue;
750 
751  // only operate on the matching tracks:
752  if (!tracks.isEmpty() &&
754 
755  // determine list of overlapping/non-overlapping tracks
756  QList<unsigned int> overlapping_tracks;
757  QList<unsigned int> non_overlapping_tracks;
758  QList<unsigned int> meta_tracks = meta.boundTracks();
759 
760  foreach (unsigned int t, meta_tracks) {
761  if (tracks.contains(t))
762  overlapping_tracks.append(t);
763  else
764  non_overlapping_tracks.append(t);
765  }
766 
767  // skip if no overlap
768  if (overlapping_tracks.isEmpty())
769  continue;
770 
771  // split all data bound to non-overlapping tracks into
772  // a separate meta data object
773  if (!non_overlapping_tracks.isEmpty()) {
774  Kwave::MetaData copy = meta;
775 
776  QVariantList list;
777  foreach (unsigned int t, overlapping_tracks)
778  list.append(QVariant(t));
780 
781  list.clear();
782  foreach (unsigned int t, non_overlapping_tracks)
783  list.append(QVariant(t));
785 
786  add(copy);
787  }
788  }
789 
790  /* --- we have a position/range/track overlap --- */
791 
792  // position bound -> move position
794  bool ok = false;
795  sample_index_t pos = static_cast<sample_index_t>(
796  meta[Kwave::MetaData::STDPROP_POS].toULongLong(&ok));
797  if (!ok) continue;
798 
799  Q_ASSERT(pos + shift >= pos);
800  if (pos + shift >= pos) {
801  // shift position right
802  meta[Kwave::MetaData::STDPROP_POS] = pos + shift;
803  } else {
804  // do not produce a coordinate overflow
805  // -> moving outside range means deleting!
806  it.remove();
807  }
808  continue;
809  }
810 
811  // check: no range -> no adjustment
814  continue;
815  }
816 
817  // check: range overflow
818  Q_ASSERT(meta_first + shift >= meta_first);
819  if (meta_first + shift < meta_first) {
820  it.remove();
821  continue;
822  }
823 
824  // move to the right, clip end to maximum coordinate
825  Q_ASSERT(meta_last + shift >= meta_last);
826  meta_last = (meta_last + shift >= meta_last) ?
827  (meta_last + shift) : SAMPLE_INDEX_MAX;
828  if (meta_first >= offset)
829  meta_first += shift;
830 
832  meta[Kwave::MetaData::STDPROP_START] = QVariant(meta_first);
834  meta[Kwave::MetaData::STDPROP_END] = QVariant(meta_last);
835  }
836 }
837 
838 //***************************************************************************
840  const QList<unsigned int> &tracks)
841 {
842  MutableIterator it(*this);
843  while (it.hasNext()) {
844  it.next();
845  Kwave::MetaData &meta = it.value();
846 
847  sample_index_t meta_first = meta.firstSample();
848  sample_index_t meta_last = meta.lastSample();
849 
850  // only operate on the matching tracks:
851  if (!tracks.isEmpty() &&
853 
854  // determine list of overlapping/non-overlapping tracks
855  QList<unsigned int> overlapping_tracks;
856  QList<unsigned int> non_overlapping_tracks;
857  QList<unsigned int> meta_tracks = meta.boundTracks();
858 
859  foreach (unsigned int t, meta_tracks) {
860  if (tracks.contains(t))
861  overlapping_tracks.append(t);
862  else
863  non_overlapping_tracks.append(t);
864  }
865 
866  // skip if no overlap
867  if (overlapping_tracks.isEmpty())
868  continue;
869 
870  // split all data bound to non-overlapping tracks into
871  // a separate meta data object
872  if (!non_overlapping_tracks.isEmpty()) {
873  Kwave::MetaData copy = meta;
874 
875  QVariantList list;
876  foreach (unsigned int t, overlapping_tracks)
877  list.append(QVariant(t));
879 
880  list.clear();
881  foreach (unsigned int t, non_overlapping_tracks)
882  list.append(QVariant(t));
884 
885  add(copy);
886  }
887  }
888 
889  /* --- we have a position/range/track overlap --- */
890 
891  // position bound -> move position
893  bool ok = false;
894  sample_index_t pos = static_cast<sample_index_t>(
895  meta[Kwave::MetaData::STDPROP_POS].toULongLong(&ok));
896  if (!ok) continue;
897 
898  if ((pos * scale) <= SAMPLE_INDEX_MAX) {
899  // scale position
900  meta[Kwave::MetaData::STDPROP_POS] = (pos * scale);
901  } else {
902  // do not produce a coordinate overflow
903  // -> moving outside range means deleting!
904  it.remove();
905  }
906  continue;
907  }
908 
909  // check: no range -> no adjustment
912  continue;
913  }
914 
915  // check: range overflow
916  if ((meta_first * scale) >= SAMPLE_INDEX_MAX) {
917  it.remove();
918  continue;
919  }
920 
921  // scale, clip end to maximum coordinate
922  meta_last = static_cast<sample_index_t>(
923  qMin<double>(SAMPLE_INDEX_MAX, meta_last * scale));
924  meta_first = static_cast<sample_index_t>(meta_first * scale);
925 
927  meta[Kwave::MetaData::STDPROP_START] = QVariant(meta_first);
929  meta[Kwave::MetaData::STDPROP_END] = QVariant(meta_last);
930  }
931 }
932 
933 //***************************************************************************
934 void Kwave::MetaDataList::insertTrack(unsigned int track)
935 {
936  const QString prop = Kwave::MetaData::STDPROP_TRACKS;
937  MutableIterator it(*this);
938  while (it.hasNext()) {
939  it.next();
940  const Kwave::MetaData &m = it.value();
941  if (m.hasProperty(prop)) {
942  // iterate over the list of tracks
943  QList<QVariant> old_list = m[prop].toList();
944  QList<QVariant> new_list;
945  foreach (const QVariant &v, old_list) {
946  bool ok = false;
947  unsigned int t = v.toUInt(&ok);
948  if (ok && (t >= track))
949  new_list.append(QVariant(t + 1));
950  else
951  new_list.append(v);
952  }
953  m[prop] = new_list; // set updated list of bound tracks
954  }
955  }
956 }
957 
958 //***************************************************************************
959 void Kwave::MetaDataList::deleteTrack(unsigned int track)
960 {
961  const QString prop = Kwave::MetaData::STDPROP_TRACKS;
962  MutableIterator it(*this);
963  while (it.hasNext()) {
964  it.next();
965  Kwave::MetaData &m = it.value();
966  if (m.hasProperty(prop)) {
967  // iterate over the list of tracks
968  QList<QVariant> old_list = m[prop].toList();
969  QList<QVariant> new_list;
970  foreach (const QVariant &v, old_list) {
971  bool ok = false;
972  unsigned int t = v.toUInt(&ok);
973  Q_ASSERT(ok);
974  if (!ok) continue;
975  if (t < track)
976  new_list.append(v);
977  else if (t > track)
978  new_list.append(QVariant(t - 1));
979  }
980  if (!new_list.isEmpty())
981  m[prop] = new_list; // set updated list of bound tracks
982  else
983  it.remove(); // list is empty now -> delete whole item
984  }
985  }
986 }
987 
988 //***************************************************************************
990  const QList<unsigned int> &tracks)
991 {
992  // check: splitting at offset zero makes no sense, but is not forbidden
993  if (!offset) return;
994 
995  MutableIterator it(*this);
996  while (it.hasNext()) {
997  it.next();
998  Kwave::MetaData &meta = it.value();
999 
1000  sample_index_t meta_first = meta.firstSample();
1001  sample_index_t meta_last = meta.lastSample();
1002 
1003  // check: is the split done in our range?
1004  if ((offset <= meta_first) || (offset > meta_last))
1005  continue;
1006 
1007  // check: no range -> no splitting
1010  continue;
1011  }
1012 
1013  // only operate on the matching tracks:
1014  if (!tracks.isEmpty() &&
1016 
1017  // determine list of overlapping/non-overlapping tracks
1018  QList<unsigned int> overlapping_tracks;
1019  QList<unsigned int> non_overlapping_tracks;
1020  QList<unsigned int> meta_tracks = meta.boundTracks();
1021 
1022  foreach (unsigned int t, meta_tracks) {
1023  if (tracks.contains(t))
1024  overlapping_tracks.append(t);
1025  else
1026  non_overlapping_tracks.append(t);
1027  }
1028 
1029  // skip if no overlap
1030  if (overlapping_tracks.isEmpty())
1031  continue;
1032 
1033  // split all data bound to non-overlapping tracks into
1034  // a separate meta data object
1035  if (!non_overlapping_tracks.isEmpty()) {
1036  Kwave::MetaData copy = meta;
1037 
1038  QVariantList list;
1039  foreach (unsigned int t, overlapping_tracks)
1040  list.append(QVariant(t));
1042 
1043  list.clear();
1044  foreach (unsigned int t, non_overlapping_tracks)
1045  list.append(QVariant(t));
1047 
1048  add(copy);
1049  }
1050  }
1051 
1052  /* --- we have a range/track overlap --- */
1053 
1054  Kwave::MetaData copy = meta;
1055  copy[Kwave::MetaData::STDPROP_START] = QVariant(offset);
1056  meta[Kwave::MetaData::STDPROP_END] = QVariant(offset - 1);
1057  add(copy);
1058  }
1059 }
1060 
1061 //***************************************************************************
1063 {
1064  qDebug("--- meta data ---");
1065 
1066  Iterator it(*this);
1067  while (it.hasNext()) {
1068  it.next();
1069  const Kwave::MetaData &meta = it.value();
1070  qDebug("* meta data #%s", DBG(it.key()));
1071  meta.dump();
1072  }
1073  qDebug("-----------------");
1074 }
1075 
1076 
1077 //***************************************************************************
1078 //***************************************************************************
virtual void cropByTracks(const QList< unsigned int > &tracks)
virtual MetaDataList copy(sample_index_t offset, sample_index_t length, const QList< unsigned int > &tracks) const
static QStringList positionBoundPropertyNames()
Definition: MetaData.cpp:155
bool hasProperty(const QString &p) const
Definition: MetaData.cpp:104
virtual MetaDataList selectByRange(sample_index_t first, sample_index_t last) const
virtual bool contains(const MetaData &metadata) const
static const QString STDPROP_POS
Definition: MetaData.h:53
Definition: App.h:33
static bool isLessThan(const Kwave::MetaData &m1, const Kwave::MetaData &m2)
virtual MetaDataList selectByTracks(const QList< unsigned int > &tracks) const
virtual void cropByRange(sample_index_t first, sample_index_t last)
QStringList keys() const
Definition: MetaData.cpp:149
virtual void shiftRight(sample_index_t offset, sample_index_t shift, const QList< unsigned int > &tracks)
virtual void remove(const MetaData &metadata)
virtual void scalePositions(double scale, const QList< unsigned int > &tracks)
static const QString STDPROP_TRACKS
Definition: MetaData.h:44
Scope scope() const
Definition: MetaData.cpp:81
virtual void dump() const
quint64 sample_index_t
Definition: Sample.h:28
virtual void add(const MetaData &metadata)
virtual void insertTrack(unsigned int track)
void merge(const MetaDataList &meta_data)
QMapIterator< QString, MetaData > Iterator
Definition: MetaDataList.h:41
virtual MetaDataList selectByType(const QString &type) const
virtual void clear()
Definition: MetaData.cpp:63
QString id() const
Definition: MetaData.cpp:75
virtual void dump() const
Definition: MetaData.cpp:241
virtual MetaDataList selectByProperty(const QString &property) const
static const QString STDPROP_TYPE
Definition: MetaData.h:41
virtual bool isNull() const
Definition: MetaData.cpp:69
QMutableMapIterator< QString, MetaData > MutableIterator
Definition: MetaDataList.h:44
static const QString STDPROP_START
Definition: MetaData.h:47
virtual void replace(const MetaDataList &list)
void setProperty(const QString &p, const QVariant &value)
Definition: MetaData.cpp:93
void split(sample_index_t offset, const QList< unsigned int > &tracks)
virtual QList< Kwave::MetaData > toSortedList() const
virtual void deleteRange(sample_index_t offset, sample_index_t length, const QList< unsigned int > &tracks)
virtual MetaDataList selectByPosition(sample_index_t pos) const
#define DBG(qs)
Definition: String.h:55
QList< unsigned int > boundTracks() const
Definition: MetaData.cpp:225
sample_index_t lastSample() const
Definition: MetaData.cpp:190
unsigned int toUint(T x)
Definition: Utils.h:109
virtual void shiftLeft(sample_index_t offset, sample_index_t shift, const QList< unsigned int > &tracks)
virtual MetaDataList selectByValue(const QString &property, QVariant value) const
static const QString STDPROP_END
Definition: MetaData.h:50
sample_index_t firstSample() const
Definition: MetaData.cpp:165
#define SAMPLE_INDEX_MAX
Definition: Sample.h:31
virtual void deleteTrack(unsigned int track)
virtual MetaDataList selectByScope(MetaData::Scope scope) const