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