Audacity 3.2.0
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*******************************************************************//*******************************************************************/
17#include "Track.h"
18
19#include <algorithm>
20#include <cassert>
21#include <numeric>
22
23#include <float.h>
24#include <wx/file.h>
25#include <wx/textfile.h>
26#include <wx/log.h>
27
28#include "BasicUI.h"
29#include "Project.h"
30
32
33#ifdef _MSC_VER
34//Disable truncation warnings
35#pragma warning( disable : 4786 )
36#endif
37
39{
40}
41
43{
44}
45
46// Copy all the track properties except the actual contents
47void Track::Init(const Track &orig)
48{
49 mId = orig.mId;
50 ChannelGroupAttachments &base = *this;
51 // Intentional slice assignment deep-copies the attachment array:
52 base = orig;
54 mLinkType = orig.mLinkType;
55}
56
58{
59 this->AttachedTrackObjects::ForEach([&](auto &attachment){
60 attachment.Reparent(this->SharedPointer());
61 });
62}
63
64const wxString &Track::GetName() const
65{
66 return mName;
67}
68
69void Track::SetName( const wxString &n )
70{
71 auto &name = mName;
72 if (name != n) {
73 name = n;
74 Notify(true);
75 }
76}
77
79{
80 return mSelected;
81}
82
84{
85 auto &selected = mSelected;
86 if (selected != s) {
87 selected = s;
88 auto pList = mList.lock();
89 if (pList)
90 pList->SelectionEvent(*this);
91 }
92}
93
94void Track::CopyAttachments(Track &dst, const Track &src, bool deep)
95{
96 if (!deep) {
97 // Share the satellites with the original, though they do not point
98 // back to the duplicate track
99 AttachedTrackObjects &attachments = dst;
100 attachments = src; // shallow copy
101 }
102 else
103 src.AttachedTrackObjects::ForEach([&](auto &attachment){
104 // Copy view state that might be important to undo/redo
105 attachment.CopyTo(dst);
106 });
107}
108
110{
111 // invoke "virtual constructor" to copy track object proper:
112 auto result = Clone(options.backup);
113 CopyAttachments(*result, *this, !options.shallowCopyAttachments);
114 return result;
115}
116
118{
119}
120
121
123{
124 return mNode;
125}
126
128(const std::weak_ptr<TrackList> &list, TrackNodePointer node)
129{
130 // BUG: When using this function to clear an owner, we may need to clear
131 // focused track too. Otherwise focus could remain on an invisible (or deleted) track.
132 mList = list;
133 mNode = node;
134}
135
136void Track::SetLinkType(LinkType linkType, bool completeList)
137{
138 DoSetLinkType(linkType, completeList);
139 if (const auto pList = mList.lock()) {
140 pList->RecalcPositions(mNode);
141 pList->ResizingEvent(mNode);
142 }
143}
144
146{
147 mName = other.mName;
148 mSelected = other.mSelected;
149}
150
151void Track::DoSetLinkType(LinkType linkType, bool completeList)
152{
153 auto oldType = GetLinkType();
154 if (linkType == oldType)
155 // No change
156 return;
157
158 if (oldType == LinkType::None) {
159 // Becoming linked
160
161 // First ensure that the previous does not link to this
162 if (auto partner = GetLinkedTrack())
163 partner->mLinkType = LinkType::None;
164 assert(!GetLinkedTrack());
165
166 // Change my link type
167 mLinkType = linkType;
168
169 // Keep link consistency, while still in un-zipped state
170 if (auto partner = GetLinkedTrack()) {
171 partner->mLinkType = LinkType::None;
172 partner->CopyGroupProperties(*this);
173 }
174 }
175 else if (linkType == LinkType::None) {
176 // Becoming unlinked
177 if (HasLinkedTrack()) {
178 if (auto partner = GetLinkedTrack()) {
179 // Make independent copy of group data in the partner, which should
180 // have had none
181 ChannelGroupAttachments &base = *partner;
182 // Intentional slice assignment deep-copies the attachment array:
183 base = *this;
184 partner->CopyGroupProperties(*this);
185 partner->mLinkType = LinkType::None;
186 }
187 }
189 }
190 else
191 // Remaining linked, changing the type
192 mLinkType = linkType;
193
194 // Assertion checks only in a debug build, does not have side effects!
195 assert(!completeList || LinkConsistencyCheck());
196}
197
199{
200 auto pList = GetOwner();
201 if (!pList)
202 return nullptr;
203
204 if (!pList->isNull(mNode)) {
205 if (HasLinkedTrack()) {
206 auto next = pList->getNext( mNode );
207 if ( !pList->isNull( next ) )
208 return next->get();
209 }
210
211 if (mNode != pList->ListOfTracks::begin()) {
212 auto prev = pList->getPrev( mNode );
213 if ( !pList->isNull( prev ) ) {
214 auto track = prev->get();
215 if (track && track->HasLinkedTrack())
216 return track;
217 }
218 }
219 }
220
221 return nullptr;
222}
223
224bool Track::HasLinkedTrack() const noexcept
225{
226 return mLinkType != LinkType::None;
227}
228
229std::optional<TranslatableString> Track::GetErrorOpening() const
230{
231 return {};
232}
233
234void Track::Notify(bool allChannels, int code)
235{
236 auto pList = mList.lock();
237 if (pList)
238 pList->DataEvent(SharedPointer(), allChannels, code);
239}
240
241void Track::SyncLockAdjust(double oldT1, double newT1)
242{
243 const auto endTime = GetEndTime();
244 if (newT1 > oldT1 && oldT1 > endTime)
245 return;
246 if (newT1 > oldT1) {
247 auto cutChannels = Cut(oldT1, endTime);
248 Paste(newT1, *cutChannels);
249 }
250 else if (newT1 < oldT1)
251 // Remove from the track
252 Clear(newT1, oldT1);
253}
254
255bool Track::Any() const
256 { return true; }
257
259 { return GetSelected(); }
260
261bool Track::IsLeader() const
262{
263 return !GetLinkedTrack() || HasLinkedTrack();
264}
265
267{
268 assert(!doFix || IsLeader());
269 // Sanity checks for linked tracks; unsetting the linked property
270 // doesn't fix the problem, but it likely leaves us with orphaned
271 // sample blocks instead of much worse problems.
272 bool err = false;
273 if (HasLinkedTrack()) {
274 if (auto link = GetLinkedTrack()) {
275 // A linked track's partner should never itself be linked
276 if (link->HasLinkedTrack()) {
277 err = true;
278 if (doFix) {
279 wxLogWarning(
280 L"Left track %s had linked right track %s with extra right "
281 "track link.\n Removing extra link from right track.",
282 GetName(), link->GetName());
283 link->SetLinkType(LinkType::None);
284 }
285 }
286 }
287 else {
288 err = true;
289 if (doFix) {
290 wxLogWarning(
291 L"Track %s had link to NULL track. Setting it to not be linked.",
292 GetName());
294 }
295 }
296 }
297 return ! err;
298}
299
300// TrackList
301//
302// The TrackList sends events whenever certain updates occur to the list it
303// is managing. Any other classes that may be interested in get these updates
304// should use TrackList::Subscribe().
305//
306
307// same value as in the default constructed TrackId:
308long TrackList::sCounter = -1;
309
312};
313
315{
316 return project.AttachedObjects::Get< TrackList >( key );
317}
318
320{
321 return Get( const_cast< AudacityProject & >( project ) );
322}
323
325 : mOwner{ pOwner }
326{
327}
328
329// Factory function
331{
332 return std::make_shared<TrackList>(pOwner);
333}
334
335#if 0
337{
338 if (this != &that) {
339 this->Clear();
340 Swap(that);
341 }
342 return *this;
343}
344#endif
345
347{
348 auto SwapLOTs = [](
349 ListOfTracks &a, const std::weak_ptr< TrackList > &aSelf,
350 ListOfTracks &b, const std::weak_ptr< TrackList > &bSelf )
351 {
352 a.swap(b);
353 for (auto it = a.begin(), last = a.end(); it != last; ++it)
354 (*it)->SetOwner(aSelf, it);
355 for (auto it = b.begin(), last = b.end(); it != last; ++it)
356 (*it)->SetOwner(bSelf, it);
357 };
358
359 const auto self = shared_from_this();
360 const auto otherSelf = that.shared_from_this();
361 SwapLOTs( *this, self, that, otherSelf );
362}
363
365{
366 Clear(false);
367}
368
369wxString TrackList::MakeUniqueTrackName(const wxString& baseTrackName) const
370{
371 int n = 1;
372 while(true) {
373 auto name = wxString::Format("%s %d", baseTrackName, n++);
374
375 bool found {false};
376 for(const auto track : Tracks<const Track>()) {
377 if(track->GetName() == name) {
378 found = true;
379 break;
380 }
381 }
382 if(!found)
383 return name;
384 }
385}
386
388{
389 if (isNull(node))
390 return;
391
392 Track *t;
393
394 auto prev = getPrev(node);
395 if (!isNull(prev))
396 t = prev->get();
397
398 const auto theEnd = End();
399 for (auto n = DoFind(node->get()); n != theEnd; ++n)
400 t = *n;
401}
402
404{
405 BasicUI::CallAfter( [wThis = weak_from_this(), event = std::move(event)]{
406 if (auto pThis = wThis.lock())
407 pThis->Publish(event);
408 } );
409}
410
412{
413 for (auto channel : Channels(&track))
414 QueueEvent({
415 TrackListEvent::SELECTION_CHANGE, channel->shared_from_this() });
416}
417
419 const std::shared_ptr<Track> &pTrack, bool allChannels, int code)
420{
421 auto doQueueEvent = [this, code](const std::shared_ptr<Track> &theTrack){
423 };
424 if (allChannels)
425 for (auto channel : Channels(pTrack.get()))
426 doQueueEvent(channel->shared_from_this());
427 else
428 doQueueEvent(pTrack);
429}
430
432{
434}
435
436void TrackList::DeletionEvent(std::weak_ptr<Track> node, bool duringReplace)
437{
439 { TrackListEvent::DELETION, std::move(node), duringReplace ? 1 : 0 });
440}
441
443{
445}
446
448{
450}
451
454{
455 auto it = const_cast<TrackList*>(this)->getEnd();
456 return {
457 { it, it, it, &Track::Any },
458 { it, it, it, &Track::Any }
459 };
460}
461
463{
464 if (!pTrack || pTrack->GetOwner().get() != this)
465 return EndIterator<Track>();
466 else
467 return MakeTrackIterator<Track>(pTrack->GetNode());
468}
469
471{
472 auto iter = DoFind(pTrack);
473 while( *iter && ! ( *iter )->IsLeader() )
474 --iter;
475 return iter.Filter( &Track::IsLeader );
476}
477
478void TrackList::Insert(const Track* before,
479 const Track::Holder &pSrc, bool assignIds)
480{
481 assert(before == nullptr || Find(before) != EndIterator<const Track>());
482
483 if(before == nullptr)
484 {
485 Add(pSrc, assignIds);
486 return;
487 }
488
489 std::vector<Track *> arr;
490 arr.reserve(Size() + 1);
491 for (const auto track : *this) {
492 if (track == before)
493 arr.push_back(pSrc.get());
494 arr.push_back(track);
495 }
496 Add(pSrc, assignIds);
497 Permute(arr);
498}
499
500void TrackList::Permute(const std::vector<Track *> &tracks)
501{
502 std::vector<TrackNodePointer> permutation;
503 for (const auto pTrack : tracks)
504 for (const auto pChannel : Channels(pTrack))
505 permutation.push_back(pChannel->GetNode());
506 for (const auto iter : permutation) {
507 ListOfTracks::value_type track = *iter;
508 erase(iter);
509 Track *pTrack = track.get();
510 pTrack->SetOwner(shared_from_this(), insert(ListOfTracks::end(), track));
511 }
512 auto n = getBegin();
515}
516
518{
519 // Linear search. Tracks in a project are usually very few.
520 // Search only the non-pending tracks.
521 auto it = std::find_if( ListOfTracks::begin(), ListOfTracks::end(),
522 [=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
523 if (it == ListOfTracks::end())
524 return {};
525 return it->get();
526}
527
528Track *TrackList::DoAddToHead(const std::shared_ptr<Track> &t)
529{
530 Track *pTrack = t.get();
531 push_front(ListOfTracks::value_type(t));
532 auto n = getBegin();
533 pTrack->SetOwner(shared_from_this(), n);
534 pTrack->SetId( TrackId{ ++sCounter } );
536 AdditionEvent(n);
537 return front().get();
538}
539
540Track *TrackList::DoAdd(const std::shared_ptr<Track> &t, bool assignIds)
541{
542 if (!ListOfTracks::empty()) {
543 auto &pLast = *ListOfTracks::rbegin();
544 if (pLast->mLinkType != Track::LinkType::None)
545 t->CopyGroupProperties(*pLast);
546 }
547
548 push_back(t);
549
550 auto n = getPrev( getEnd() );
551
552 t->SetOwner(shared_from_this(), n);
553 if (mAssignsIds && assignIds)
554 t->SetId(TrackId{ ++sCounter });
556 AdditionEvent(n);
557 return back().get();
558}
559
561{
562 assert(t.GetOwner().get() == this);
563 assert(!with.empty());
564
565 auto save = t.shared_from_this();
566
568 auto node = t.GetNode();
569 t.SetOwner({}, {});
570
572 const auto iter = with.ListOfTracks::begin();
573 const auto pTrack = *iter;
574 *node = pTrack;
575 with.erase(iter);
576 pTrack->SetOwner(shared_from_this(), node);
577 pTrack->SetId(save->GetId());
578 RecalcPositions(node);
579 DeletionEvent(save, true);
580 AdditionEvent(node);
581 return save;
582}
583
584std::shared_ptr<Track> TrackList::Remove(Track &track)
585{
586 auto *t = &track;
587 auto iter = getEnd();
588 auto node = t->GetNode();
589 t->SetOwner({}, {});
590
591 std::shared_ptr<Track> holder;
592 if (!isNull(node)) {
593 holder = *node;
594
595 iter = getNext(node);
596 erase(node);
597 if (!isNull(iter))
598 RecalcPositions(iter);
599
600 DeletionEvent(t->shared_from_this(), false);
601 }
602 return holder;
603}
604
605void TrackList::Clear(bool sendEvent)
606{
607 // Null out the back-pointers to this in tracks, in case there
608 // are outstanding shared_ptrs to those tracks, making them outlive
609 // the temporary ListOfTracks below.
610 for (auto pTrack: Tracks<Track>()) {
611 pTrack->SetOwner({}, {});
612
613 if (sendEvent)
614 DeletionEvent(pTrack->shared_from_this(), false);
615 }
616
617 ListOfTracks tempList;
618 tempList.swap( *this );
619}
620
622Track *TrackList::GetNext(Track &t, bool linked) const
623{
624 auto node = t.GetNode();
625 if (!isNull(node)) {
626 if (linked && t.HasLinkedTrack())
627 node = getNext(node);
628
629 if (!isNull(node))
630 node = getNext(node);
631
632 if (!isNull(node))
633 return node->get();
634 }
635 return nullptr;
636}
637
638Track *TrackList::GetPrev(Track &t, bool linked) const
639{
640 TrackNodePointer prev;
641 auto node = t.GetNode();
642 if (!isNull(node)) {
643 // linked is true and input track second in team?
644 if (linked) {
645 prev = getPrev(node);
646 if (!isNull(prev) &&
647 !t.HasLinkedTrack() && t.GetLinkedTrack())
648 // Make it the first
649 node = prev;
650 }
651
652 prev = getPrev(node);
653 if (!isNull(prev)) {
654 // Back up once
655 node = prev;
656
657 // Back up twice sometimes when linked is true
658 if (linked) {
659 prev = getPrev(node);
660 if( !isNull(prev) &&
661 !(*node)->HasLinkedTrack() &&
662 (*node)->GetLinkedTrack())
663 node = prev;
664 }
665
666 return node->get();
667 }
668 }
669 return nullptr;
670}
671
673{
674 return GetPrev(t, true) != nullptr;
675}
676
678{
679 return GetNext(t, true) != nullptr;
680}
681
682// This is used when you want to swap the track at s1 with the track at s2.
683// The complication is that the tracks are stored in a single
684// linked list.
686{
687 // if a null pointer is passed in, we want to know about it
688 wxASSERT(!isNull(s1));
689 wxASSERT(!isNull(s2));
690
691 // Safety check...
692 if (s1 == s2)
693 return;
694
695 // Be sure s1 is the earlier iterator
696 {
697 const auto begin = ListOfTracks::begin();
698 auto d1 = std::distance(begin, s1);
699 auto d2 = std::distance(begin, s2);
700 if (d1 > d2)
701 std::swap(s1, s2);
702 }
703
704 // For saving the removed tracks
705 using Saved = ListOfTracks::value_type;
706 Saved saved1, saved2;
707
708 auto doSave = [&](Saved &saved, TrackNodePointer &s) {
709 saved = *s, s = erase(s);
710 };
711
712 doSave(saved1, s1);
713 // The two ranges are assumed to be disjoint but might abut
714 const bool same = (s1 == s2);
715 doSave(saved2, s2);
716 if (same)
717 // Careful, we invalidated s1 in the second doSave!
718 s1 = s2;
719
720 // Reinsert them
721 auto doInsert = [&](Saved &saved, TrackNodePointer &s) {
722 const auto pTrack = saved.get();
723 // Insert before s, and reassign s to point at the new node before
724 // old s; which is why we saved pointers in backwards order
725 pTrack->SetOwner(shared_from_this(), s = insert(s, saved) );
726 };
727 // This does not invalidate s2 even when it equals s1:
728 doInsert(saved2, s1);
729 // Even if s2 was same as s1, this correctly inserts the saved1 range
730 // after the saved2 range, when done after:
731 doInsert(saved1, s2);
732
733 // Now correct the Index in the tracks, and other things
734 RecalcPositions(s1);
736}
737
739{
740 Track *p = GetPrev(t, true);
741 if (p) {
742 SwapNodes(p->GetNode(), t.GetNode());
743 return true;
744 }
745 return false;
746}
747
749{
750 Track *n = GetNext(t, true);
751 if (n) {
752 SwapNodes(t.GetNode(), n->GetNode());
753 return true;
754 }
755 return false;
756}
757
759{
760 return Begin() == End();
761}
762
763namespace {
764 // Abstract the common pattern of the following two member functions
765 inline double Accumulate(const TrackList &list,
766 double (Track::*memfn)() const, double ident,
767 const double &(*combine)(const double&, const double&))
768 {
769 // Default the answer to zero for empty list
770 if (list.empty())
771 return 0.0;
772
773 // Otherwise accumulate minimum or maximum of track values
774 return list.Any().accumulate(ident, combine, memfn);
775 }
776}
777
779{
780 return Accumulate(*this, &Track::GetStartTime,
781 std::numeric_limits<double>::max(), std::min);
782}
783
785{
786 return Accumulate(*this, &Track::GetEndTime,
787 std::numeric_limits<double>::lowest(), std::max);
788}
789
791{
792 static Track::TypeInfo info{
793 { "generic", "generic", XO("Generic Track") }, false };
794 return info;
795}
796
798{
799 return true;
800}
801
802// Serialize, not with tags of its own, but as attributes within a tag.
804 XMLWriter &xmlFile, bool includeNameAndSelected) const
805{
806 if (includeNameAndSelected) {
807 // May write name and selectedness redundantly for right channels,
808 // but continue doing that in case the file is opened in Audacity 3.1.x
809 // which does not have unique ChannelGroupData for the track
810 xmlFile.WriteAttr(wxT("name"), GetName());
811 xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected());
812 }
813 AttachedTrackObjects::ForEach([&](auto &attachment){
814 attachment.WriteXMLAttributes( xmlFile );
815 });
816}
817
818// Return true iff the attribute is recognized.
820 const std::string_view& attr, const XMLAttributeValueView& valueView)
821{
822 long nValue = -1;
823
824 bool handled = false;
825 AttachedTrackObjects::ForEach([&](auto &attachment){
826 handled = handled || attachment.HandleXMLAttribute( attr, valueView );
827 });
828 if (handled)
829 ;
830 // Note that the per-group properties of name and selectedness may have
831 // been written redundantly for each channel, and values for the last
832 // channel will be the last ones assigned
833 else if (attr == "name") {
834 SetName(valueView.ToWString());
835 return true;
836 }
837 else if (attr == "isSelected" && valueView.TryGet(nValue)) {
838 this->SetSelected(nValue != 0);
839 return true;
840 }
841 return false;
842}
843
845{
846 auto pList = mList.lock();
847 if (pList) {
848 pList->RecalcPositions(mNode);
849 pList->ResizingEvent(mNode);
850 }
851}
852
854{
855 return mLinkType;
856}
857
859 const Track::Holder &pTrack)
860{
861 assert(pTrack == nullptr || pTrack->GetOwner() == nullptr);
862 // Make a well formed channel group from these tracks
863 auto tempList = Create(pProject);
864 if (pTrack)
865 tempList->Add(pTrack);
866 tempList->mAssignsIds = false;
867 return tempList;
868}
869
870void TrackList::Append(TrackList &&list, bool assignIds)
871{
872 auto iter = list.ListOfTracks::begin(),
873 end = list.ListOfTracks::end();
874 while (iter != end) {
875 auto pTrack = *iter;
876 iter = list.erase(iter);
877 this->Add(pTrack, assignIds);
878 }
879}
880
882{
883 const auto iter = list.ListOfTracks::begin(),
884 end = list.ListOfTracks::end();
885 if (iter != end) {
886 auto pTrack = *iter;
887 list.erase(iter);
888 this->Add(pTrack);
889 }
890}
891
893{
894 auto iter = ListOfTracks::begin();
895 auto result = *iter;
896 erase(iter);
897 result->SetOwner({}, {});
898 return result;
899}
wxT("CloseDown"))
Toolkit-neutral facade for basic user interface services.
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
MessageBoxException for violation of preconditions or assertions.
static CommandHandlerObject & ident(AudacityProject &project)
const auto tracks
const auto project
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: Track.cpp:310
declares abstract base class Track, TrackList, and iterators over TrackList
ListOfTracks::iterator TrackNodePointer
Definition: Track.h:46
std::list< std::shared_ptr< Track > > ListOfTracks
Definition: Track.h:44
std::shared_ptr< TrackList > TrackListHolder
Definition: Track.h:42
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
Definition: Channel.cpp:61
double GetStartTime() const
Get the minimum of Start() values of intervals, or 0 when none.
Definition: Channel.cpp:50
LinkType
For two tracks describes the type of the linkage.
Definition: Channel.h:512
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:275
Utility to register hooks into a host class that attach client data.
Definition: ClientData.h:229
void ForEach(const Function &function)
Invoke function on each ClientData object that has been created in this.
Definition: ClientData.h:389
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
bool GetSelected() const
Selectedness is always the same for all channels of a group.
Definition: Track.cpp:78
virtual void Paste(double t, const Track &src)=0
Weak precondition allows overrides to replicate one channel into many.
Track()
Definition: Track.cpp:38
virtual void SetSelected(bool s)
Definition: Track.cpp:83
bool IsSelected() const
Definition: Track.cpp:258
void Notify(bool allChannels, int code=-1)
Definition: Track.cpp:234
virtual ~Track()
Definition: Track.cpp:117
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
Definition: Track.cpp:797
static const TypeInfo & ClassTypeInfo()
Definition: Track.cpp:790
LinkType mLinkType
Definition: Track.h:439
virtual void SyncLockAdjust(double oldT1, double newT1)
Definition: Track.cpp:241
TrackNodePointer GetNode() const
Retrieve mNode with debug checks.
Definition: Track.cpp:122
std::shared_ptr< TrackList > GetOwner() const
Definition: Track.h:230
bool mSelected
Definition: Track.h:440
static void CopyAttachments(Track &dst, const Track &src, bool deep)
Copy (deep) or just share (!deep) AttachedTrackObjects.
Definition: Track.cpp:94
virtual bool LinkConsistencyFix(bool doFix=true)
Check consistency of channel groups, and maybe fix it.
Definition: Track.cpp:266
void SetLinkType(LinkType linkType, bool completeList=true)
Definition: Track.cpp:136
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:146
bool HasLinkedTrack() const noexcept
During file loading only, true for leaders of multichannel groups.
Definition: Track.cpp:224
void CopyGroupProperties(const Track &other)
Definition: Track.cpp:145
virtual void Clear(double t0, double t1)=0
std::shared_ptr< Track > Holder
Definition: Track.h:202
wxString mName
Definition: Track.h:437
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:128
void SetId(TrackId id)
Definition: Track.h:138
void ReparentAllAttachments()
Definition: Track.cpp:57
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
Definition: Track.cpp:819
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:64
void Init(const Track &orig)
Definition: Track.cpp:47
virtual Holder Duplicate(DuplicateOptions={}) const
public nonvirtual duplication function that invokes Clone()
Definition: Track.cpp:109
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
Definition: Track.cpp:803
void AdjustPositions()
Definition: Track.cpp:844
std::weak_ptr< TrackList > mList
Definition: Track.h:127
TrackNodePointer mNode
Holds iterator to self, so that TrackList::Find can be constant-time.
Definition: Track.h:129
bool IsLeader() const
Definition: Track.cpp:261
Track * GetLinkedTrack() const
Definition: Track.cpp:198
LinkType GetLinkType() const noexcept
Definition: Track.cpp:853
virtual std::optional< TranslatableString > GetErrorOpening() const
Definition: Track.cpp:229
void DoSetLinkType(LinkType linkType, bool completeList=true)
Definition: Track.cpp:151
bool LinkConsistencyCheck()
Do the non-mutating part of consistency fix only and return status.
Definition: Track.h:225
virtual Holder Cut(double t0, double t1)=0
Create tracks and modify this track.
bool Any() const
Definition: Track.cpp:255
void SetName(const wxString &n)
Definition: Track.cpp:69
TrackId mId
Identifies the track only in-session, not persistently.
Definition: Track.h:124
An in-session identifier of track objects across undo states. It does not persist between sessions.
Definition: Track.h:79
Iterator over only members of a TrackList of the specified subtype, optionally filtered by a predicat...
Definition: Track.h:521
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:850
void PermutationEvent(TrackNodePointer node)
Definition: Track.cpp:431
bool CanMoveUp(Track &t) const
Definition: Track.cpp:672
Track * DoAdd(const std::shared_ptr< Track > &t, bool assignIds)
Definition: Track.cpp:540
bool empty() const
Definition: Track.cpp:758
static TrackListHolder Create(AudacityProject *pOwner)
Definition: Track.cpp:330
void Insert(const Track *before, const Track::Holder &pSrc, bool assignIds=false)
Moves *pSrc to position where before is located. If before is nullptr the track is appended.
Definition: Track.cpp:478
void AppendOne(TrackList &&list)
Remove first track (if any) from list and put it at the end of this
Definition: Track.cpp:881
static long sCounter
Definition: Track.h:1217
Track * GetNext(Track &, bool linked=false) const
Return a track in the list that comes after Track t.
Definition: Track.cpp:622
void Permute(const std::vector< Track * > &tracks)
Definition: Track.cpp:500
double GetEndTime() const
Return the greatest end time of the tracks, or 0 when no tracks.
Definition: Track.cpp:784
void ResizingEvent(TrackNodePointer node)
Definition: Track.cpp:447
TrackNodePointer getBegin() const
Definition: Track.h:1177
iterator end()
Definition: Track.h:906
TrackIter< Track > Find(Track *pTrack)
Definition: Track.cpp:470
wxString MakeUniqueTrackName(const wxString &baseTrackName) const
Returns string that contains baseTrackName, but is guaranteed to be unique among other tracks in that...
Definition: Track.cpp:369
TrackList & operator=(const TrackList &)=delete
double GetStartTime() const
Return the least start time of the tracks, or 0 when no tracks.
Definition: Track.cpp:778
void Append(TrackList &&list, bool assignIds=true)
Remove all tracks from list and put them at the end of this
Definition: Track.cpp:870
size_t Size() const
Definition: Track.h:1091
bool isNull(TrackNodePointer p) const
Definition: Track.h:1174
bool CanMoveDown(Track &t) const
Definition: Track.cpp:677
TrackNodePointer getNext(TrackNodePointer p) const
Move an iterator to the next node, if any; else stay at end.
Definition: Track.h:1181
void Swap(TrackList &that)
Definition: Track.cpp:346
void AdditionEvent(TrackNodePointer node)
Definition: Track.cpp:442
void RecalcPositions(TrackNodePointer node)
Definition: Track.cpp:387
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:950
bool MoveUp(Track &t)
Definition: Track.cpp:738
void SelectionEvent(Track &track)
Definition: Track.cpp:411
TrackNodePointer getEnd() const
Definition: Track.h:1175
Track::Holder DetachFirst()
Remove and return the first track.
Definition: Track.cpp:892
TrackIterRange< Track > EmptyRange() const
Definition: Track.cpp:452
Track::Holder ReplaceOne(Track &t, TrackList &&with)
Definition: Track.cpp:560
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
iterator begin()
Definition: Track.h:905
Track * DoAddToHead(const std::shared_ptr< Track > &t)
Definition: Track.cpp:528
Track::Holder Remove(Track &track)
Remove a track and return it.
Definition: Track.cpp:584
Track * FindById(TrackId id)
Definition: Track.cpp:517
TrackIter< Track > DoFind(Track *pTrack)
Definition: Track.cpp:462
void DataEvent(const std::shared_ptr< Track > &pTrack, bool allChannels, int code)
Definition: Track.cpp:418
iterator Begin()
This private function still iterates channels not tracks.
Definition: Track.h:939
iterator End()
This private function still iterates channels not tracks.
Definition: Track.h:941
void QueueEvent(TrackListEvent event)
Definition: Track.cpp:403
void SwapNodes(TrackNodePointer s1, TrackNodePointer s2)
Definition: Track.cpp:685
TrackList(const TrackList &that)=delete
TrackKind * Add(const std::shared_ptr< TrackKind > &t, bool assignIds=true)
Definition: Track.h:1048
bool MoveDown(Track &t)
Definition: Track.cpp:748
virtual ~TrackList()
Definition: Track.cpp:364
void Clear(bool sendEvent=true)
Make the list empty.
Definition: Track.cpp:605
void DeletionEvent(std::weak_ptr< Track > node, bool duringReplace)
Definition: Track.cpp:436
bool mAssignsIds
Definition: Track.h:1223
TrackNodePointer getPrev(TrackNodePointer p) const
Move an iterator to the previous node, if any; else wrap to end.
Definition: Track.h:1191
static TrackListHolder Temporary(AudacityProject *pProject, const Track::Holder &pTrack={})
Definition: Track.cpp:858
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1016
Track * GetPrev(Track &, bool linked=false) const
Definition: Track.cpp:638
A view into an attribute value. The class does not take the ownership of the data.
wxString ToWString() const
Convert the view value to wxString.
bool TryGet(bool &value) const noexcept
Try to get a boolean value from the view.
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:25
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:213
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:628
double Accumulate(const TrackList &list, double(Track::*memfn)() const, double ident, const double &(*combine)(const double &, const double &))
Definition: Track.cpp:765
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
Choices when duplicating a track.
Definition: Track.h:271
Empty argument passed to some public constructors.
Definition: Track.h:117
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Definition: Track.h:682
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
Definition: Track.h:803
@ RESIZING
Posted when some track changed its height.
Definition: Track.h:816
@ SELECTION_CHANGE
Posted when the set of selected tracks changes.
Definition: Track.h:806
@ DELETION
Posted when a track has been deleted from a tracklist. Also posted when one track replaces another.
Definition: Track.h:825
@ ADDITION
Posted when a track has been added to a tracklist. Also posted when one track replaces another.
Definition: Track.h:819
@ PERMUTED
Posted when tracks are reordered but otherwise unchanged.
Definition: Track.h:813
@ TRACK_DATA_CHANGE
Posted when certain fields of a track change.
Definition: Track.h:809