Audacity  3.0.3
Track.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Track.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//*******************************************************************/
23 
24 
25 
26 #include "Track.h"
27 
28 
29 
30 #include <algorithm>
31 #include <numeric>
32 
33 #include <float.h>
34 #include <wx/file.h>
35 #include <wx/textfile.h>
36 #include <wx/log.h>
37 
39 #include "Project.h"
40 #include "ProjectSettings.h"
41 
42 #include "InconsistencyException.h"
43 
44 #ifdef _MSC_VER
45 //Disable truncation warnings
46 #pragma warning( disable : 4786 )
47 #endif
48 
50 : vrulerSize(36,0)
51 {
52  mSelected = false;
53  mLinked = false;
54 
55  mIndex = 0;
56 
57  mOffset = 0.0;
58 
60 }
61 
62 Track::Track(const Track &orig)
63 : vrulerSize( orig.vrulerSize )
64 {
65  mIndex = 0;
66  Init(orig);
67  mOffset = orig.mOffset;
68 }
69 
70 // Copy all the track properties except the actual contents
71 void Track::Init(const Track &orig)
72 {
73  mId = orig.mId;
74 
76  mName = orig.mName;
77 
78  mSelected = orig.mSelected;
79  mLinked = orig.mLinked;
80  mChannel = orig.mChannel;
81 }
82 
83 void Track::SetName( const wxString &n )
84 {
85  if ( mName != n ) {
86  mName = n;
87  Notify();
88  }
89 }
90 
91 void Track::SetSelected(bool s)
92 {
93  if (mSelected != s) {
94  mSelected = s;
95  auto pList = mList.lock();
96  if (pList)
97  pList->SelectionEvent( SharedPointer() );
98  }
99 }
100 
101 void Track::EnsureVisible( bool modifyState )
102 {
103  auto pList = mList.lock();
104  if (pList)
105  pList->EnsureVisibleEvent( SharedPointer(), modifyState );
106 }
107 
108 void Track::Merge(const Track &orig)
109 {
110  mSelected = orig.mSelected;
111 }
112 
114 {
115  // invoke "virtual constructor" to copy track object proper:
116  auto result = Clone();
117 
118  if (mpView)
119  // Copy view state that might be important to undo/redo
120  mpView->CopyTo( *result );
121 
122  return result;
123 }
124 
125 Track::~Track()
126 {
127 }
128 
129 
131 {
132  wxASSERT(mList.lock() == NULL || this == mNode.first->get());
133  return mNode;
134 }
135 
137 (const std::weak_ptr<TrackList> &list, TrackNodePointer node)
138 {
139  // BUG: When using this function to clear an owner, we may need to clear
140  // focused track too. Otherwise focus could remain on an invisible (or deleted) track.
141  mList = list;
142  mNode = node;
143 }
144 
145 const std::shared_ptr<CommonTrackCell> &Track::GetTrackView()
146 {
147  return mpView;
148 }
149 
150 void Track::SetTrackView( const std::shared_ptr<CommonTrackCell> &pView )
151 {
152  mpView = pView;
153 }
154 
155 const std::shared_ptr<CommonTrackCell> &Track::GetTrackControls()
156 {
157  return mpControls;
158 }
159 
160 void Track::SetTrackControls( const std::shared_ptr<CommonTrackCell> &pControls )
161 {
162  mpControls = pControls;
163 }
164 
165 int Track::GetIndex() const
166 {
167  return mIndex;
168 }
169 
170 void Track::SetIndex(int index)
171 {
172  mIndex = index;
173 }
174 
175 void Track::SetLinked(bool l)
176 {
177  auto pList = mList.lock();
178  if (pList && !pList->mPendingUpdates.empty()) {
179  auto orig = pList->FindById( GetId() );
180  if (orig && orig != this) {
181  orig->SetLinked(l);
182  return;
183  }
184  }
185 
186  DoSetLinked(l);
187 
188  if (pList) {
189  pList->RecalcPositions(mNode);
190  pList->ResizingEvent(mNode);
191  }
192 }
193 
194 void Track::DoSetLinked(bool l)
195 {
196  mLinked = l;
197 }
198 
200 {
201  auto pList = mList.lock();
202  if (!pList)
203  return nullptr;
204 
205  if (!pList->isNull(mNode)) {
206  if (mLinked) {
207  auto next = pList->getNext( mNode );
208  if ( !pList->isNull( next ) )
209  return next.first->get();
210  }
211 
212  if (mNode.first != mNode.second->begin()) {
213  auto prev = pList->getPrev( mNode );
214  if ( !pList->isNull( prev ) ) {
215  auto track = prev.first->get();
216  if (track && track->GetLinked())
217  return track;
218  }
219  }
220  }
221 
222  return nullptr;
223 }
224 
225 namespace {
226  inline bool IsSyncLockableNonLabelTrack( const Track *pTrack )
227  {
228  return nullptr != track_cast< const AudioTrack * >( pTrack );
229  }
230 
231  bool IsGoodNextSyncLockTrack(const Track *t, bool inLabelSection)
232  {
233  if (!t)
234  return false;
235  const bool isLabel = ( nullptr != track_cast<const LabelTrack*>(t) );
236  if (inLabelSection)
237  return isLabel;
238  else if (isLabel)
239  return true;
240  else
241  return IsSyncLockableNonLabelTrack( t );
242  }
243 }
244 
246 {
247 #ifdef EXPERIMENTAL_SYNC_LOCK
248  auto pList = mList.lock();
249  if (!pList)
250  return false;
251 
252  auto p = pList->GetOwner();
253  if (!p || !ProjectSettings::Get( *p ).IsSyncLocked())
254  return false;
255 
256  auto shTrack = this->SubstituteOriginalTrack();
257  if (!shTrack)
258  return false;
259 
260  const auto pTrack = shTrack.get();
261  auto trackRange = TrackList::SyncLockGroup( pTrack );
262 
263  if (trackRange.size() <= 1) {
264  // Not in a sync-locked group.
265  // Return true iff selected and of a sync-lockable type.
266  return (IsSyncLockableNonLabelTrack( pTrack ) ||
267  track_cast<const LabelTrack*>( pTrack )) && GetSelected();
268  }
269 
270  // Return true iff any track in the group is selected.
271  return *(trackRange + &Track::IsSelected).begin();
272 #endif
273 
274  return false;
275 }
276 
277 void Track::Notify( int code )
278 {
279  auto pList = mList.lock();
280  if (pList)
281  pList->DataEvent( SharedPointer(), code );
282 }
283 
284 void Track::SyncLockAdjust(double oldT1, double newT1)
285 {
286  if (newT1 > oldT1) {
287  // Insert space within the track
288 
289  if (oldT1 > GetEndTime())
290  return;
291 
292  auto tmp = Cut(oldT1, GetEndTime());
293 
294  Paste(newT1, tmp.get());
295  }
296  else if (newT1 < oldT1) {
297  // Remove from the track
298  Clear(newT1, oldT1);
299  }
300 }
301 
303 {
304  mMute = orig.mMute;
305  mSolo = orig.mSolo;
306  AudioTrack::Init( orig );
307 }
308 
309 void PlayableTrack::Merge( const Track &orig )
310 {
311  auto pOrig = dynamic_cast<const PlayableTrack *>(&orig);
312  wxASSERT( pOrig );
313  mMute = pOrig->mMute;
314  mSolo = pOrig->mSolo;
315  AudioTrack::Merge( *pOrig );
316 }
317 
319 {
320  if ( mMute != m ) {
321  mMute = m;
322  Notify();
323  }
324 }
325 
327 {
328  if ( mSolo != s ) {
329  mSolo = s;
330  Notify();
331  }
332 }
333 
334 // Serialize, not with tags of its own, but as attributes within a tag.
336 {
337  xmlFile.WriteAttr(wxT("mute"), mMute);
338  xmlFile.WriteAttr(wxT("solo"), mSolo);
340 }
341 
342 // Return true iff the attribute is recognized.
343 bool PlayableTrack::HandleXMLAttribute(const wxChar *attr, const wxChar *value)
344 {
345  const wxString strValue{ value };
346  long nValue;
347  if (!wxStrcmp(attr, wxT("mute")) &&
348  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
349  mMute = (nValue != 0);
350  return true;
351  }
352  else if (!wxStrcmp(attr, wxT("solo")) &&
353  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
354  mSolo = (nValue != 0);
355  return true;
356  }
357 
358  return AudioTrack::HandleXMLAttribute(attr, value);
359 }
360 
361 bool Track::Any() const
362  { return true; }
363 
364 bool Track::IsSelected() const
365  { return GetSelected(); }
366 
368  { return GetSelected() || IsSyncLockSelected(); }
369 
370 bool Track::IsLeader() const
371  { return !GetLink() || GetLinked(); }
372 
374  { return IsSelected() && IsLeader(); }
375 
377 (const Track *n, Track *dest)
378 {
379  if (dest) {
380  dest->SetChannel(n->GetChannel());
381  dest->SetLinked(n->GetLinked());
382  dest->SetName(n->GetName());
383  }
384 }
385 
387 {
388  // Sanity checks for linked tracks; unsetting the linked property
389  // doesn't fix the problem, but it likely leaves us with orphaned
390  // sample blocks instead of much worse problems.
391  bool err = false;
392  if (GetLinked())
393  {
394  Track *l = GetLink();
395  if (l)
396  {
397  // A linked track's partner should never itself be linked
398  if (l->GetLinked())
399  {
400  wxLogWarning(
401  wxT("Left track %s had linked right track %s with extra right track link.\n Removing extra link from right track."),
402  GetName(), l->GetName());
403  err = true;
404  l->SetLinked(false);
405  }
406 
407  // Channels should be left and right
408  if ( !( (GetChannel() == Track::LeftChannel &&
409  l->GetChannel() == Track::RightChannel) ||
411  l->GetChannel() == Track::LeftChannel) ) )
412  {
413  wxLogWarning(
414  wxT("Track %s and %s had left/right track links out of order. Setting tracks to not be linked."),
415  GetName(), l->GetName());
416  err = true;
417  SetLinked(false);
418  }
419  }
420  else
421  {
422  wxLogWarning(
423  wxT("Track %s had link to NULL track. Setting it to not be linked."),
424  GetName());
425  err = true;
426  SetLinked(false);
427  }
428  }
429 
430  return ! err;
431 }
432 
433 std::pair<Track *, Track *> TrackList::FindSyncLockGroup(Track *pMember) const
434 {
435  if (!pMember)
436  return { nullptr, nullptr };
437 
438  // A non-trivial sync-locked group is a maximal sub-sequence of the tracks
439  // consisting of any positive number of audio tracks followed by zero or
440  // more label tracks.
441 
442  // Step back through any label tracks.
443  auto member = pMember;
444  while (member && ( nullptr != track_cast<const LabelTrack*>(member) )) {
445  member = GetPrev(member);
446  }
447 
448  // Step back through the wave and note tracks before the label tracks.
449  Track *first = nullptr;
450  while (member && IsSyncLockableNonLabelTrack(member)) {
451  first = member;
452  member = GetPrev(member);
453  }
454 
455  if (!first)
456  // Can't meet the criteria described above. In that case,
457  // consider the track to be the sole member of a group.
458  return { pMember, pMember };
459 
460  Track *last = first;
461  bool inLabels = false;
462 
463  while (const auto next = GetNext(last)) {
464  if ( ! IsGoodNextSyncLockTrack(next, inLabels) )
465  break;
466  last = next;
467  inLabels = (nullptr != track_cast<const LabelTrack*>(last) );
468  }
469 
470  return { first, last };
471 }
472 
473 
474 // TrackList
475 //
476 // The TrackList sends events whenever certain updates occur to the list it
477 // is managing. Any other classes that may be interested in get these updates
478 // should use TrackList::Connect() or TrackList::Bind().
479 //
480 wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent);
481 wxDEFINE_EVENT(EVT_TRACKLIST_SELECTION_CHANGE, TrackListEvent);
482 wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, TrackListEvent);
483 wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, TrackListEvent);
484 wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, TrackListEvent);
485 wxDEFINE_EVENT(EVT_TRACKLIST_ADDITION, TrackListEvent);
486 wxDEFINE_EVENT(EVT_TRACKLIST_DELETION, TrackListEvent);
487 
488 // same value as in the default constructed TrackId:
489 long TrackList::sCounter = -1;
490 
492  [](AudacityProject &project) { return TrackList::Create( &project ); }
493 };
494 
496 {
497  return project.AttachedObjects::Get< TrackList >( key );
498 }
499 
500 const TrackList &TrackList::Get( const AudacityProject &project )
501 {
502  return Get( const_cast< AudacityProject & >( project ) );
503 }
504 
506 : wxEvtHandler()
507 , mOwner{ pOwner }
508 {
509 }
510 
511 // Factory function
512 std::shared_ptr<TrackList> TrackList::Create( AudacityProject *pOwner )
513 {
514  return std::make_shared<TrackList>( pOwner );
515 }
516 
517 #if 0
519 {
520  if (this != &that) {
521  this->Clear();
522  Swap(that);
523  }
524  return *this;
525 }
526 #endif
527 
529 {
530  auto SwapLOTs = [](
531  ListOfTracks &a, const std::weak_ptr< TrackList > &aSelf,
532  ListOfTracks &b, const std::weak_ptr< TrackList > &bSelf )
533  {
534  a.swap(b);
535  for (auto it = a.begin(), last = a.end(); it != last; ++it)
536  (*it)->SetOwner(aSelf, {it, &a});
537  for (auto it = b.begin(), last = b.end(); it != last; ++it)
538  (*it)->SetOwner(bSelf, {it, &b});
539  };
540 
541  const auto self = shared_from_this();
542  const auto otherSelf = that.shared_from_this();
543  SwapLOTs( *this, self, that, otherSelf );
544  SwapLOTs( this->mPendingUpdates, self, that.mPendingUpdates, otherSelf );
545  mUpdaters.swap(that.mUpdaters);
546 }
547 
549 {
550  Clear(false);
551 }
552 
554 {
555  if ( isNull( node ) )
556  return;
557 
558  Track *t;
559  int i = 0;
560 
561  auto prev = getPrev( node );
562  if ( !isNull( prev ) ) {
563  t = prev.first->get();
564  i = t->GetIndex() + 1;
565  }
566 
567  const auto theEnd = end();
568  for (auto n = Find( node.first->get() ); n != theEnd; ++n) {
569  t = *n;
570  t->SetIndex(i++);
571  }
572 
574 }
575 
576 void TrackList::SelectionEvent( const std::shared_ptr<Track> &pTrack )
577 {
578  // wxWidgets will own the event object
579  QueueEvent(
580  safenew TrackListEvent{ EVT_TRACKLIST_SELECTION_CHANGE, pTrack } );
581 }
582 
583 void TrackList::DataEvent( const std::shared_ptr<Track> &pTrack, int code )
584 {
585  // wxWidgets will own the event object
586  QueueEvent(
587  safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } );
588 }
589 
591  const std::shared_ptr<Track> &pTrack, bool modifyState )
592 {
593  auto pEvent = std::make_unique<TrackListEvent>(
594  EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, pTrack, 0 );
595  pEvent->SetInt( modifyState ? 1 : 0 );
596  // wxWidgets will own the event object
597  QueueEvent( pEvent.release() );
598 }
599 
601 {
602  // wxWidgets will own the event object
603  QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_PERMUTED, *node.first } );
604 }
605 
607 {
608  // wxWidgets will own the event object
609  QueueEvent( safenew TrackListEvent{
610  EVT_TRACKLIST_DELETION,
611  node.second && node.first != node.second->end()
612  ? *node.first
613  : nullptr
614  } );
615 }
616 
618 {
619  // wxWidgets will own the event object
620  QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_ADDITION, *node.first } );
621 }
622 
624 {
625  // wxWidgets will own the event object
626  QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_RESIZING, *node.first } );
627 }
628 
630  -> TrackIterRange< Track >
631 {
632  auto it = const_cast<TrackList*>(this)->getEnd();
633  return {
634  { it, it, it, &Track::Any },
635  { it, it, it, &Track::Any }
636  };
637 }
638 
641 {
642  auto pList = pTrack->GetOwner();
643  auto tracks =
644  pList->FindSyncLockGroup( const_cast<Track*>( pTrack ) );
645  return pList->Any().StartingWith(tracks.first).EndingAfter(tracks.second);
646 }
647 
650 {
651  auto iter = Find(pTrack);
652  while( *iter && ! ( *iter )->IsLeader() )
653  --iter;
654  return iter.Filter( &Track::IsLeader );
655 }
656 
657 void TrackList::Permute(const std::vector<TrackNodePointer> &permutation)
658 {
659  for (const auto iter : permutation) {
660  ListOfTracks::value_type track = *iter.first;
661  erase(iter.first);
662  Track *pTrack = track.get();
663  pTrack->SetOwner(shared_from_this(),
664  { insert(ListOfTracks::end(), track), this });
665  }
666  auto n = getBegin();
667  RecalcPositions(n);
668  PermutationEvent(n);
669 }
670 
672 {
673  // Linear search. Tracks in a project are usually very few.
674  // Search only the non-pending tracks.
675  auto it = std::find_if( ListOfTracks::begin(), ListOfTracks::end(),
676  [=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
677  if (it == ListOfTracks::end())
678  return {};
679  return it->get();
680 }
681 
682 Track *TrackList::DoAddToHead(const std::shared_ptr<Track> &t)
683 {
684  Track *pTrack = t.get();
685  push_front(ListOfTracks::value_type(t));
686  auto n = getBegin();
687  pTrack->SetOwner(shared_from_this(), n);
688  pTrack->SetId( TrackId{ ++sCounter } );
689  RecalcPositions(n);
690  AdditionEvent(n);
691  return front().get();
692 }
693 
694 Track *TrackList::DoAdd(const std::shared_ptr<Track> &t)
695 {
696  push_back(t);
697 
698  auto n = getPrev( getEnd() );
699 
700  t->SetOwner(shared_from_this(), n);
701  t->SetId( TrackId{ ++sCounter } );
702  RecalcPositions(n);
703  AdditionEvent(n);
704  return back().get();
705 }
706 
708  Track &track, size_t groupSize, bool resetChannels )
709 {
710  // If group size is exactly two, group as stereo, else mono (bug 2195).
711  auto list = track.mList.lock();
712  if ( groupSize > 0 && list.get() == this ) {
713  auto iter = track.mNode.first;
714  auto after = iter;
715  auto end = this->ListOfTracks::end();
716  auto count = groupSize;
717  for ( ; after != end && count; ++after, --count )
718  ;
719  if ( count == 0 ) {
720  auto unlink = [&] ( Track &tr ) {
721  if ( tr.GetLinked() ) {
722  if ( resetChannels ) {
723  auto link = tr.GetLink();
724  if ( link )
725  link->SetChannel( Track::MonoChannel );
726  }
727  tr.SetLinked( false );
728  }
729  if ( resetChannels )
730  tr.SetChannel( Track::MonoChannel );
731  };
732 
733  // Disassociate previous tracks -- at most one
734  auto pLeader = this->FindLeader( &track );
735  if ( *pLeader && *pLeader != &track )
736  unlink( **pLeader );
737 
738  // First disassociate given and later tracks, then reassociate them
739  for ( auto iter2 = iter; iter2 != after; ++iter2 )
740  unlink( **iter2 );
741 
742  if ( groupSize > 1 ) {
743  const auto channel = *iter++;
744  channel->SetLinked( groupSize == 2 );
745  channel->SetChannel( groupSize == 2? Track::LeftChannel : Track::MonoChannel );
746  (*iter++)->SetChannel( groupSize == 2? Track::RightChannel : Track::MonoChannel );
747  while (iter != after)
748  (*iter++)->SetChannel( Track::MonoChannel );
749  }
750  return;
751  }
752  }
753  // *this does not contain the track or sufficient following channels
754  // or group size is zero
756 }
757 
758 auto TrackList::Replace(Track * t, const ListOfTracks::value_type &with) ->
759  ListOfTracks::value_type
760 {
761  ListOfTracks::value_type holder;
762  if (t && with) {
763  auto node = t->GetNode();
764  t->SetOwner({}, {});
765 
766  holder = *node.first;
767 
768  Track *pTrack = with.get();
769  *node.first = with;
770  pTrack->SetOwner(shared_from_this(), node);
771  pTrack->SetId( t->GetId() );
772  RecalcPositions(node);
773 
774  DeletionEvent(node);
775  AdditionEvent(node);
776  }
777  return holder;
778 }
779 
781 {
782  auto result = getEnd();
783  if (t) {
784  auto node = t->GetNode();
785  t->SetOwner({}, {});
786 
787  if ( !isNull( node ) ) {
788  ListOfTracks::value_type holder = *node.first;
789 
790  result = getNext( node );
791  erase(node.first);
792  if ( !isNull( result ) )
793  RecalcPositions(result);
794 
795  DeletionEvent(result);
796  }
797  }
798  return result;
799 }
800 
801 void TrackList::Clear(bool sendEvent)
802 {
803  // Null out the back-pointers to this in tracks, in case there
804  // are outstanding shared_ptrs to those tracks, making them outlive
805  // the temporary ListOfTracks below.
806  for ( auto pTrack: *this )
807  pTrack->SetOwner( {}, {} );
808  for ( auto pTrack: mPendingUpdates )
809  pTrack->SetOwner( {}, {} );
810 
811  ListOfTracks tempList;
812  tempList.swap( *this );
813 
814  ListOfTracks updating;
815  updating.swap( mPendingUpdates );
816 
817  mUpdaters.clear();
818 
819  if (sendEvent)
820  DeletionEvent();
821 }
822 
824 Track *TrackList::GetNext(Track * t, bool linked) const
825 {
826  if (t) {
827  auto node = t->GetNode();
828  if ( !isNull( node ) ) {
829  if ( linked && t->GetLinked() )
830  node = getNext( node );
831 
832  if ( !isNull( node ) )
833  node = getNext( node );
834 
835  if ( !isNull( node ) )
836  return node.first->get();
837  }
838  }
839 
840  return nullptr;
841 }
842 
843 Track *TrackList::GetPrev(Track * t, bool linked) const
844 {
845  if (t) {
846  TrackNodePointer prev;
847  auto node = t->GetNode();
848  if ( !isNull( node ) ) {
849  // linked is true and input track second in team?
850  if (linked) {
851  prev = getPrev( node );
852  if( !isNull( prev ) &&
853  !t->GetLinked() && t->GetLink() )
854  // Make it the first
855  node = prev;
856  }
857 
858  prev = getPrev( node );
859  if ( !isNull( prev ) ) {
860  // Back up once
861  node = prev;
862 
863  // Back up twice sometimes when linked is true
864  if (linked) {
865  prev = getPrev( node );
866  if( !isNull( prev ) &&
867  !(*node.first)->GetLinked() && (*node.first)->GetLink() )
868  node = prev;
869  }
870 
871  return node.first->get();
872  }
873  }
874  }
875 
876  return nullptr;
877 }
878 
880 {
881  return GetPrev(t, true) != NULL;
882 }
883 
885 {
886  return GetNext(t, true) != NULL;
887 }
888 
889 // This is used when you want to swap the channel group starting
890 // at s1 with that starting at s2.
891 // The complication is that the tracks are stored in a single
892 // linked list.
894 {
895  // if a null pointer is passed in, we want to know about it
896  wxASSERT(!isNull(s1));
897  wxASSERT(!isNull(s2));
898 
899  // Deal with first track in each team
900  s1 = ( * FindLeader( s1.first->get() ) )->GetNode();
901  s2 = ( * FindLeader( s2.first->get() ) )->GetNode();
902 
903  // Safety check...
904  if (s1 == s2)
905  return;
906 
907  // Be sure s1 is the earlier iterator
908  if ((*s1.first)->GetIndex() >= (*s2.first)->GetIndex())
909  std::swap(s1, s2);
910 
911  // For saving the removed tracks
912  using Saved = std::vector< ListOfTracks::value_type >;
913  Saved saved1, saved2;
914 
915  auto doSave = [&] ( Saved &saved, TrackNodePointer &s ) {
916  size_t nn = Channels( s.first->get() ).size();
917  saved.resize( nn );
918  // Save them in backwards order
919  while( nn-- )
920  saved[nn] = *s.first, s.first = erase(s.first);
921  };
922 
923  doSave( saved1, s1 );
924  // The two ranges are assumed to be disjoint but might abut
925  const bool same = (s1 == s2);
926  doSave( saved2, s2 );
927  if (same)
928  // Careful, we invalidated s1 in the second doSave!
929  s1 = s2;
930 
931  // Reinsert them
932  auto doInsert = [&] ( Saved &saved, TrackNodePointer &s ) {
933  Track *pTrack;
934  for (auto & pointer : saved)
935  pTrack = pointer.get(),
936  // Insert before s, and reassign s to point at the new node before
937  // old s; which is why we saved pointers in backwards order
938  pTrack->SetOwner(shared_from_this(),
939  s = { insert(s.first, pointer), this } );
940  };
941  // This does not invalidate s2 even when it equals s1:
942  doInsert( saved2, s1 );
943  // Even if s2 was same as s1, this correctly inserts the saved1 range
944  // after the saved2 range, when done after:
945  doInsert( saved1, s2 );
946 
947  // Now correct the Index in the tracks, and other things
948  RecalcPositions(s1);
949  PermutationEvent(s1);
950 }
951 
953 {
954  if (t) {
955  Track *p = GetPrev(t, true);
956  if (p) {
957  SwapNodes(p->GetNode(), t->GetNode());
958  return true;
959  }
960  }
961 
962  return false;
963 }
964 
966 {
967  if (t) {
968  Track *n = GetNext(t, true);
969  if (n) {
970  SwapNodes(t->GetNode(), n->GetNode());
971  return true;
972  }
973  }
974 
975  return false;
976 }
977 
978 bool TrackList::Contains(const Track * t) const
979 {
980  return make_iterator_range( *this ).contains( t );
981 }
982 
983 bool TrackList::empty() const
984 {
985  return begin() == end();
986 }
987 
988 size_t TrackList::size() const
989 {
990  int cnt = 0;
991 
992  if (!empty())
993  cnt = getPrev( getEnd() ).first->get()->GetIndex() + 1;
994 
995  return cnt;
996 }
997 
998 namespace {
999  // Abstract the common pattern of the following three member functions
1000  inline double Accumulate
1001  (const TrackList &list,
1002  double (Track::*memfn)() const,
1003  double ident,
1004  const double &(*combine)(const double&, const double&))
1005  {
1006  // Default the answer to zero for empty list
1007  if (list.empty()) {
1008  return 0.0;
1009  }
1010 
1011  // Otherwise accumulate minimum or maximum of track values
1012  return list.Any().accumulate(ident, combine, memfn);
1013  }
1014 }
1015 
1017 {
1018  return Accumulate(*this, &Track::GetOffset, DBL_MAX, std::min);
1019 }
1020 
1022 {
1023  return Accumulate(*this, &Track::GetStartTime, DBL_MAX, std::min);
1024 }
1025 
1027 {
1028  return Accumulate(*this, &Track::GetEndTime, -DBL_MAX, std::max);
1029 }
1030 
1031 std::shared_ptr<Track>
1033 {
1034  std::shared_ptr<Track> pTrack;
1035  if (src) {
1036  pTrack = src->Clone(); // not duplicate
1037  // Share the satellites with the original, though they do not point back
1038  // to the pending track
1039  pTrack->mpView = src->mpView;
1040  pTrack->mpControls = src->mpControls;
1041  }
1042 
1043  if (pTrack) {
1044  mUpdaters.push_back( updater );
1045  mPendingUpdates.push_back( pTrack );
1046  auto n = mPendingUpdates.end();
1047  --n;
1048  pTrack->SetOwner(shared_from_this(), {n, &mPendingUpdates});
1049  }
1050 
1051  return pTrack;
1052 }
1053 
1054 void TrackList::RegisterPendingNewTrack( const std::shared_ptr<Track> &pTrack )
1055 {
1056  Add<Track>( pTrack );
1057  pTrack->SetId( TrackId{} );
1058 }
1059 
1061 {
1062  auto pUpdater = mUpdaters.begin();
1063  for (const auto &pendingTrack : mPendingUpdates) {
1064  // Copy just a part of the track state, according to the update
1065  // function
1066  const auto &updater = *pUpdater;
1067  auto src = FindById( pendingTrack->GetId() );
1068  if (pendingTrack && src) {
1069  if (updater)
1070  updater( *pendingTrack, *src );
1071  pendingTrack->DoSetLinked(src->GetLinked());
1072  }
1073  ++pUpdater;
1074  }
1075 }
1076 
1079 {
1080  for (const auto &pTrack: mPendingUpdates)
1081  pTrack->SetOwner( {}, {} );
1082  mPendingUpdates.clear();
1083  mUpdaters.clear();
1084 
1085  if (pAdded)
1086  pAdded->clear();
1087 
1088  // To find the first node that remains after the first deleted one
1089  TrackNodePointer node;
1090  bool foundNode = false;
1091 
1092  for (auto it = ListOfTracks::begin(), stop = ListOfTracks::end();
1093  it != stop;) {
1094  if (it->get()->GetId() == TrackId{}) {
1095  do {
1096  if (pAdded)
1097  pAdded->push_back( *it );
1098  (*it)->SetOwner( {}, {} );
1099  it = erase( it );
1100  }
1101  while (it != stop && it->get()->GetId() == TrackId{});
1102 
1103  if (!foundNode && it != stop) {
1104  node = (*it)->GetNode();
1105  foundNode = true;
1106  }
1107  }
1108  else
1109  ++it;
1110  }
1111 
1112  if (!empty()) {
1114  DeletionEvent( node );
1115  }
1116 }
1117 
1120 {
1121  bool result = false;
1122 
1123  ListOfTracks additions;
1124  ListOfTracks updates;
1125  {
1126  // Always clear, even if one of the update functions throws
1127  auto cleanup = finally( [&] { ClearPendingTracks( &additions ); } );
1129  updates.swap( mPendingUpdates );
1130  }
1131 
1132  // Remaining steps must be No-fail-guarantee so that this function
1133  // gives Strong-guarantee
1134 
1135  std::vector< std::shared_ptr<Track> > reinstated;
1136 
1137  for (auto &pendingTrack : updates) {
1138  if (pendingTrack) {
1139  if (pendingTrack->mpView)
1140  pendingTrack->mpView->Reparent( pendingTrack );
1141  if (pendingTrack->mpControls)
1142  pendingTrack->mpControls->Reparent( pendingTrack );
1143  auto src = FindById( pendingTrack->GetId() );
1144  if (src)
1145  this->Replace(src, pendingTrack), result = true;
1146  else
1147  // Perhaps a track marked for pending changes got deleted by
1148  // some other action. Recreate it so we don't lose the
1149  // accumulated changes.
1150  reinstated.push_back(pendingTrack);
1151  }
1152  }
1153 
1154  // If there are tracks to reinstate, append them to the list.
1155  for (auto &pendingTrack : reinstated)
1156  if (pendingTrack)
1157  this->Add( pendingTrack ), result = true;
1158 
1159  // Put the pending added tracks back into the list, preserving their
1160  // positions.
1161  bool inserted = false;
1162  ListOfTracks::iterator first;
1163  for (auto &pendingTrack : additions) {
1164  if (pendingTrack) {
1165  auto iter = ListOfTracks::begin();
1166  std::advance( iter, pendingTrack->GetIndex() );
1167  iter = ListOfTracks::insert( iter, pendingTrack );
1168  pendingTrack->SetOwner( shared_from_this(), {iter, this} );
1169  pendingTrack->SetId( TrackId{ ++sCounter } );
1170  if (!inserted) {
1171  first = iter;
1172  inserted = true;
1173  }
1174  }
1175  }
1176  if (inserted) {
1177  TrackNodePointer node{first, this};
1178  RecalcPositions(node);
1179  AdditionEvent(node);
1180  result = true;
1181  }
1182 
1183  return result;
1184 }
1185 
1187 {
1188  // Linear search. Tracks in a project are usually very few.
1189  auto pList = mList.lock();
1190  if (pList) {
1191  const auto id = GetId();
1192  const auto end = pList->mPendingUpdates.end();
1193  auto it = std::find_if(
1194  pList->mPendingUpdates.begin(), end,
1195  [=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
1196  if (it != end)
1197  return *it;
1198  }
1199  return SharedPointer();
1200 }
1201 
1202 std::shared_ptr<const Track> Track::SubstitutePendingChangedTrack() const
1203 {
1204  return const_cast<Track*>(this)->SubstitutePendingChangedTrack();
1205 }
1206 
1207 std::shared_ptr<const Track> Track::SubstituteOriginalTrack() const
1208 {
1209  auto pList = mList.lock();
1210  if (pList) {
1211  const auto id = GetId();
1212  const auto pred = [=]( const ListOfTracks::value_type &ptr ) {
1213  return ptr->GetId() == id; };
1214  const auto end = pList->mPendingUpdates.end();
1215  const auto it = std::find_if( pList->mPendingUpdates.begin(), end, pred );
1216  if (it != end) {
1217  const auto &list2 = (const ListOfTracks &) *pList;
1218  const auto end2 = list2.end();
1219  const auto it2 = std::find_if( list2.begin(), end2, pred );
1220  if ( it2 != end2 )
1221  return *it2;
1222  }
1223  }
1224  return SharedPointer();
1225 }
1226 
1228 {
1229  return true;
1230 }
1231 
1233 {
1234  return {};
1235 }
1236 
1238 {
1239  return {};
1240 }
1241 
1242 // Serialize, not with tags of its own, but as attributes within a tag.
1244  XMLWriter &xmlFile, bool includeNameAndSelected) const
1245 {
1246  if (includeNameAndSelected) {
1247  xmlFile.WriteAttr(wxT("name"), GetName());
1248  xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected());
1249  }
1250  if ( mpView )
1251  mpView->WriteXMLAttributes( xmlFile );
1252  if ( mpControls )
1253  mpControls->WriteXMLAttributes( xmlFile );
1254 }
1255 
1256 // Return true iff the attribute is recognized.
1257 bool Track::HandleCommonXMLAttribute(const wxChar *attr, const wxChar *value)
1258 {
1259  long nValue = -1;
1260  wxString strValue( value );
1261  if ( mpView && mpView->HandleXMLAttribute( attr, value ) )
1262  ;
1263  else if ( mpControls && mpControls->HandleXMLAttribute( attr, value ) )
1264  ;
1265  else if (!wxStrcmp(attr, wxT("name")) &&
1266  XMLValueChecker::IsGoodString(strValue)) {
1267  SetName( strValue );
1268  return true;
1269  }
1270  else if (!wxStrcmp(attr, wxT("isSelected")) &&
1271  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
1272  this->SetSelected(nValue != 0);
1273  return true;
1274  }
1275  return false;
1276 }
1277 
1279 {
1280  auto pList = mList.lock();
1281  if (pList) {
1282  pList->RecalcPositions(mNode);
1283  pList->ResizingEvent(mNode);
1284  }
1285 }
1286 
1288 
1290 {
1291  if ( !mPendingUpdates.empty() )
1292  return true;
1293  if (end() != std::find_if(begin(), end(), [](const Track *t){
1294  return t->GetId() == TrackId{};
1295  }))
1296  return true;
1297  return false;
1298 }
XMLWriter
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:23
TrackList::isNull
bool isNull(TrackNodePointer p) const
Definition: Track.h:1597
TrackIntervalData::~TrackIntervalData
virtual ~TrackIntervalData()
Track::SubstituteOriginalTrack
std::shared_ptr< const Track > SubstituteOriginalTrack() const
Definition: Track.cpp:1207
Track::mChannel
ChannelType mChannel
Definition: Track.h:390
key
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: Track.cpp:491
Track::mOffset
double mOffset
Definition: Track.h:391
Track::WriteCommonXMLAttributes
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
Definition: Track.cpp:1243
anonymous_namespace{Track.cpp}::IsGoodNextSyncLockTrack
bool IsGoodNextSyncLockTrack(const Track *t, bool inLabelSection)
Definition: Track.cpp:231
Track::SetId
void SetId(TrackId id)
Definition: Track.h:271
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:625
Track::RightChannel
static const auto RightChannel
Definition: Track.h:266
Track::mSelected
bool mSelected
Definition: Track.h:254
TrackList::FindById
Track * FindById(TrackId id)
Definition: Track.cpp:671
TrackList::PermutationEvent
void PermutationEvent(TrackNodePointer node)
Definition: Track.cpp:600
TrackList::ResizingEvent
void ResizingEvent(TrackNodePointer node)
Definition: Track.cpp:623
XMLValueChecker::IsGoodInt
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
Definition: XMLTagHandler.cpp:158
TrackList::SelectionEvent
void SelectionEvent(const std::shared_ptr< Track > &pTrack)
Definition: Track.cpp:576
TrackList::getEnd
TrackNodePointer getEnd() const
Definition: Track.h:1600
Track::SetOwner
void SetOwner(const std::weak_ptr< TrackList > &list, TrackNodePointer node)
Update mNode when Track is added to TrackList, or removed from it.
Definition: Track.cpp:137
TrackList::GetNext
Track * GetNext(Track *t, bool linked=false) const
Return a track in the list that comes after Track t.
Definition: Track.cpp:824
Track::GetEndTime
virtual double GetEndTime() const =0
TrackList::CanMoveUp
bool CanMoveUp(Track *t) const
Definition: Track.cpp:879
Track::GetName
wxString GetName() const
Definition: Track.h:409
Project.h
TrackList::GetMinOffset
double GetMinOffset() const
Definition: Track.cpp:1016
Track::SupportsBasicEditing
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
Definition: Track.cpp:1227
Track::EnsureVisible
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:101
Track::ConstIntervals
std::vector< ConstInterval > ConstIntervals
Definition: Track.h:319
InconsistencyException.h
MessageBoxException for violation of preconditions or assertions.
TrackIter
Iterator over only members of a TrackList of the specified subtype, optionally filtered by a predicat...
Definition: Track.h:916
Track::SetTrackView
void SetTrackView(const std::shared_ptr< CommonTrackCell > &pView)
Definition: Track.cpp:150
Track::GetIntervals
virtual ConstIntervals GetIntervals() const
Report times on the track where important intervals begin and end, for UI to snap to.
Definition: Track.cpp:1232
PlayableTrack::Merge
void Merge(const Track &init) override
Definition: Track.cpp:309
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1467
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1263
Track::GetLinked
bool GetLinked() const
Definition: Track.h:371
Track::Merge
virtual void Merge(const Track &orig)
Definition: Track.cpp:108
Track::SharedPointer
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:279
Track::Cut
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1))=0
Track::LinkConsistencyCheck
bool LinkConsistencyCheck()
Definition: Track.cpp:386
anonymous_namespace{Track.cpp}::IsSyncLockableNonLabelTrack
bool IsSyncLockableNonLabelTrack(const Track *pTrack)
Definition: Track.cpp:226
Track::Duplicate
virtual Holder Duplicate() const
Definition: Track.cpp:113
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:39
TrackList::Add
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
Definition: Track.h:1486
TrackList::Find
auto Find(Track *pTrack) -> TrackIter< TrackType >
Turn a pointer into a TrackIter (constant time); get end iterator if this does not own the track.
Definition: Track.h:1316
Track::mNode
TrackNodePointer mNode
Holds iterator to self, so that TrackList::Find can be constant-time.
Definition: Track.h:248
PlayableTrack::Init
void Init(const PlayableTrack &init)
Definition: Track.cpp:302
TrackList::RecalcPositions
void RecalcPositions(TrackNodePointer node)
Definition: Track.cpp:553
Track::Paste
virtual void Paste(double WXUNUSED(t), const Track *WXUNUSED(src))=0
AudioTrack::HandleXMLAttribute
bool HandleXMLAttribute(const wxChar *, const wxChar *)
Definition: Track.h:831
Track::Any
bool Any() const
Definition: Track.cpp:361
ProjectSettings.h
Track::HandleCommonXMLAttribute
bool HandleCommonXMLAttribute(const wxChar *attr, const wxChar *value)
Definition: Track.cpp:1257
Track::IsSyncLockSelected
bool IsSyncLockSelected() const
Definition: Track.cpp:245
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
Track::mDefaultName
wxString mDefaultName
Definition: Track.h:251
Track::mpControls
std::shared_ptr< CommonTrackCell > mpControls
Definition: Track.h:816
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:39
TrackList::Swap
void Swap(TrackList &that)
Definition: Track.cpp:528
anonymous_namespace{Track.cpp}::Accumulate
double Accumulate(const TrackList &list, double(Track::*memfn)() const, double ident, const double &(*combine)(const double &, const double &))
Definition: Track.cpp:1001
Track::mLinked
bool mLinked
Definition: Track.h:257
TrackList::end
iterator end()
Definition: Track.h:1308
TrackList::RegisterPendingChangedTrack
std::shared_ptr< Track > RegisterPendingChangedTrack(Updater updater, Track *src)
Definition: Track.cpp:1032
TrackList::GetEndTime
double GetEndTime() const
Definition: Track.cpp:1026
Track::mName
wxString mName
Definition: Track.h:250
TrackList::Contains
bool Contains(const Track *t) const
Mainly a test function. Uses a linear search, so could be slow.
Definition: Track.cpp:978
Track::GetStartTime
virtual double GetStartTime() const =0
Track::SetSelected
virtual void SetSelected(bool s)
Definition: Track.cpp:91
ProjectSettings::IsSyncLocked
bool IsSyncLocked() const
Definition: ProjectSettings.cpp:190
TrackList::mUpdaters
std::vector< Updater > mUpdaters
This is in correspondence with mPendingUpdates.
Definition: Track.h:1698
TrackList::CanMoveDown
bool CanMoveDown(Track *t) const
Definition: Track.cpp:884
Track::Track
Track()
Definition: Track.cpp:49
TrackList::mPendingUpdates
ListOfTracks mPendingUpdates
Shadow tracks holding append-recording in progress; need to put them into a list so that GetLink() wo...
Definition: Track.h:1696
TrackList::FindLeader
TrackIter< Track > FindLeader(Track *pTrack)
Definition: Track.cpp:648
Track::mList
std::weak_ptr< TrackList > mList
Definition: Track.h:245
Track::SubstitutePendingChangedTrack
std::shared_ptr< Track > SubstitutePendingChangedTrack()
Definition: Track.cpp:1186
TrackList::Updater
std::function< void(Track &dest, const Track &src) > Updater
Definition: Track.h:1647
TrackList::Permute
void Permute(const std::vector< TrackNodePointer > &permutation)
For use in sorting: assume each iterator points into this list, no duplications.
Definition: Track.cpp:657
AudioTrack::WriteXMLAttributes
void WriteXMLAttributes(XMLWriter &WXUNUSED(xmlFile)) const
Definition: Track.h:828
CommonTrackPanelCell.h
TrackList::FindSyncLockGroup
std::pair< Track *, Track * > FindSyncLockGroup(Track *pMember) const
Definition: Track.cpp:433
Track::mId
TrackId mId
Identifies the track only in-session, not persistently.
Definition: Track.h:242
TrackList::operator=
TrackList & operator=(const TrackList &)=delete
Track::GetId
TrackId GetId() const
Definition: Track.h:269
TrackListEvent
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
Definition: Track.h:1205
TrackList::AdditionEvent
void AdditionEvent(TrackNodePointer node)
Definition: Track.cpp:617
Track::Holder
std::shared_ptr< Track > Holder
Definition: Track.h:324
TrackList::begin
iterator begin()
Definition: Track.h:1307
TrackList::DataEvent
void DataEvent(const std::shared_ptr< Track > &pTrack, int code)
Definition: Track.cpp:583
TrackList::ClearPendingTracks
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
Definition: Track.cpp:1078
ListOfTracks
std::list< std::shared_ptr< Track > > ListOfTracks
Definition: Track.h:52
Track::GetTrackView
const std::shared_ptr< CommonTrackCell > & GetTrackView()
Definition: Track.cpp:145
Track::MonoChannel
static const auto MonoChannel
Definition: Track.h:267
Track::AdjustPositions
void AdjustPositions()
Definition: Track.cpp:1278
Track::GetOffset
virtual double GetOffset() const =0
Track::mpView
std::shared_ptr< CommonTrackCell > mpView
Definition: Track.h:815
TrackNodePointer
std::pair< ListOfTracks::iterator, ListOfTracks * > TrackNodePointer
Pairs a std::list iterator and a pointer to a list, for comparison purposes.
Definition: Track.h:58
Track::GetLink
Track * GetLink() const
Definition: Track.cpp:199
TrackList::~TrackList
virtual ~TrackList()
Definition: Track.cpp:548
Track::Clone
virtual Holder Clone() const =0
TrackList::DoAddToHead
Track * DoAddToHead(const std::shared_ptr< Track > &t)
Definition: Track.cpp:682
PlayableTrack::mSolo
bool mSolo
Definition: Track.h:861
Track::IsSelected
bool IsSelected() const
Definition: Track.cpp:364
Track::SetLinked
void SetLinked(bool l)
Definition: Track.cpp:175
THROW_INCONSISTENCY_EXCEPTION
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Definition: InconsistencyException.h:77
Track::LeftChannel
static const auto LeftChannel
Definition: Track.h:265
anonymous_namespace{NoteTrack.cpp}::swap
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:733
Track::IsSelectedLeader
bool IsSelectedLeader() const
Definition: Track.cpp:373
Track::SetChannel
void SetChannel(ChannelType c)
Definition: Track.h:376
TrackList::RegisterPendingNewTrack
void RegisterPendingNewTrack(const std::shared_ptr< Track > &pTrack)
Definition: Track.cpp:1054
TrackIterRange
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Definition: Track.h:1084
PlayableTrack
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:837
TrackList::GetStartTime
double GetStartTime() const
Definition: Track.cpp:1021
ActiveProjects::Find
wxString Find(const FilePath &path)
TrackList::MoveUp
bool MoveUp(Track *t)
Definition: Track.cpp:952
TrackList::DeletionEvent
void DeletionEvent(TrackNodePointer node={})
Definition: Track.cpp:606
TrackList::getBegin
TrackNodePointer getBegin() const
Definition: Track.h:1603
TrackList::TrackList
TrackList(const TrackList &that)=delete
Track::GetSelected
bool GetSelected() const
Definition: Track.h:414
Track::Intervals
std::vector< Interval > Intervals
Definition: Track.h:317
Track::mIndex
int mIndex
0-based position of this track in its TrackList
Definition: Track.h:249
TrackIterRange::StartingWith
TrackIterRange StartingWith(const Track *pTrack) const
Definition: Track.h:1146
TrackList::UpdatePendingTracks
void UpdatePendingTracks()
Definition: Track.cpp:1060
TrackList::Clear
void Clear(bool sendEvent=true)
Make the list empty.
Definition: Track.cpp:801
TrackList::size
size_t size() const
Definition: Track.cpp:988
id
int id
Definition: WaveTrackControls.cpp:589
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
TrackList::HasPendingTracks
bool HasPendingTracks() const
Definition: Track.cpp:1289
TrackId
An in-session identifier of track objects across undo states. It does not persist between sessions.
Definition: Track.h:164
Track::GetIndex
int GetIndex() const
Definition: Track.cpp:165
wxDEFINE_EVENT
wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent)
TrackList::GroupChannels
void GroupChannels(Track &track, size_t groupSize, bool resetChannels=true)
Define a group of channels starting at the given track.
Definition: Track.cpp:707
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
TrackList::ApplyPendingTracks
bool ApplyPendingTracks()
Definition: Track.cpp:1119
TrackList::GetPrev
Track * GetPrev(Track *t, bool linked=false) const
Definition: Track.cpp:843
Track::SetName
void SetName(const wxString &n)
Definition: Track.cpp:83
TrackList::sCounter
static long sCounter
Definition: Track.h:1644
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:238
Track::IsLeader
bool IsLeader() const
Definition: Track.cpp:370
Track::Notify
void Notify(int code=-1)
Definition: Track.cpp:277
Track::DoSetLinked
void DoSetLinked(bool l)
Definition: Track.cpp:194
TrackList::SwapNodes
void SwapNodes(TrackNodePointer s1, TrackNodePointer s2)
Definition: Track.cpp:893
Track::Init
void Init(const Track &orig)
Definition: Track.cpp:71
TrackList::DoAdd
Track * DoAdd(const std::shared_ptr< Track > &t)
Definition: Track.cpp:694
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:112
TrackList::Replace
ListOfTracks::value_type Replace(Track *t, const ListOfTracks::value_type &with)
Definition: Track.cpp:758
TrackList::getNext
TrackNodePointer getNext(TrackNodePointer p) const
Move an iterator to the next node, if any; else stay at end.
Definition: Track.h:1608
Track::SetTrackControls
void SetTrackControls(const std::shared_ptr< CommonTrackCell > &pControls)
Definition: Track.cpp:160
Track::GetChannel
virtual ChannelType GetChannel() const
Definition: Track.h:424
XMLWriter::WriteAttr
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:34
TrackList::getPrev
TrackNodePointer getPrev(TrackNodePointer p) const
Move an iterator to the previous node, if any; else wrap to end.
Definition: Track.h:1618
TrackList::Create
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:512
Track::FinishCopy
static void FinishCopy(const Track *n, Track *dest)
Definition: Track.cpp:377
Track::Clear
virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1))=0
Track.h
declares abstract base class Track, TrackList, and iterators over TrackList
TrackList::MoveDown
bool MoveDown(Track *t)
Definition: Track.cpp:965
Track::IsSelectedOrSyncLockSelected
bool IsSelectedOrSyncLockSelected() const
Definition: Track.cpp:367
Track::SetIndex
void SetIndex(int index)
Definition: Track.cpp:170
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1354
TrackList::Remove
TrackNodePointer Remove(Track *t)
Remove the Track and return an iterator to what followed it.
Definition: Track.cpp:780
PlayableTrack::HandleXMLAttribute
bool HandleXMLAttribute(const wxChar *attr, const wxChar *value)
Definition: Track.cpp:343
PlayableTrack::SetSolo
void SetSolo(bool s)
Definition: Track.cpp:326
PlayableTrack::mMute
bool mMute
Definition: Track.h:860
PlayableTrack::SetMute
void SetMute(bool m)
Definition: Track.cpp:318
PlayableTrack::WriteXMLAttributes
void WriteXMLAttributes(XMLWriter &xmlFile) const
Definition: Track.cpp:335
safenew
#define safenew
Definition: MemoryX.h:8
TrackList::SyncLockGroup
static TrackIterRange< Track > SyncLockGroup(Track *pTrack)
Definition: Track.cpp:639
TrackIterRange::EndingAfter
TrackIterRange EndingAfter(const Track *pTrack) const
Definition: Track.h:1160
TrackList::EnsureVisibleEvent
void EnsureVisibleEvent(const std::shared_ptr< Track > &pTrack, bool modifyState)
Definition: Track.cpp:590
TrackList::empty
bool empty() const
Definition: Track.cpp:983
Track::SyncLockAdjust
virtual void SyncLockAdjust(double oldT1, double newT1)
Definition: Track.cpp:284
TrackList::EmptyRange
TrackIterRange< Track > EmptyRange() const
Definition: Track.cpp:629
Track::GetTrackControls
const std::shared_ptr< CommonTrackCell > & GetTrackControls()
Definition: Track.cpp:155
Track::GetNode
TrackNodePointer GetNode() const
Retrieve mNode with debug checks.
Definition: Track.cpp:130