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