31#include <wx/textfile.h>
42#pragma warning( disable : 4786 )
58: vrulerSize( orig.vrulerSize )
75 std::make_unique<ChannelGroupData>(*orig.
mpGroupData) :
nullptr;
92 auto pList =
mList.lock();
100 auto pList =
mList.lock();
113 auto result =
Clone();
117 attachment.CopyTo( *result );
130 wxASSERT(
mList.lock() == NULL ||
this ==
mNode.first->get());
155 auto pList =
mList.lock();
156 if (pList && !pList->mPendingUpdates.empty()) {
157 auto orig = pList->FindById(
GetId() );
158 if (orig && orig !=
this) {
159 orig->SetLinkType(linkType);
167 pList->RecalcPositions(
mNode);
168 pList->ResizingEvent(
mNode);
176 mpGroupData = std::make_unique<ChannelGroupData>();
184 if (
auto pLeader = *pList->FindLeader(pTrack))
187 return pTrack->MakeGroupData();
199 if (linkType == oldType)
208 partner->mpGroupData.reset();
216 partner->mpGroupData.reset();
225 assert(!partner->mpGroupData);
226 partner->mpGroupData =
250 auto pList =
mList.lock();
254 if (!pList->isNull(
mNode)) {
256 auto next = pList->getNext(
mNode );
257 if ( !pList->isNull( next ) )
258 return next.first->get();
262 auto prev = pList->getPrev(
mNode );
263 if ( !pList->isNull( prev ) ) {
264 auto track = prev.first->get();
265 if (track && track->HasLinkedTrack())
281 auto pList =
mList.lock();
296 Paste(newT1, tmp.get());
298 else if (newT1 < oldT1) {
357 return mMute.load(std::memory_order_relaxed);
362 mMute.store(value, std::memory_order_relaxed);
367 return mSolo.load(std::memory_order_relaxed);
372 mSolo.store(value, std::memory_order_relaxed);
388 if (attr ==
"mute" && value.
TryGet(nValue)) {
392 else if (attr ==
"solo" && value.
TryGet(nValue)) {
420 std::make_unique<ChannelGroupData>(*n->
mpGroupData) :
nullptr;
434 if (link->HasLinkedTrack()) {
438 L
"Left track %s had linked right track %s with extra right "
439 "track link.\n Removing extra link from right track.",
453 L
"Track %s and %s had left/right track links out of order. "
454 "Setting tracks to not be linked.",
464 L
"Track %s had link to NULL track. Setting it to not be linked.",
489 return project.AttachedObjects::Get<
TrackList >(
key );
505 return std::make_shared<TrackList>( pOwner );
522 ListOfTracks &a,
const std::weak_ptr< TrackList > &aSelf,
523 ListOfTracks &b,
const std::weak_ptr< TrackList > &bSelf )
526 for (
auto it = a.begin(), last = a.end(); it != last; ++it)
527 (*it)->SetOwner(aSelf, {it, &a});
528 for (
auto it = b.begin(), last = b.end(); it != last; ++it)
529 (*it)->SetOwner(bSelf, {it, &b});
532 const auto self = shared_from_this();
533 const auto otherSelf = that.shared_from_this();
534 SwapLOTs( *
this, self, that, otherSelf );
535 SwapLOTs( this->mPendingUpdates, self, that.mPendingUpdates, otherSelf );
536 mUpdaters.swap(that.mUpdaters);
549 auto name = wxString::Format(
"%s %d", baseTrackName, n++);
552 for(
const auto track :
Any())
554 if(track->GetName() ==
name)
575 t = prev.first->get();
579 const auto theEnd =
end();
580 for (
auto n =
Find( node.first->get() ); n != theEnd; ++n) {
591 if (
auto pThis = wThis.lock())
592 pThis->Publish(event);
608 const std::shared_ptr<Track> &pTrack,
bool modifyState )
611 pTrack,
static_cast<int>(modifyState) });
648 auto iter =
Find(pTrack);
649 while( *iter && ! ( *iter )->IsLeader() )
661 auto pPartner = pOwner->GetNext(&track,
false);
668 pOwner->MoveUp(pPartner);
669 pPartner->mpGroupData = move(pData);
677 for (
const auto iter : permutation) {
678 ListOfTracks::value_type track = *iter.first;
680 Track *pTrack = track.get();
681 pTrack->
SetOwner(shared_from_this(),
694 [=](
const ListOfTracks::value_type &ptr){
return ptr->GetId() ==
id; } );
702 Track *pTrack = t.get();
703 push_front(ListOfTracks::value_type(t));
705 pTrack->
SetOwner(shared_from_this(), n);
709 return front().get();
718 t->SetOwner(shared_from_this(), n);
726 ListOfTracks::value_type
728 ListOfTracks::value_type holder;
730 auto node = t->GetNode();
733 holder = *node.first;
735 Track *pTrack = with.get();
737 pTrack->
SetOwner(shared_from_this(), node);
738 pTrack->
SetId( t->GetId() );
739 RecalcPositions(node);
741 DeletionEvent(t->shared_from_this(),
true);
749 auto list = track.
mList.lock();
750 if (list.get() ==
this)
753 for (
auto c : channels)
756 c->SetChannel(Track::ChannelType::MonoChannel);
768 auto list = track.
mList.lock();
769 if (list.get() ==
this)
771 if (*list->FindLeader(&track) != &track)
774 auto first = list->Find(&track);
775 auto canLink = [&]() ->
bool {
776 int count = nChannels;
779 if ((*it)->HasLinkedTrack())
790 auto second = std::next(first);
807 ListOfTracks::value_type holder = *node.first;
825 for (
auto pTrack: *
this )
827 pTrack->SetOwner({}, {});
835 pTrack->SetOwner({}, {});
842 tempList.swap( *
this );
863 return node.first->get();
894 !(*node.first)->HasLinkedTrack() && (*node.first)->GetLinkedTrack() )
898 return node.first->get();
908 return GetPrev(t,
true) != NULL;
913 return GetNext(t,
true) != NULL;
927 s1 = ( *
FindLeader( s1.first->get() ) )->GetNode();
928 s2 = ( *
FindLeader( s2.first->get() ) )->GetNode();
935 if ((*s1.first)->GetIndex() >= (*s2.first)->GetIndex())
939 using Saved = std::vector< ListOfTracks::value_type >;
940 Saved saved1, saved2;
943 size_t nn =
Channels( s.first->get() ).size();
947 saved[nn] = *s.first, s.first = erase(s.first);
950 doSave( saved1, s1 );
952 const bool same = (s1 == s2);
953 doSave( saved2, s2 );
961 for (
auto & pointer : saved)
962 pTrack = pointer.get(),
965 pTrack->
SetOwner(shared_from_this(),
966 s = { insert(s.first, pointer),
this } );
969 doInsert( saved2, s1 );
972 doInsert( saved1, s2 );
1029 double (
Track::*memfn)()
const,
1031 const double &(*combine)(
const double&,
const double&))
1039 return list.
Any().accumulate(
ident, combine, memfn);
1058std::shared_ptr<Track>
1061 std::shared_ptr<Track> pTrack;
1063 pTrack = src->
Clone();
1082 Add<Track>( pTrack );
1093 auto src =
FindById( pendingTrack->GetId() );
1094 if (pendingTrack && src) {
1096 updater( *pendingTrack, *src );
1097 pendingTrack->DoSetLinkType(src->GetLinkType());
1107 pTrack->SetOwner( {}, {} );
1116 bool foundNode =
false;
1120 if (it->get()->GetId() ==
TrackId{}) {
1123 pAdded->push_back( *it );
1124 (*it)->SetOwner( {}, {} );
1128 while (it != stop && it->get()->GetId() ==
TrackId{});
1130 if (!foundNode && it != stop) {
1131 node = (*it)->GetNode();
1147 bool result =
false;
1161 std::vector< std::shared_ptr<Track> > reinstated;
1163 for (
auto &pendingTrack : updates) {
1165 pendingTrack->AttachedTrackObjects::ForEach([&](
auto &attachment){
1166 attachment.Reparent( pendingTrack );
1168 auto src =
FindById( pendingTrack->GetId() );
1170 this->
Replace(src, pendingTrack), result =
true;
1175 reinstated.push_back(pendingTrack);
1180 for (
auto &pendingTrack : reinstated)
1182 this->
Add( pendingTrack ), result =
true;
1186 bool inserted =
false;
1187 ListOfTracks::iterator first;
1188 for (
auto &pendingTrack : additions) {
1191 std::advance( iter, pendingTrack->GetIndex() );
1192 iter = ListOfTracks::insert( iter, pendingTrack );
1193 pendingTrack->SetOwner( shared_from_this(), {iter,
this} );
1214 auto pList =
mList.lock();
1216 const auto id =
GetId();
1217 const auto end = pList->mPendingUpdates.end();
1218 auto it = std::find_if(
1219 pList->mPendingUpdates.begin(),
end,
1220 [=](
const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
1234 auto pList =
mList.lock();
1236 const auto id =
GetId();
1237 const auto pred = [=](
const ListOfTracks::value_type &ptr ) {
1238 return ptr->GetId() ==
id; };
1239 const auto end = pList->mPendingUpdates.end();
1240 const auto it = std::find_if( pList->mPendingUpdates.begin(),
end, pred );
1243 const auto end2 = list2.end();
1244 const auto it2 = std::find_if( list2.begin(), end2, pred );
1255 {
"generic",
"generic",
XO(
"Generic Track") },
false };
1276 XMLWriter &xmlFile,
bool includeNameAndSelected)
const
1278 if (includeNameAndSelected) {
1283 attachment.WriteXMLAttributes( xmlFile );
1293 bool handled =
false;
1295 handled = handled || attachment.HandleXMLAttribute( attr, valueView );
1299 else if (attr ==
"name") {
1303 else if (attr ==
"isSelected" && valueView.
TryGet(nValue)) {
1312 auto pList =
mList.lock();
1314 pList->RecalcPositions(
mNode);
1315 pList->ResizingEvent(
mNode);
1322 {
"audio",
"audio",
XO(
"Audio Track") },
1330 {
"playable",
"playable",
XO(
"Playable Track") },
1357 auto leader = *owner->FindLeader(
this);
1367 : mpTracks{
TrackList::Create(nullptr) }
1370 if ( pTrack->GetId() ==
TrackId{} )
1373 mpTracks->
Add(pTrack->Duplicate());
1379 for (
auto pTrack : mpTracks->Any())
1380 dstTracks.Add(pTrack->Duplicate());
1390 return std::make_shared<TrackListRestorer>(project);
1399 iter = std::find_if(
exts.begin(),
end, [](
auto &pExt){
1400 return dynamic_cast<TrackListRestorer*>(pExt.get());
1403 return static_cast<TrackListRestorer*
>(iter->get())->mpTracks.get();
Toolkit-neutral facade for basic user interface services.
const TranslatableString name
MessageBoxException for violation of preconditions or assertions.
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
static CommandHandlerObject & ident(AudacityProject &project)
static const AudacityProject::AttachedObjects::RegisteredFactory key
declares abstract base class Track, TrackList, and iterators over TrackList
std::pair< ListOfTracks::iterator, ListOfTracks * > TrackNodePointer
Pairs a std::list iterator and a pointer to a list, for comparison purposes.
std::list< std::shared_ptr< Track > > ListOfTracks
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Track subclass holding data representing sound (as notes, or samples, or ...)
bool HandleXMLAttribute(const std::string_view &, const XMLAttributeValueView &)
static const TypeInfo & ClassTypeInfo()
void WriteXMLAttributes(XMLWriter &WXUNUSED(xmlFile)) const
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Utility to register hooks into a host class that attach client data.
void ForEach(const Function &function)
Invoke function on each ClientData object that has been created in this.
AudioTrack subclass that can also be audibly replayed by the program.
bool HandleXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &value)
std::atomic< bool > mMute
Atomic because it may be read by worker threads in playback.
void DoSetSolo(bool value)
void Init(const PlayableTrack &init)
void Merge(const Track &init) override
void DoSetMute(bool value)
static const TypeInfo & ClassTypeInfo()
void WriteXMLAttributes(XMLWriter &xmlFile) const
std::atomic< bool > mSolo
Atomic because it may be read by worker threads in playback.
Abstract base class for an object holding data associated with points on a time axis.
virtual void Merge(const Track &orig)
void EnsureVisible(bool modifyState=false)
virtual void SetSelected(bool s)
virtual void Paste(double WXUNUSED(t), const Track *WXUNUSED(src))=0
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1))=0
virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1))=0
void SetChannel(ChannelType c) noexcept
static void FinishCopy(const Track *n, Track *dest)
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
virtual double GetStartTime() const =0
static const TypeInfo & ClassTypeInfo()
virtual Holder Clone() const =0
bool IsSelectedLeader() const
virtual void SyncLockAdjust(double oldT1, double newT1)
TrackNodePointer GetNode() const
Retrieve mNode with debug checks.
virtual bool LinkConsistencyFix(bool doFix=true, bool completeList=true)
Check consistency of channel groups, and maybe fix it.
ChannelGroupData & GetGroupData()
std::shared_ptr< Track > SubstitutePendingChangedTrack()
std::shared_ptr< const Track > SubstituteOriginalTrack() const
std::shared_ptr< TrackList > GetOwner() const
void SetLinkType(LinkType linkType, bool completeList=true)
std::shared_ptr< Subclass > SharedPointer()
bool HasLinkedTrack() const noexcept
Returns true for leaders of multichannel groups.
virtual Holder Duplicate() const
std::shared_ptr< Track > Holder
void SetOwner(const std::weak_ptr< TrackList > &list, TrackNodePointer node)
Update mNode when Track is added to TrackList, or removed from it.
bool LinkConsistencyCheck(bool completeList)
Do the non-mutating part of consistency fix only and return status.
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
void Init(const Track &orig)
virtual ConstIntervals GetIntervals() const
Report times on the track where important intervals begin and end, for UI to snap to.
virtual ChannelType GetChannel() const
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
std::weak_ptr< TrackList > mList
virtual double GetOffset() const =0
TrackNodePointer mNode
Holds iterator to self, so that TrackList::Find can be constant-time.
virtual double GetEndTime() const =0
std::vector< Interval > Intervals
Track * GetLinkedTrack() const
ChannelGroupData & MakeGroupData()
LinkType
For two tracks describes the type of the linkage.
LinkType GetLinkType() const noexcept
int mIndex
0-based position of this track in its TrackList
bool IsAlignedWithLeader() const
Returns true if the leader track has link type LinkType::Aligned.
void DoSetLinkType(LinkType linkType, bool completeList=true)
std::unique_ptr< ChannelGroupData > mpGroupData
std::vector< ConstInterval > ConstIntervals
void SetName(const wxString &n)
TrackId mId
Identifies the track only in-session, not persistently.
An in-session identifier of track objects across undo states. It does not persist between sessions.
Iterator over only members of a TrackList of the specified subtype, optionally filtered by a predicat...
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
void PermutationEvent(TrackNodePointer node)
void RegisterPendingNewTrack(const std::shared_ptr< Track > &pTrack)
bool CanMoveUp(Track *t) const
bool MakeMultiChannelTrack(Track &first, int nChannels, bool aligned)
Converts channels to a multichannel track.
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
double GetEndTime() const
bool CanMoveDown(Track *t) const
std::vector< Updater > mUpdaters
This is in correspondence with mPendingUpdates.
static TrackList * FindUndoTracks(const UndoStackElem &state)
double GetMinOffset() const
void ResizingEvent(TrackNodePointer node)
TrackNodePointer getBegin() const
ListOfTracks::value_type Replace(Track *t, const ListOfTracks::value_type &with)
wxString MakeUniqueTrackName(const wxString &baseTrackName) const
Returns string that contains baseTrackName, but is guaranteed to be unique among other tracks in that...
TrackList & operator=(const TrackList &)=delete
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
double GetStartTime() const
bool isNull(TrackNodePointer p) const
TrackNodePointer getNext(TrackNodePointer p) const
Move an iterator to the next node, if any; else stay at end.
void Swap(TrackList &that)
void AdditionEvent(TrackNodePointer node)
void RecalcPositions(TrackNodePointer node)
auto Find(Track *pTrack) -> TrackIter< TrackType >
Turn a pointer into a TrackIter (constant time); get end iterator if this does not own the track.
auto Any() -> TrackIterRange< TrackType >
TrackNodePointer getEnd() const
bool ApplyPendingTracks()
std::function< void(Track &dest, const Track &src) > Updater
bool Contains(const Track *t) const
Mainly a test function. Uses a linear search, so could be slow.
TrackIterRange< Track > EmptyRange() const
void EnsureVisibleEvent(const std::shared_ptr< Track > &pTrack, bool modifyState)
void DataEvent(const std::shared_ptr< Track > &pTrack, int code)
static TrackList & Get(AudacityProject &project)
Track * DoAdd(const std::shared_ptr< Track > &t)
TrackNodePointer Remove(Track *t)
Remove the Track and return an iterator to what followed it.
static bool SwapChannels(Track &track)
If the given track is one of a pair of channels, swap them.
Track * GetNext(Track *t, bool linked=false) const
Return a track in the list that comes after Track t.
Track * GetPrev(Track *t, bool linked=false) const
std::shared_ptr< Track > RegisterPendingChangedTrack(Updater updater, Track *src)
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
void UpdatePendingTracks()
Track * DoAddToHead(const std::shared_ptr< Track > &t)
Track * FindById(TrackId id)
void Permute(const std::vector< TrackNodePointer > &permutation)
For use in sorting: assume each iterator points into this list, no duplications.
TrackIter< Track > FindLeader(Track *pTrack)
void QueueEvent(TrackListEvent event)
void SwapNodes(TrackNodePointer s1, TrackNodePointer s2)
TrackList(const TrackList &that)=delete
void UnlinkChannels(Track &track)
Removes linkage if track belongs to a group.
bool HasPendingTracks() const
void Clear(bool sendEvent=true)
Make the list empty.
void DeletionEvent(std::weak_ptr< Track > node, bool duringReplace)
void SelectionEvent(const std::shared_ptr< Track > &pTrack)
TrackNodePointer getPrev(TrackNodePointer p) const
Move an iterator to the previous node, if any; else wrap to end.
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
ListOfTracks mPendingUpdates
Shadow tracks holding append-recording in progress; need to put them into a list so that GetLink() wo...
Base class for extra information attached to undo/redo states.
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...
void WriteAttr(const wxString &name, const Identifier &value)
PROJECT_FILE_IO_API wxString Find(const FilePath &path)
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
std::optional< LogWindowUpdater > pUpdater
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
double Accumulate(const TrackList &list, double(Track::*memfn)() const, double ident, const double &(*combine)(const double &, const double &))
UndoRedoExtensionRegistry::Entry sEntry
Empty argument passed to some public constructors.
virtual ~TrackIntervalData()
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
@ RESIZING
Posted when some track changed its height.
@ SELECTION_CHANGE
Posted when the set of selected tracks changes.
@ DELETION
Posted when a track has been deleted from a tracklist. Also posted when one track replaces another.
@ ADDITION
Posted when a track has been added to a tracklist. Also posted when one track replaces another.
@ PERMUTED
Posted when tracks are reordered but otherwise unchanged.
@ TRACK_REQUEST_VISIBLE
Posted when a track needs to be scrolled into view.
@ TRACK_DATA_CHANGE
Posted when certain fields of a track change.
Typically statically constructed.
Holds one item with description and time range for the UndoManager.
void RestoreUndoRedoState(AudacityProject &project) override
Modify the project when undoing or redoing to some state in history.
const std::shared_ptr< TrackList > mpTracks
TrackListRestorer(AudacityProject &project)
bool CanUndoOrRedo(const AudacityProject &project) override
Whether undo or redo is now permitted; default returns true.