Audacity  2.2.2
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 #include <algorithm>
25 #include <numeric>
26 #include "Track.h"
27 
28 #include <float.h>
29 #include <wx/file.h>
30 #include <wx/textfile.h>
31 #include <wx/log.h>
32 
33 #include "TimeTrack.h"
34 #include "WaveTrack.h"
35 #include "NoteTrack.h"
36 #include "LabelTrack.h"
37 #include "Project.h"
38 #include "DirManager.h"
39 
40 #include "Experimental.h"
41 
42 #include "TrackPanel.h" // for TrackInfo
43 
44 #ifdef _MSC_VER
45 //Disable truncation warnings
46 #pragma warning( disable : 4786 )
47 #endif
48 
49 #ifdef __WXDEBUG__
50  // if we are in a debug build of audacity
52 // #define DEBUG_TLI
53 #endif
54 
55 Track::Track(const std::shared_ptr<DirManager> &projDirManager)
56 : vrulerSize(36,0),
57  mDirManager(projDirManager)
58 {
59  mSelected = false;
60  mLinked = false;
61 
62  mY = 0;
64  mIndex = 0;
65 
66  mMinimized = false;
67 
68  mOffset = 0.0;
69 
71 }
72 
73 Track::Track(const Track &orig)
74 : vrulerSize( orig.vrulerSize )
75 {
76  mY = 0;
77  mIndex = 0;
78  Init(orig);
79  mOffset = orig.mOffset;
80 }
81 
82 // Copy all the track properties except the actual contents
83 void Track::Init(const Track &orig)
84 {
85  mId = orig.mId;
86 
88  mName = orig.mName;
89 
90  mDirManager = orig.mDirManager;
91 
92  mSelected = orig.mSelected;
93  mLinked = orig.mLinked;
94  mHeight = orig.mHeight;
95  mMinimized = orig.mMinimized;
96  mChannel = orig.mChannel;
97 }
98 
99 void Track::SetSelected(bool s)
100 {
101  mSelected = s;
102 }
103 
104 void Track::Merge(const Track &orig)
105 {
106  mSelected = orig.mSelected;
107 }
108 
110 {
111 }
112 
113 
115 {
116  wxASSERT(mList.lock() == NULL || this == mNode->get());
117  return mNode;
118 }
119 
120 void Track::SetOwner
121 (const std::weak_ptr<TrackList> &list, TrackNodePointer node)
122 {
123  mList = list;
124  mNode = node;
125 }
126 
128 {
129  auto height = TrackInfo::MinimumTrackHeight();
130 
131  if (GetLink()) {
132  auto halfHeight = height / 2;
133  if (GetLinked())
134  return halfHeight;
135  else
136  return height - halfHeight;
137  }
138 
139  return height;
140 }
141 
142 int Track::GetIndex() const
143 {
144  return mIndex;
145 }
146 
147 void Track::SetIndex(int index)
148 {
149  mIndex = index;
150 }
151 
152 int Track::GetY() const
153 {
154  return mY;
155 }
156 
157 void Track::SetY(int y)
158 {
159  auto pList = mList.lock();
160  if (pList && !pList->mPendingUpdates.empty()) {
161  auto orig = pList->FindById( GetId() );
162  if (orig && orig != this) {
163  // delegate, and rely on the update to copy back
164  orig->SetY(y);
165  pList->UpdatePendingTracks();
166  return;
167  }
168  }
169 
170  DoSetY(y);
171 }
172 
173 void Track::DoSetY(int y)
174 {
175  mY = y;
176 }
177 
178 int Track::GetHeight() const
179 {
180  if (mMinimized) {
181  return GetMinimizedHeight();
182  }
183 
184  return mHeight;
185 }
186 
187 void Track::SetHeight(int h)
188 {
189  auto pList = mList.lock();
190  if (pList && !pList->mPendingUpdates.empty()) {
191  auto orig = pList->FindById( GetId() );
192  if (orig && orig != this) {
193  // delegate, and rely on RecalcPositions to copy back
194  orig->SetHeight(h);
195  return;
196  }
197  }
198 
199  DoSetHeight(h);
200 
201  if (pList) {
202  pList->RecalcPositions(mNode);
203  pList->ResizingEvent(mNode);
204  }
205 }
206 
208 {
209  mHeight = h;
210 }
211 
213 {
214  return mMinimized;
215 }
216 
217 void Track::SetMinimized(bool isMinimized)
218 {
219  auto pList = mList.lock();
220  if (pList && !pList->mPendingUpdates.empty()) {
221  auto orig = pList->FindById( GetId() );
222  if (orig && orig != this) {
223  // delegate, and rely on RecalcPositions to copy back
224  orig->SetMinimized(isMinimized);
225  return;
226  }
227  }
228 
229  DoSetMinimized(isMinimized);
230 
231  if (pList) {
232  pList->RecalcPositions(mNode);
233  pList->ResizingEvent(mNode);
234  }
235 }
236 
237 void Track::DoSetMinimized(bool isMinimized)
238 {
239  mMinimized = isMinimized;
240 }
241 
242 void Track::SetLinked(bool l)
243 {
244  auto pList = mList.lock();
245  if (pList && !pList->mPendingUpdates.empty()) {
246  auto orig = pList->FindById( GetId() );
247  if (orig && orig != this) {
248  // delegate, and rely on RecalcPositions to copy back
249  orig->SetLinked(l);
250  return;
251  }
252  }
253 
254  DoSetLinked(l);
255 
256  if (pList) {
257  pList->RecalcPositions(mNode);
258  pList->ResizingEvent(mNode);
259  }
260 }
261 
262 void Track::DoSetLinked(bool l)
263 {
264  mLinked = l;
265 }
266 
268 {
269  auto pList = mList.lock();
270  if (!pList)
271  return nullptr;
272 
273  if (!pList->isNull(mNode)) {
274  if (mLinked) {
275  auto next = pList->getNext( mNode );
276  if ( !pList->isNull( next ) )
277  return next->get();
278  }
279 
280  auto prev = pList->getPrev( mNode );
281  if ( !pList->isNull( prev ) ) {
282  auto track = prev->get();
283  if (track && track->GetLinked())
284  return track;
285  }
286  }
287 
288  return nullptr;
289 }
290 
292 {
293 #ifdef EXPERIMENTAL_SYNC_LOCK
295  if (!p || !p->IsSyncLocked())
296  return false;
297 
298  auto pList = mList.lock();
299  SyncLockedTracksIterator git(pList.get());
300  Track *t = git.StartWith(const_cast<Track*>(this));
301 
302  if (!t) {
303  // Not in a sync-locked group.
304  return ((this->GetKind() == Track::Wave) || (this->GetKind() == Track::Label)) && GetSelected();
305  }
306 
307  for (; t; t = git.Next()) {
308  if (t->GetSelected())
309  return true;
310  }
311 #endif
312 
313  return false;
314 }
315 
316 void Track::SyncLockAdjust(double oldT1, double newT1)
317 {
318  if (newT1 > oldT1) {
319  // Insert space within the track
320 
321  if (oldT1 > GetEndTime())
322  return;
323 
324  auto tmp = Cut(oldT1, GetEndTime());
325 
326  Paste(newT1, tmp.get());
327  }
328  else if (newT1 < oldT1) {
329  // Remove from the track
330  Clear(newT1, oldT1);
331  }
332 }
333 
334 std::shared_ptr<Track> Track::FindTrack()
335 {
336  return Pointer( this );
337 }
338 
340 {
341  mMute = orig.mMute;
342  mSolo = orig.mSolo;
343  AudioTrack::Init( orig );
344 }
345 
346 void PlayableTrack::Merge( const Track &orig )
347 {
348  auto pOrig = dynamic_cast<const PlayableTrack *>(&orig);
349  wxASSERT( pOrig );
350  mMute = pOrig->mMute;
351  mSolo = pOrig->mSolo;
352  AudioTrack::Merge( *pOrig );
353 }
354 
355 // Serialize, not with tags of its own, but as attributes within a tag.
357 {
358  xmlFile.WriteAttr(wxT("mute"), mMute);
359  xmlFile.WriteAttr(wxT("solo"), mSolo);
361 }
362 
363 // Return true iff the attribute is recognized.
364 bool PlayableTrack::HandleXMLAttribute(const wxChar *attr, const wxChar *value)
365 {
366  const wxString strValue{ value };
367  long nValue;
368  if (!wxStrcmp(attr, wxT("mute")) &&
369  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
370  mMute = (nValue != 0);
371  return true;
372  }
373  else if (!wxStrcmp(attr, wxT("solo")) &&
374  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
375  mSolo = (nValue != 0);
376  return true;
377  }
378 
379  return AudioTrack::HandleXMLAttribute(attr, value);
380 }
381 
382 // TrackListIterator
384  : l{ val }
385  , cur{ p }
386 {
387 }
388 
390  : l{ val }
391  , cur{}
392 {
393  if (l)
394  cur = l->getBegin();
395 }
396 
398 {
399  if (val == NULL) {
400  return First();
401  }
402 
403  if (l == NULL) {
404  return NULL;
405  }
406 
407  if (val->mList.lock() == NULL)
408  return nullptr;
409 
410  cur = val->GetNode();
411  return cur->get();
412 }
413 
415 {
416  if (val != NULL) {
417  l = val;
418  }
419 
420  if (l == NULL) {
421  return NULL;
422  }
423 
424  cur = l->getBegin();
425 
426  if (!l->isNull(cur)) {
427  return cur->get();
428  }
429 
430  return nullptr;
431 }
432 
434 {
435  if (l == NULL) {
436  return NULL;
437  }
438 
439  cur = l->getPrev( l->getEnd() );
440  if ( l->isNull( cur ) )
441  return nullptr;
442 
443  // With skiplinked set, we won't return the second channel of a linked pair
444  if (skiplinked) {
445  auto prev = l->getPrev( cur );
446  if ( !l->isNull( prev ) &&
447  !(*cur)->GetLinked() &&
448  (*cur)->GetLink()
449  )
450  cur = prev;
451  }
452 
453  return cur->get();
454 }
455 
457 {
458 #ifdef DEBUG_TLI // if we are debugging this bit
459  wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid at start of Next(). List changed since iterator created?")); // check that cur is in the list
460 #endif
461 
462  if (!l || l->isNull(cur))
463  return nullptr;
464 
465  if (skipLinked &&
466  (*cur)->GetLinked())
467  cur = l->getNext( cur );
468 
469  #ifdef DEBUG_TLI // if we are debugging this bit
470  wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after skipping linked tracks.")); // check that cur is in the list
471  #endif
472 
473  if (!l->isNull(cur))
474  cur = l->getNext( cur );
475 
476  #ifdef DEBUG_TLI // if we are debugging this bit
477  wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after moving to next track.")); // check that cur is in the list if it is not null
478  #endif
479 
480  if (!l->isNull(cur))
481  return cur->get();
482 
483  return nullptr;
484 }
485 
487 {
488  if (!l || l->isNull(cur))
489  return nullptr;
490 
491  cur = l->getPrev( cur );
492  if ( l->isNull( cur ) )
493  return nullptr;
494 
495  if ( skiplinked ) {
496  auto prev = l->getPrev( cur );
497  if( !l->isNull( prev ) && (*prev)->GetLinked() )
498  cur = prev;
499  }
500 
501  return cur->get();
502 }
503 
505 {
506  if ( !l || l->isNull( cur ) )
507  return nullptr;
508  else
509  return cur->get();
510 }
511 
513 {
514  if ( !l || l->isNull( cur ) )
515  return nullptr;
516 
517  cur = l->Remove( cur->get() );
518 
519  #ifdef DEBUG_TLI // if we are debugging this bit
520  wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after deletion of track.")); // check that cur is in the list
521  #endif
522 
523  if ( !l->isNull( cur ) )
524  return cur->get();
525 
526  return nullptr;
527 }
528 
530 {
531  // Order these steps so as not to use operator == on default-constructed
532  // std::list::iterator -- that crashes in the MSVC 2013 standard library
533  bool isEnd = !l || l->isNull( cur );
534  bool otherIsEnd = !other.l || other.l->isNull( other.cur );
535 
536  return (isEnd == otherIsEnd && (isEnd || cur == other.cur));
537 }
538 
539 //
540 // TrackListCondIterator (base class for iterators that iterate over all tracks
541 // that meet a condition)
542 //
543 
545 {
547 
548  if (t && !this->Condition(t))
549  return nullptr;
550 
551  return t;
552 }
553 
555 {
557 
558  while (t && !this->Condition(t)) {
560  }
561 
562  return t;
563 }
564 
566 {
567  while (Track *t = TrackListIterator::Next(skiplinked)) {
568  if (this->Condition(t)) {
569  return t;
570  }
571  }
572 
573  return NULL;
574 }
575 
577 {
578  while (Track *t = TrackListIterator::Prev(skiplinked))
579  {
580  if (this->Condition(t)) {
581  return t;
582  }
583  }
584 
585  return NULL;
586 }
587 
589 {
590  Track *t = TrackListIterator::Last(skiplinked);
591 
592  while (t && !this->Condition(t)) {
593  t = TrackListIterator::Prev(skiplinked);
594  }
595 
596  return t;
597 }
598 
599 // TrackListOfKindIterator
602 {
603  this->kind = kind;
604 }
605 
607 {
608  return kind == Track::All || t->GetKind() == kind;
609 }
610 
611 //SelectedTrackListOfKindIterator
613 {
615 }
616 
617 // VisibleTrackIterator
618 //
619 // Based on TrackListIterator returns only the currently visible tracks.
620 //
622 : TrackListCondIterator(project->GetTracks())
623 {
624  mProject = project;
627 }
628 
630 {
631  wxRect r(0, t->GetY(), 1, t->GetHeight());
632  if( r.Intersects(mPanelRect) )
633  return true;
634  auto partner = t->GetLink();
635  if ( partner && t->GetLinked() )
636  return Condition( partner );
637  return false;
638 }
639 
640 // SyncLockedTracksIterator
641 //
642 // Based on TrackListIterator returns only tracks belonging to the group
643 // in which the starting track is a member.
644 //
646 : TrackListIterator(val),
647  mInLabelSection(false)
648 {
649 }
650 
651 namespace {
652  inline bool IsSyncLockableNonLabelTrack( const Track *pTrack )
653  {
654  return nullptr != dynamic_cast< const AudioTrack * >( pTrack );
655  }
656 }
657 
659 {
660  Track *t = NULL;
661 
662  // A sync-locked group consists of any positive number of wave (or note)
663  // tracks followed by any
664  // non-negative number of label tracks. Step back through any label tracks,
665  // and then through the wave tracks above them.
666 
667  while (member && member->GetKind() == Track::Label) {
668  member = l->GetPrev(member);
669  }
670 
671  while (member && IsSyncLockableNonLabelTrack(member)) {
672  t = member;
673  member = l->GetPrev(member);
674  }
675 
676  // Make it current (if t is still NULL there are no wave tracks, so we're
677  // not in a sync-locked group).
678  if (t)
679  cur = t->GetNode();
680 
681  mInLabelSection = false;
682 
683  return t;
684 }
685 
687 {
688  if (!t)
689  return false;
690 
691  const bool isLabel = ( t->GetKind() == Track::Label );
692  const bool isSyncLockable = IsSyncLockableNonLabelTrack( t );
693 
694  if ( !( isLabel || isSyncLockable ) ) {
695  return false;
696  }
697 
698  if (mInLabelSection && !isLabel) {
699  return false;
700  }
701 
702  return true;
703 }
704 
706 {
707  Track *t = TrackListIterator::Next(skiplinked);
708 
709  if (!t)
710  return nullptr;
711 
712  if ( ! IsGoodNextTrack(t) ) {
713  cur = l->getEnd();
714  return nullptr;
715  }
716 
717  mInLabelSection = ( t->GetKind() == Track::Label );
718 
719  return t;
720 }
721 
723 {
724  Track *t = TrackListIterator::Prev(skiplinked);
725 
726  //
727  // Ways to end a sync-locked group in reverse
728  //
729 
730  // Beginning of tracks
731  if (!t)
732  return nullptr;
733 
734  const bool isLabel = ( t->GetKind() == Track::Label );
735  const bool isSyncLockable = IsSyncLockableNonLabelTrack( t );
736 
737  if ( !( isLabel || isSyncLockable ) ) {
738  cur = l->getEnd();
739  return nullptr;
740  }
741 
742  if ( !mInLabelSection && isLabel ) {
743  cur = l->getEnd();
744  return nullptr;
745  }
746 
747  mInLabelSection = isLabel;
748 
749  return t;
750 }
751 
753 {
754  if ( !l || l->isNull( cur ) )
755  return nullptr;
756 
757  Track *t = cur->get();
758 
759  while (const auto next = l->GetNext(t, skiplinked)) {
760  if ( ! IsGoodNextTrack(next) )
761  break;
762  t = Next(skiplinked);
763  }
764 
765  return t;
766 }
767 
768 
769 // TrackList
770 //
771 // The TrackList sends events whenever certain updates occur to the list it
772 // is managing. Any other classes that may be interested in get these updates
773 // should use TrackList::Connect() or TrackList::Bind().
774 //
775 wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, wxCommandEvent);
776 wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, wxCommandEvent);
777 wxDEFINE_EVENT(EVT_TRACKLIST_DELETION, wxCommandEvent);
778 
779 // same value as in the default constructed TrackId:
780 long TrackList::sCounter = -1;
781 
783 : wxEvtHandler()
784 {
785 }
786 
787 // Factory function
788 std::shared_ptr<TrackList> TrackList::Create()
789 {
790  std::shared_ptr<TrackList> result{ safenew TrackList{} };
791  result->mSelf = result;
792  return result;
793 }
794 
796 {
797  if (this != &that) {
798  this->Clear();
799  Swap(that);
800  }
801  return *this;
802 }
803 
805 {
806  auto SwapLOTs = [](
807  ListOfTracks &a, const std::weak_ptr< TrackList > &aSelf,
808  ListOfTracks &b, const std::weak_ptr< TrackList > &bSelf )
809  {
810  a.swap(b);
811  for (auto it = a.begin(), last = a.end(); it != last; ++it)
812  (*it)->SetOwner(aSelf, it);
813  for (auto it = b.begin(), last = b.end(); it != last; ++it)
814  (*it)->SetOwner(bSelf, it);
815  };
816 
817  SwapLOTs( *this, mSelf, that, that.mSelf );
818  SwapLOTs( this->mPendingUpdates, mSelf, that.mPendingUpdates, that.mSelf );
819  mUpdaters.swap(that.mUpdaters);
820 }
821 
823 {
824  Clear(false);
825 }
826 
828 {
829  if ( isNull( node ) )
830  return;
831 
832  Track *t;
833  int i = 0;
834  int y = 0;
835 
836  auto prev = getPrev( node );
837  if ( !isNull( prev ) ) {
838  t = prev->get();
839  i = t->GetIndex() + 1;
840  y = t->GetY() + t->GetHeight();
841  }
842 
843  const auto theEnd = end();
844  for (auto n = TrackListIterator{ this, node }; n != theEnd; ++n) {
845  t = *n;
846  t->SetIndex(i++);
847  t->DoSetY(y);
848  y += t->GetHeight();
849  }
850 
852 }
853 
855 {
856  auto e = std::make_unique<wxCommandEvent>(EVT_TRACKLIST_PERMUTED);
857  // wxWidgets will own the event object
858  QueueEvent(e.release());
859 }
860 
862 {
863  auto e = std::make_unique<wxCommandEvent>(EVT_TRACKLIST_DELETION);
864  // wxWidgets will own the event object
865  QueueEvent(e.release());
866 }
867 
869 {
870  auto e = std::make_unique<TrackListEvent>(EVT_TRACKLIST_RESIZING);
871  e->mpTrack = *node;
872  // wxWidgets will own the event object
873  QueueEvent(e.release());
874 }
875 
876 void TrackList::Permute(const std::vector<TrackNodePointer> &permutation)
877 {
878  for (const auto iter : permutation) {
879  ListOfTracks::value_type track = std::move(*iter);
880  erase(iter);
881  Track *pTrack = track.get();
882  pTrack->SetOwner(mSelf, insert(ListOfTracks::end(), std::move(track)));
883  }
884  auto n = getBegin();
885  RecalcPositions(n);
887 }
888 
890 {
891  // Linear search. Tracks in a project are usually very few.
892  // Search only the non-pending tracks.
893  auto it = std::find_if( ListOfTracks::begin(), ListOfTracks::end(),
894  [=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
895  if (it == ListOfTracks::end())
896  return {};
897  return it->get();
898 }
899 
900 template<typename TrackKind>
901 Track *TrackList::Add(std::unique_ptr<TrackKind> &&t)
902 {
903  Track *pTrack;
904  push_back(ListOfTracks::value_type(pTrack = t.release()));
905 
906  auto n = getPrev( getEnd() );
907 
908  pTrack->SetOwner(mSelf, n);
909  pTrack->SetId( TrackId{ ++sCounter } );
910  RecalcPositions(n);
911  ResizingEvent(n);
912  return back().get();
913 }
914 
915 // Make instantiations for the linker to find
916 template Track *TrackList::Add<TimeTrack>(std::unique_ptr<TimeTrack> &&);
917 #if defined(USE_MIDI)
918 template Track *TrackList::Add<NoteTrack>(std::unique_ptr<NoteTrack> &&);
919 #endif
920 template Track *TrackList::Add<WaveTrack>(std::unique_ptr<WaveTrack> &&);
921 template Track *TrackList::Add<LabelTrack>(std::unique_ptr<LabelTrack> &&);
922 template Track *TrackList::Add<Track>(std::unique_ptr<Track> &&);
923 
924 template<typename TrackKind>
925 Track *TrackList::AddToHead(std::unique_ptr<TrackKind> &&t)
926 {
927  Track *pTrack;
928  push_front(ListOfTracks::value_type(pTrack = t.release()));
929  auto n = getBegin();
930  pTrack->SetOwner(mSelf, n);
931  pTrack->SetId( TrackId{ ++sCounter } );
932  RecalcPositions(n);
933  ResizingEvent(n);
934  return front().get();
935 }
936 
937 // Make instantiations for the linker to find
938 template Track *TrackList::AddToHead<TimeTrack>(std::unique_ptr<TimeTrack> &&);
939 
940 template<typename TrackKind>
941 Track *TrackList::Add(std::shared_ptr<TrackKind> &&t)
942 {
943  push_back(t);
944 
945  auto n = getPrev( getEnd() );
946 
947  t->SetOwner(mSelf, n);
948  t->SetId( TrackId{ ++sCounter } );
949  RecalcPositions(n);
950  ResizingEvent(n);
951  return back().get();
952 }
953 
954 // Make instantiations for the linker to find
955 template Track *TrackList::Add<Track>(std::shared_ptr<Track> &&);
956 template Track *TrackList::Add<WaveTrack>(std::shared_ptr<WaveTrack> &&);
957 
958 auto TrackList::Replace(Track * t, ListOfTracks::value_type &&with) ->
959  ListOfTracks::value_type
960 {
961  ListOfTracks::value_type holder;
962  if (t && with) {
963  auto node = t->GetNode();
964  t->SetOwner({}, {});
965 
966  holder = std::move(*node);
967 
968  Track *pTrack = with.get();
969  *node = std::move(with);
970  pTrack->SetOwner(mSelf, node);
971  pTrack->SetId( t->GetId() );
972  RecalcPositions(node);
973 
974  DeletionEvent();
975  ResizingEvent(node);
976  }
977  return holder;
978 }
979 
981 {
982  auto result = getEnd();
983  if (t) {
984  auto node = t->GetNode();
985  t->SetOwner({}, {});
986 
987  if ( !isNull( node ) ) {
988  ListOfTracks::value_type holder = std::move( *node );
989 
990  result = getNext( node );
991  erase(node);
992  if ( !isNull( result ) )
993  RecalcPositions(result);
994 
995  DeletionEvent();
996  }
997  }
998  return result;
999 }
1000 
1001 void TrackList::Clear(bool sendEvent)
1002 {
1003  // Null out the back-pointers in tracks, in case there are outstanding
1004  // shared_ptrs to those tracks.
1005  for ( auto pTrack: *this )
1006  pTrack->SetOwner( {}, {} );
1007  for ( auto pTrack: mPendingUpdates )
1008  pTrack->SetOwner( {}, {} );
1009 
1010  ListOfTracks tempList;
1011  tempList.swap( *this );
1012 
1013  ListOfTracks updating;
1014  updating.swap( mPendingUpdates );
1015 
1016  mUpdaters.clear();
1017 
1018  if (sendEvent)
1019  DeletionEvent();
1020 }
1021 
1022 void TrackList::Select(Track * t, bool selected /* = true */ )
1023 {
1024  if (t) {
1025  const auto node = t->GetNode();
1026  if ( !isNull( node ) ) {
1027  t->SetSelected( selected );
1028  if ( t->GetLinked() ) {
1029  auto next = getNext( node );
1030  if ( !isNull( next ) )
1031  (*next)->SetSelected( selected );
1032  }
1033  else {
1034  auto prev = getPrev( node );
1035  if ( !isNull( prev ) && (*prev)->GetLinked() )
1036  (*prev)->SetSelected( selected );
1037  }
1038  }
1039  }
1040 }
1041 
1043 Track *TrackList::GetNext(Track * t, bool linked) const
1044 {
1045  if (t) {
1046  auto node = t->GetNode();
1047  if ( !isNull( node ) ) {
1048  if ( linked && t->GetLinked() )
1049  node = getNext( node );
1050 
1051  if ( !isNull( node ) )
1052  node = getNext( node );
1053 
1054  if ( !isNull( node ) )
1055  return node->get();
1056  }
1057  }
1058 
1059  return nullptr;
1060 }
1061 
1062 Track *TrackList::GetPrev(Track * t, bool linked) const
1063 {
1064  if (t) {
1065  TrackNodePointer prev;
1066  auto node = t->GetNode();
1067  if ( !isNull( node ) ) {
1068  // linked is true and input track second in team?
1069  if (linked) {
1070  prev = getPrev( node );
1071  if( !isNull( prev ) &&
1072  !t->GetLinked() && t->GetLink() )
1073  // Make it the first
1074  node = prev;
1075  }
1076 
1077  prev = getPrev( node );
1078  if ( !isNull( prev ) ) {
1079  // Back up once
1080  node = prev;
1081 
1082  // Back up twice sometimes when linked is true
1083  if (linked) {
1084  prev = getPrev( node );
1085  if( !isNull( prev ) &&
1086  !(*node)->GetLinked() && (*node)->GetLink() )
1087  node = prev;
1088  }
1089 
1090  return node->get();
1091  }
1092  }
1093  }
1094 
1095  return nullptr;
1096 }
1097 
1101 {
1102  int height = t->GetHeight();
1103 
1104  t = t->GetLink();
1105  if (t) {
1106  height += t->GetHeight();
1107  }
1108  return height;
1109 }
1110 
1112 {
1113  return GetPrev(t, true) != NULL;
1114 }
1115 
1117 {
1118  return GetNext(t, true) != NULL;
1119 }
1120 
1121 // This is used when you want to swap the track or pair of
1122 // tracks in s1 with the track or pair of tracks in s2.
1123 // The complication is that the tracks are stored in a single
1124 // linked list, and pairs of tracks are marked only by a flag
1125 // in one of the tracks.
1127 {
1128  // if a null pointer is passed in, we want to know about it
1129  wxASSERT(!isNull(s1));
1130  wxASSERT(!isNull(s2));
1131 
1132  // Deal with first track in each team
1133  Track *link;
1134  link = (*s1)->GetLink();
1135  bool linked1 = link != nullptr;
1136  if (linked1 && !(*s1)->GetLinked()) {
1137  s1 = link->GetNode();
1138  }
1139 
1140  link = (*s2)->GetLink();
1141  bool linked2 = link != nullptr;
1142  if (linked2 && !(*s2)->GetLinked()) {
1143  s2 = link->GetNode();
1144  }
1145 
1146  // Safety check...
1147  if (s1 == s2)
1148  return;
1149 
1150  // Be sure s1 is the earlier iterator
1151  if ((*s1)->GetIndex() >= (*s2)->GetIndex()) {
1152  std::swap(s1, s2);
1153  std::swap(linked1, linked2);
1154  }
1155 
1156  // Remove tracks
1157  ListOfTracks::value_type save11 = std::move(*s1), save12{};
1158  s1 = erase(s1);
1159  if (linked1) {
1160  wxASSERT(s1 != s2);
1161  save12 = std::move(*s1), s1 = erase(s1);
1162  }
1163  const bool same = (s1 == s2);
1164 
1165  ListOfTracks::value_type save21 = std::move(*s2), save22{};
1166  s2 = erase(s2);
1167  if (linked2)
1168  save22 = std::move(*s2), s2 = erase(s2);
1169 
1170  if (same)
1171  // We invalidated s1!
1172  s1 = s2;
1173 
1174  // Reinsert them
1175  Track *pTrack;
1176  if (save22)
1177  pTrack = save22.get(), pTrack->SetOwner(mSelf, s1 = insert(s1, std::move(save22)));
1178  pTrack = save21.get(), pTrack->SetOwner(mSelf, s1 = insert(s1, std::move(save21)));
1179 
1180  if (save12)
1181  pTrack = save12.get(), pTrack->SetOwner(mSelf, s2 = insert(s2, std::move(save12)));
1182  pTrack = save11.get(), pTrack->SetOwner(mSelf, s2 = insert(s2, std::move(save11)));
1183 
1184  // Now correct the Index in the tracks, and other things
1185  RecalcPositions(s1);
1186  PermutationEvent();
1187 }
1188 
1190 {
1191  if (t) {
1192  Track *p = GetPrev(t, true);
1193  if (p) {
1194  SwapNodes(p->GetNode(), t->GetNode());
1195  return true;
1196  }
1197  }
1198 
1199  return false;
1200 }
1201 
1203 {
1204  if (t) {
1205  Track *n = GetNext(t, true);
1206  if (n) {
1207  SwapNodes(t->GetNode(), n->GetNode());
1208  return true;
1209  }
1210  }
1211 
1212  return false;
1213 }
1214 
1215 bool TrackList::Contains(const Track * t) const
1216 {
1217  return make_iterator_range( *this ).contains( t );
1218 }
1219 
1220 bool TrackList::empty() const
1221 {
1222  return begin() == end();
1223 }
1224 
1225 size_t TrackList::size() const
1226 {
1227  int cnt = 0;
1228 
1229  if (!empty())
1230  cnt = getPrev( getEnd() )->get()->GetIndex() + 1;
1231 
1232  return cnt;
1233 }
1234 
1236 {
1237  auto iter = std::find_if(begin(), end(),
1238  [] ( Track *t ) { return t->GetKind() == Track::Time; }
1239  );
1240  if (iter == end())
1241  return nullptr;
1242  else
1243  return static_cast<TimeTrack*>(*iter);
1244 }
1245 
1247 {
1248  return const_cast<TrackList*>(this)->GetTimeTrack();
1249 }
1250 
1251 unsigned TrackList::GetNumExportChannels(bool selectionOnly) const
1252 {
1253  /* counters for tracks panned different places */
1254  int numLeft = 0;
1255  int numRight = 0;
1256  //int numMono = 0;
1257  /* track iteration kit */
1258  const Track *tr;
1260 
1261  for (tr = iter.First(this); tr != NULL; tr = iter.Next()) {
1262 
1263  // Want only unmuted wave tracks.
1264  auto wt = static_cast<const WaveTrack *>(tr);
1265  if ((tr->GetKind() != Track::Wave) ||
1266  wt->GetMute())
1267  continue;
1268 
1269  // do we only want selected ones?
1270  if (selectionOnly && !(tr->GetSelected())) {
1271  //want selected but this one is not
1272  continue;
1273  }
1274 
1275  // Found a left channel
1276  if (tr->GetChannel() == Track::LeftChannel) {
1277  numLeft++;
1278  }
1279 
1280  // Found a right channel
1281  else if (tr->GetChannel() == Track::RightChannel) {
1282  numRight++;
1283  }
1284 
1285  // Found a mono channel, but it may be panned
1286  else if (tr->GetChannel() == Track::MonoChannel) {
1287  float pan = ((WaveTrack*)tr)->GetPan();
1288 
1289  // Figure out what kind of channel it should be
1290  if (pan == -1.0) { // panned hard left
1291  numLeft++;
1292  }
1293  else if (pan == 1.0) { // panned hard right
1294  numRight++;
1295  }
1296  else if (pan == 0) { // panned dead center
1297  // numMono++;
1298  }
1299  else { // panned somewhere else
1300  numLeft++;
1301  numRight++;
1302  }
1303  }
1304  }
1305 
1306  // if there is stereo content, report 2, else report 1
1307  if (numRight > 0 || numLeft > 0) {
1308  return 2;
1309  }
1310 
1311  return 1;
1312 }
1313 
1314 namespace {
1315  template<typename Array>
1316  Array GetWaveTracks(TrackListIterator p, const TrackListIterator end,
1317  bool selectionOnly, bool includeMuted)
1318  {
1319  Array waveTrackArray;
1320 
1321  for (; p != end; ++p) {
1322  const auto &track = *p;
1323  auto wt = static_cast<const WaveTrack *>(&*track);
1324  if (track->GetKind() == Track::Wave &&
1325  (includeMuted || !wt->GetMute()) &&
1326  (track->GetSelected() || !selectionOnly)) {
1327  waveTrackArray.push_back( Track::Pointer< WaveTrack >( track ) );
1328  }
1329  }
1330 
1331  return waveTrackArray;
1332  }
1333 }
1334 
1335 WaveTrackArray TrackList::GetWaveTrackArray(bool selectionOnly, bool includeMuted)
1336 {
1337  return GetWaveTracks<WaveTrackArray>(begin(), end(), selectionOnly, includeMuted);
1338 }
1339 
1340 WaveTrackConstArray TrackList::GetWaveTrackConstArray(bool selectionOnly, bool includeMuted) const
1341 {
1342  auto list = const_cast<TrackList*>(this);
1343  return GetWaveTracks<WaveTrackConstArray>(
1344  list->begin(), list->end(), selectionOnly, includeMuted);
1345 }
1346 
1347 #if defined(USE_MIDI)
1348 NoteTrackArray TrackList::GetNoteTrackArray(bool selectionOnly)
1349 {
1350  NoteTrackArray noteTrackArray;
1351 
1352  for(const auto &track : *this) {
1353  if (track->GetKind() == Track::Note &&
1354  (track->GetSelected() || !selectionOnly)) {
1355  noteTrackArray.push_back( Track::Pointer<NoteTrack>(track) );
1356  }
1357  }
1358 
1359  return noteTrackArray;
1360 }
1361 #endif
1362 
1364 {
1365  int height = 0;
1366 
1367  if (!empty()) {
1368  auto track = getPrev( getEnd() )->get();
1369  height = track->GetY() + track->GetHeight();
1370  }
1371 
1372  return height;
1373 }
1374 
1375 namespace {
1376  // Abstract the common pattern of the following three member functions
1377  double doubleMin(double a, double b) { return std::min(a, b); }
1378  double doubleMax(double a, double b) { return std::max(a, b); }
1379  inline double Accumulate
1380  (const TrackList &list,
1381  double (Track::*memfn)() const,
1382  double (*combine)(double, double))
1383  {
1384  // Default the answer to zero for empty list
1385  if (list.empty()) {
1386  return 0.0;
1387  }
1388 
1389  // Otherwise accumulate minimum or maximum of track values
1390  auto iter = list.begin();
1391  double acc = (**iter++.*memfn)();
1392  return std::accumulate(iter, list.end(), acc,
1393  [=](double acc, const Track *pTrack) {
1394  return combine(acc, (*pTrack.*memfn)());
1395  });
1396  }
1397 }
1398 
1400 {
1401  return Accumulate(*this, &Track::GetOffset, doubleMin);
1402 }
1403 
1405 {
1406  return Accumulate(*this, &Track::GetStartTime, doubleMin);
1407 }
1408 
1410 {
1411  return Accumulate(*this, &Track::GetEndTime, doubleMax);
1412 }
1413 
1414 std::shared_ptr<Track>
1416 {
1417  std::shared_ptr<Track> pTrack;
1418  if (src)
1419  // convert from unique_ptr to shared_ptr
1420  pTrack.reset( src->Duplicate().release() );
1421 
1422  if (pTrack) {
1423  mUpdaters.push_back( updater );
1424  mPendingUpdates.push_back( pTrack );
1425  auto n = mPendingUpdates.end();
1426  --n;
1427  pTrack->SetOwner(mSelf, n);
1428  }
1429 
1430  return pTrack;
1431 }
1432 
1433 void TrackList::RegisterPendingNewTrack( const std::shared_ptr<Track> &pTrack )
1434 {
1435  auto copy = pTrack;
1436  Add<Track>( std::move( copy ) );
1437  pTrack->SetId( TrackId{} );
1438 }
1439 
1441 {
1442  auto pUpdater = mUpdaters.begin();
1443  for (const auto &pendingTrack : mPendingUpdates) {
1444  // Copy just a part of the track state, according to the update
1445  // function
1446  const auto &updater = *pUpdater;
1447  auto src = FindById( pendingTrack->GetId() );
1448  if (pendingTrack && src) {
1449  if (updater)
1450  updater( *pendingTrack, *src );
1451  pendingTrack->DoSetY(src->GetY());
1452  pendingTrack->DoSetHeight(src->GetHeight());
1453  pendingTrack->DoSetMinimized(src->GetMinimized());
1454  pendingTrack->DoSetLinked(src->GetLinked());
1455  }
1456  ++pUpdater;
1457  }
1458 }
1459 
1461 // NOFAIL-GUARANTEE
1462 {
1463  for (const auto &pTrack: mPendingUpdates)
1464  pTrack->SetOwner( {}, {} );
1465  mPendingUpdates.clear();
1466  mUpdaters.clear();
1467 
1468  if (pAdded)
1469  pAdded->clear();
1470 
1471  for (auto it = ListOfTracks::begin(), stop = ListOfTracks::end();
1472  it != stop;) {
1473  if (it->get()->GetId() == TrackId{}) {
1474  if (pAdded)
1475  pAdded->push_back( *it );
1476  it = erase( it );
1477  }
1478  else
1479  ++it;
1480  }
1481 
1482  if (!empty())
1483  RecalcPositions(ListOfTracks::begin());
1484 }
1485 
1487 {
1488  bool result = false;
1489 
1490  ListOfTracks additions;
1491  ListOfTracks updates;
1492  {
1493  // Always clear, even if one of the update functions throws
1494  auto cleanup = finally( [&] { ClearPendingTracks( &additions ); } );
1496  updates.swap( mPendingUpdates );
1497  }
1498 
1499  // Remaining steps must be NOFAIL-GUARANTEE so that this function
1500  // gives STRONG-GUARANTEE
1501 
1502  std::vector< std::shared_ptr<Track> > reinstated;
1503 
1504  for (auto &pendingTrack : updates) {
1505  if (pendingTrack) {
1506  auto src = FindById( pendingTrack->GetId() );
1507  if (src)
1508  this->Replace(src, std::move(pendingTrack)), result = true;
1509  else
1510  // Perhaps a track marked for pending changes got deleted by
1511  // some other action. Recreate it so we don't lose the
1512  // accumulated changes.
1513  reinstated.push_back(pendingTrack);
1514  }
1515  }
1516 
1517  // If there are tracks to reinstate, append them to the list.
1518  for (auto &pendingTrack : reinstated)
1519  if (pendingTrack)
1520  this->Add(std::move(pendingTrack)), result = true;
1521 
1522  // Put the pending added tracks back into the list, preserving their
1523  // positions.
1524  bool inserted = false;
1525  ListOfTracks::iterator first;
1526  for (auto &pendingTrack : additions) {
1527  if (pendingTrack) {
1528  auto iter = ListOfTracks::begin();
1529  std::advance( iter, pendingTrack->GetIndex() );
1530  iter = ListOfTracks::insert( iter, pendingTrack );
1531  pendingTrack->SetOwner( mSelf, iter );
1532  pendingTrack->SetId( TrackId{ ++sCounter } );
1533  if (!inserted) {
1534  first = iter;
1535  inserted = true;
1536  }
1537  }
1538  }
1539  if (inserted) {
1540  RecalcPositions(first);
1541  result = true;
1542  }
1543 
1544  return result;
1545 }
1546 
1547 std::shared_ptr<Track> TrackList::FindPendingChangedTrack(TrackId id) const
1548 {
1549  // Linear search. Tracks in a project are usually very few.
1550  auto it = std::find_if( mPendingUpdates.begin(), mPendingUpdates.end(),
1551  [=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
1552  if (it == mPendingUpdates.end())
1553  return {};
1554  return *it;
1555 }
1556 
1558 {
1559  if ( !mPendingUpdates.empty() )
1560  return true;
1561  if (end() != std::find_if(begin(), end(), [](const Track *t){
1562  return t->GetId() == TrackId{};
1563  }))
1564  return true;
1565  return false;
1566 }
void SetY(int y)
Definition: Track.cpp:157
virtual void Paste(double WXUNUSED(t), const Track *WXUNUSED(src))=0
void SetId(TrackId id)
Definition: Track.h:123
bool mSolo
Definition: Track.h:391
A list of TrackListNode items.
Definition: Track.h:611
void Merge(const Track &init) override
Definition: Track.cpp:346
virtual Track * Prev(bool skiplinked=false)
Definition: Track.cpp:486
virtual double GetOffset() const =0
bool CanMoveDown(Track *t) const
Definition: Track.cpp:1116
void Select(Track *t, bool selected=true)
Definition: Track.cpp:1022
int GetHeight() const
Definition: Track.cpp:1363
bool isNull(TrackNodePointer p) const
Definition: Track.h:752
double GetStartTime() const
Definition: Track.cpp:1404
virtual void WriteAttr(const wxString &name, const wxString &value)
Definition: XMLWriter.cpp:131
int mIndex
Definition: Track.h:108
void SetIndex(int index)
Definition: Track.cpp:147
bool GetSelected() const
Definition: Track.h:268
TrackNodePointer mNode
Definition: Track.h:107
void Init(const PlayableTrack &init)
Definition: Track.cpp:339
void SetLinked(bool l)
Definition: Track.cpp:242
TrackNodePointer GetNode() const
Definition: Track.cpp:114
const Track * First(const TrackList *val=NULL)
Definition: Track.h:457
virtual bool Condition(Track *t) override
Definition: Track.cpp:606
TrackListOfKindIterator(int kind, TrackList *val=NULL)
Definition: Track.cpp:600
bool HandleXMLAttribute(const wxChar *attr, const wxChar *value)
Definition: Track.cpp:364
float GetPan() const
Definition: WaveTrack.cpp:451
VisibleTrackIterator(AudacityProject *project)
Definition: Track.cpp:621
bool IsSyncLockSelected() const
Definition: Track.cpp:291
TrackId GetId() const
Definition: Track.h:121
virtual double GetEndTime() const =0
Track * Add(std::unique_ptr< TrackKind > &&t)
Add a Track, giving it a fresh id.
Definition: Track.cpp:901
int mHeight
Definition: Track.h:110
void DeletionEvent()
Definition: Track.cpp:861
double GetEndTime() const
Definition: Track.cpp:1409
void SetHeight(int h)
Definition: Track.cpp:187
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:705
bool mSelected
Definition: Track.h:114
void RegisterPendingNewTrack(const std::shared_ptr< Track > &pTrack)
Definition: Track.cpp:1433
iterator begin()
Definition: Track.h:643
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
Definition: Track.cpp:1460
ListOfTracks::iterator TrackNodePointer
Definition: Track.h:63
Track * Last(bool skiplinked=false) override
Definition: Track.cpp:752
virtual int GetChannel() const
Definition: Track.h:278
wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, wxCommandEvent)
void SwapNodes(TrackNodePointer s1, TrackNodePointer s2)
Definition: Track.cpp:1126
bool GetLinked() const
Definition: Track.h:271
int GetIndex() const
Definition: Track.cpp:142
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1))=0
static long sCounter
Definition: Track.h:792
bool GetMinimized() const
Definition: Track.cpp:212
virtual int GetMinimizedHeight() const
Definition: Track.cpp:127
Track * Prev(bool skiplinked=false) override
Definition: Track.cpp:576
bool MoveUp(Track *t)
Definition: Track.cpp:1189
void DoSetLinked(bool l)
Definition: Track.cpp:262
virtual bool Condition(Track *t)=0
Track * StartWith(Track *val) override
Definition: Track.cpp:544
virtual double GetStartTime() const =0
void SetMinimized(bool isMinimized)
Definition: Track.cpp:217
TrackNodePointer getPrev(TrackNodePointer p) const
Definition: Track.h:770
bool ApplyPendingTracks()
Definition: Track.cpp:1486
AudacityProject * mProject
Definition: Track.h:556
wxString mDefaultName
Definition: Track.h:112
TimeTrack * GetTimeTrack()
Definition: Track.cpp:1235
TrackList & operator=(const TrackList &)=delete
static unsigned MinimumTrackHeight()
#define safenew
Definition: Audacity.h:223
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
void ResizingEvent(TrackNodePointer node)
Definition: Track.cpp:868
virtual void SetSelected(bool s)
Definition: Track.cpp:99
virtual int GetKind() const
Definition: Track.h:322
static std::shared_ptr< TrackList > Create()
Definition: Track.cpp:788
bool operator==(const TrackListIterator &other) const
Definition: Track.cpp:529
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:565
bool Condition(Track *t) override
Definition: Track.cpp:629
const Track * Next(bool skiplinked=false)
Definition: Track.h:461
std::shared_ptr< Track > RegisterPendingChangedTrack(Updater updater, Track *src)
Definition: Track.cpp:1415
TrackList()
Definition: Track.cpp:782
void Swap(TrackList &that)
Definition: Track.cpp:804
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:158
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
size_t size() const
Definition: Track.cpp:1225
std::function< void(Track &dest, const Track &src) > Updater
Definition: Track.h:795
bool CanMoveUp(Track *t) const
Definition: Track.cpp:1111
void WriteXMLAttributes(XMLWriter &xmlFile) const
Definition: Track.cpp:356
WaveTrackConstArray GetWaveTrackConstArray(bool selectionOnly, bool includeMuted=true) const
Definition: Track.cpp:1340
void DoSetY(int y)
Definition: Track.cpp:173
bool HandleXMLAttribute(const wxChar *, const wxChar *)
Definition: Track.h:364
Track * Prev(bool skiplinked=false) override
Definition: Track.cpp:722
ListOfTracks mPendingUpdates
Definition: Track.h:845
Track * GetNext(Track *t, bool linked=false) const
Return a track in the list that comes after Track t.
Definition: Track.cpp:1043
Track * AddToHead(std::unique_ptr< TrackKind > &&t)
Add a Track, giving it a fresh id.
Definition: Track.cpp:925
std::vector< std::shared_ptr< WaveTrack > > WaveTrackArray
Definition: AudioIO.h:65
void RecalcPositions(TrackNodePointer node)
Definition: Track.cpp:827
Track * Last(bool skiplinked=false) override
Definition: Track.cpp:588
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:66
bool mMinimized
Definition: Track.h:117
bool Contains(const Track *t) const
Mainly a test function. Uses a linear search, so could be slow.
Definition: Track.cpp:1215
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:1058
A Track that can load/save audio data to/from XML.
Definition: Track.h:353
Track * FindById(TrackId id)
Definition: Track.cpp:889
virtual ~TrackList()
Definition: Track.cpp:822
ListOfTracks::value_type Replace(Track *t, ListOfTracks::value_type &&with)
Definition: Track.cpp:958
std::weak_ptr< TrackList > mList
Definition: Track.h:106
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
WaveTrackArray GetWaveTrackArray(bool selectionOnly, bool includeMuted=true)
Definition: Track.cpp:1335
bool HasPendingTracks() const
Definition: Track.cpp:1557
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:94
virtual void DoSetMinimized(bool isMinimized)
Definition: Track.cpp:237
std::shared_ptr< Track > FindPendingChangedTrack(TrackId id) const
Definition: Track.cpp:1547
virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1))=0
unsigned GetNumExportChannels(bool selectionOnly) const
Find out how many channels this track list mixes to.
Definition: Track.cpp:1251
ViewInfo mViewInfo
Definition: Project.h:542
int min(int a, int b)
virtual Track * First(TrackList *val=nullptr)
Definition: Track.cpp:414
iterator end()
Definition: Track.h:644
virtual Track * Last(bool skiplinked=false)
Definition: Track.cpp:433
void Clear(bool sendEvent=true)
Make the list empty.
Definition: Track.cpp:1001
bool Condition(Track *t) override
Definition: Track.cpp:612
std::vector< std::shared_ptr< NoteTrack > > NoteTrackArray
Definition: Track.h:53
TrackNodePointer getEnd() const
Definition: Track.h:755
An AudioTrack that can be played and stopped.
Definition: Track.h:368
int vpos
Definition: ViewInfo.h:45
bool MoveDown(Track *t)
Definition: Track.cpp:1202
double mOffset
Definition: Track.h:222
TrackNodePointer cur
Definition: Track.h:434
An iterator for a TrackList.
Definition: Track.h:394
bool mLinked
Definition: Track.h:116
TrackNodePointer getBegin() const
Definition: Track.h:757
double GetMinOffset() const
Definition: Track.cpp:1399
wxRect mPanelRect
Definition: Track.h:557
virtual ~Track()
Definition: Track.cpp:109
int GetGroupHeight(Track *t) const
Definition: Track.cpp:1100
TrackNodePointer Remove(Track *t)
Definition: Track.cpp:980
Track(const std::shared_ptr< DirManager > &projDirManager)
Definition: Track.cpp:55
TrackList * l
Definition: Track.h:433
std::shared_ptr< Track > FindTrack() override
Definition: Track.cpp:334
bool IsGoodNextTrack(const Track *t) const
Definition: Track.cpp:686
Track * GetPrev(Track *t, bool linked=false) const
Definition: Track.cpp:1062
void Permute(const std::vector< TrackNodePointer > &permutation)
For use in sorting: assume each iterator points into this list, no duplications.
Definition: Track.cpp:876
Track * GetLink() const
Definition: Track.cpp:267
bool IsSyncLocked()
Definition: Project.cpp:5477
virtual Track * Next(bool skiplinked=false)
Definition: Track.cpp:456
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:300
void Init(const Track &orig)
Definition: Track.cpp:83
int GetY() const
Definition: Track.cpp:152
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:554
void WriteXMLAttributes(XMLWriter &WXUNUSED(xmlFile)) const
Definition: Track.h:361
void SetOwner(const std::weak_ptr< TrackList > &list, TrackNodePointer node)
Definition: Track.cpp:121
Track * operator*() const
Definition: Track.cpp:504
Definition: Track.h:73
std::vector< Updater > mUpdaters
Definition: Track.h:847
TrackNodePointer getNext(TrackNodePointer p) const
Definition: Track.h:761
virtual Track * StartWith(Track *val)
Definition: Track.cpp:397
virtual void SyncLockAdjust(double oldT1, double newT1)
Definition: Track.cpp:316
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:22
Track * RemoveCurrent()
Definition: Track.cpp:512
void PermutationEvent()
Definition: Track.cpp:854
static std::shared_ptr< Subclass > Pointer(Track *t)
Definition: Track.h:129
Track * StartWith(Track *member) override
Definition: Track.cpp:658
std::list< std::shared_ptr< Track > > ListOfTracks
Definition: Track.h:61
virtual void Merge(const Track &orig)
Definition: Track.cpp:104
virtual void DoSetHeight(int h)
Definition: Track.cpp:207
int mY
Definition: Track.h:109
wxSize GetTPTracksUsableArea()
Definition: Project.cpp:5218
SyncLockedTracksIterator(TrackList *val)
Definition: Track.cpp:645
std::shared_ptr< DirManager > mDirManager
Definition: Track.h:224
virtual Holder Duplicate() const =0
int GetHeight() const
Definition: Track.cpp:178
std::weak_ptr< TrackList > mSelf
Definition: Track.h:787
void UpdatePendingTracks()
Definition: Track.cpp:1440
bool empty() const
Definition: Track.cpp:1220
int mChannel
Definition: Track.h:221
bool mMute
Definition: Track.h:390
TrackId mId
Definition: Track.h:103
wxString mName
Definition: Track.h:111