1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-06 23:29:24 +02:00

WaveTrack.cpp does not depend on ODManager.cpp ...

... Breaking up an s.c.c. of 6 into 3 components:
ODManager, ODTask, ODWaveTrackTaskQueue
UndoManager
WaveClip, WaveTrack

Rewrite the OD tasks and queues to hold weak pointers to tracks, so the
track destructor need not notify them.
This commit is contained in:
Paul Licameli 2019-06-05 11:46:07 -04:00
parent 71250b1dc3
commit 86320838de
16 changed files with 101 additions and 120 deletions

View File

@ -210,7 +210,7 @@ void ProjectFileManager::EnqueueODTasks()
//add the track to the already created tasks that correspond to the od flags in the wavetrack. //add the track to the already created tasks that correspond to the od flags in the wavetrack.
for(unsigned int i=0;i<newTasks.size();i++) { for(unsigned int i=0;i<newTasks.size();i++) {
if(newTasks[i]->GetODType() & odFlags) if(newTasks[i]->GetODType() & odFlags)
newTasks[i]->AddWaveTrack(wt); newTasks[i]->AddWaveTrack(wt->SharedPointer< WaveTrack >());
} }
//create whatever NEW tasks we need to. //create whatever NEW tasks we need to.
@ -236,7 +236,7 @@ void ProjectFileManager::EnqueueODTasks()
} }
if(newTask) if(newTask)
{ {
newTask->AddWaveTrack(wt); newTask->AddWaveTrack(wt->SharedPointer< WaveTrack >());
newTasks.push_back(std::move(newTask)); newTasks.push_back(std::move(newTask));
} }
} }

View File

@ -17,6 +17,7 @@ Paul Licameli split from ProjectManager.cpp
#include "Track.h" #include "Track.h"
#include "UndoManager.h" #include "UndoManager.h"
#include "ViewInfo.h" #include "ViewInfo.h"
#include "WaveTrack.h"
#include "ondemand/ODComputeSummaryTask.h" #include "ondemand/ODComputeSummaryTask.h"
#include "ondemand/ODManager.h" #include "ondemand/ODManager.h"
@ -167,7 +168,7 @@ void ProjectHistory::PopState(const UndoState &state)
// PRL: Is it correct to add all tracks to one task, even if they // PRL: Is it correct to add all tracks to one task, even if they
// are not partnered channels? Rather than // are not partnered channels? Rather than
// make one task for each? // make one task for each?
computeTask->AddWaveTrack(wt); computeTask->AddWaveTrack(wt->SharedPointer< WaveTrack >());
} }
}); });
} }

View File

@ -53,8 +53,6 @@ Track classes.
#include "Prefs.h" #include "Prefs.h"
#include "ondemand/ODManager.h"
#include "effects/TimeWarper.h" #include "effects/TimeWarper.h"
#include "prefs/SpectrogramSettings.h" #include "prefs/SpectrogramSettings.h"
#include "prefs/TracksPrefs.h" #include "prefs/TracksPrefs.h"
@ -213,10 +211,6 @@ void WaveTrack::Merge(const Track &orig)
WaveTrack::~WaveTrack() WaveTrack::~WaveTrack()
{ {
//Let the ODManager know this WaveTrack is disappearing.
//Deschedules tasks associated with this track.
if(ODManager::IsInstanceCreated())
ODManager::Instance()->RemoveWaveTrack(this);
} }
double WaveTrack::GetOffset() const double WaveTrack::GetOffset() const

View File

@ -2256,7 +2256,7 @@ void Effect::ReplaceProcessedTracks(const bool bGoodResult)
// Swap the wavecache track the ondemand task uses, since now the NEW // Swap the wavecache track the ondemand task uses, since now the NEW
// one will be kept in the project // one will be kept in the project
if (ODManager::IsInstanceCreated()) { if (ODManager::IsInstanceCreated()) {
ODManager::Instance()->ReplaceWaveTrack( t, o.get() ); ODManager::Instance()->ReplaceWaveTrack( t, o );
} }
} }
} }

View File

@ -588,7 +588,7 @@ ProgressResult FFmpegImportFileHandle::Import(TrackFactory *trackFactory,
//for each wavetrack within the stream add coded blockfiles //for each wavetrack within the stream add coded blockfiles
for (int c = 0; c < sc->m_stream->codec->channels; c++) { for (int c = 0; c < sc->m_stream->codec->channels; c++) {
WaveTrack *t = stream[c].get(); auto t = stream[c];
odTask->AddWaveTrack(t); odTask->AddWaveTrack(t);
auto maxBlockSize = t->GetMaxBlockSize(); auto maxBlockSize = t->GetMaxBlockSize();

View File

@ -505,7 +505,7 @@ ProgressResult FLACImportFileHandle::Import(TrackFactory *trackFactory,
bool moreThanStereo = mNumChannels>2; bool moreThanStereo = mNumChannels>2;
for (const auto &channel : mChannels) for (const auto &channel : mChannels)
{ {
mDecoderTask->AddWaveTrack(channel.get()); mDecoderTask->AddWaveTrack(channel);
if(moreThanStereo) if(moreThanStereo)
{ {
//if we have 3 more channels, they get imported on seperate tracks, so we add individual tasks for each. //if we have 3 more channels, they get imported on seperate tracks, so we add individual tasks for each.

View File

@ -445,7 +445,7 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
bool moreThanStereo = mInfo.channels>2; bool moreThanStereo = mInfo.channels>2;
for (const auto &channel : channels) for (const auto &channel : channels)
{ {
computeTask->AddWaveTrack(channel.get()); computeTask->AddWaveTrack(channel);
if(moreThanStereo) if(moreThanStereo)
{ {
//if we have 3 more channels, they get imported on seperate tracks, so we add individual tasks for each. //if we have 3 more channels, they get imported on seperate tracks, so we add individual tasks for each.

View File

@ -116,8 +116,9 @@ void ODComputeSummaryTask::DoSomeInternal()
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(success && mWaveTracks[i]) auto waveTrack = mWaveTracks[i].lock();
mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample); if(success && waveTrack)
waveTrack->AddInvalidRegion(blockStartSample,blockEndSample);
} }
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();
} }
@ -182,13 +183,14 @@ void ODComputeSummaryTask::Update()
for(size_t j=0;j<mWaveTracks.size();j++) for(size_t j=0;j<mWaveTracks.size();j++)
{ {
if(mWaveTracks[j]) auto waveTrack = mWaveTracks[j].lock();
if(waveTrack)
{ {
BlockArray *blocks; BlockArray *blocks;
Sequence *seq; Sequence *seq;
//gather all the blockfiles that we should process in the wavetrack. //gather all the blockfiles that we should process in the wavetrack.
for (const auto &clip : mWaveTracks[j]->GetAllClips()) { for (const auto &clip : waveTrack->GetAllClips()) {
seq = clip->GetSequence(); seq = clip->GetSequence();
//This lock may be way too big since the whole file is one sequence. //This lock may be way too big since the whole file is one sequence.
//TODO: test for large files and find a way to break it down. //TODO: test for large files and find a way to break it down.

View File

@ -102,8 +102,9 @@ void ODDecodeTask::DoSomeInternal()
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(mWaveTracks[i]) auto waveTrack = mWaveTracks[i].lock();
mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample); if(waveTrack)
waveTrack->AddInvalidRegion(blockStartSample,blockEndSample);
} }
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();
} }
@ -138,13 +139,14 @@ void ODDecodeTask::Update()
for(size_t j=0;j<mWaveTracks.size();j++) for(size_t j=0;j<mWaveTracks.size();j++)
{ {
if(mWaveTracks[j]) auto waveTrack = mWaveTracks[j].lock();
if(waveTrack)
{ {
BlockArray *blocks; BlockArray *blocks;
Sequence *seq; Sequence *seq;
//gather all the blockfiles that we should process in the wavetrack. //gather all the blockfiles that we should process in the wavetrack.
for (const auto &clip : mWaveTracks[j]->GetAllClips()) { for (const auto &clip : waveTrack->GetAllClips()) {
seq = clip->GetSequence(); seq = clip->GetSequence();
//TODO:this lock is way to big since the whole file is one sequence. find a way to break it down. //TODO:this lock is way to big since the whole file is one sequence. find a way to break it down.
seq->LockDeleteUpdateMutex(); seq->LockDeleteUpdateMutex();

View File

@ -257,7 +257,7 @@ void ODManager::AddNewTask(std::unique_ptr<ODTask> &&mtask, bool lockMutex)
{ {
//search for a task containing the lead track. wavetrack removal is threadsafe and bound to the mQueuesMutex //search for a task containing the lead track. wavetrack removal is threadsafe and bound to the mQueuesMutex
//note that GetWaveTrack is not threadsafe, but we are assuming task is not running on a different thread yet. //note that GetWaveTrack is not threadsafe, but we are assuming task is not running on a different thread yet.
if(mQueues[i]->ContainsWaveTrack(task->GetWaveTrack(0))) if(mQueues[i]->ContainsWaveTrack(task->GetWaveTrack(0).get()))
queue = mQueues[i].get(); queue = mQueues[i].get();
} }
@ -472,20 +472,9 @@ void ODManager::Quit()
} }
} }
///removes a wavetrack and notifies its associated tasks to stop using its reference.
void ODManager::RemoveWaveTrack(WaveTrack* track)
{
mQueuesMutex.Lock();
for(unsigned int i=0;i<mQueues.size();i++)
{
if(mQueues[i]->ContainsWaveTrack(track))
mQueues[i]->RemoveWaveTrack(track);
}
mQueuesMutex.Unlock();
}
///replace the wavetrack whose wavecache the gui watches for updates ///replace the wavetrack whose wavecache the gui watches for updates
void ODManager::ReplaceWaveTrack(Track *oldTrack, Track *newTrack) void ODManager::ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr<Track> &newTrack)
{ {
mQueuesMutex.Lock(); mQueuesMutex.Lock();
for(unsigned int i=0;i<mQueues.size();i++) for(unsigned int i=0;i<mQueues.size();i++)
@ -496,13 +485,14 @@ void ODManager::ReplaceWaveTrack(Track *oldTrack, Track *newTrack)
} }
///if it shares a queue/task, creates a NEW queue/task for the track, and removes it from any previously existing tasks. ///if it shares a queue/task, creates a NEW queue/task for the track, and removes it from any previously existing tasks.
void ODManager::MakeWaveTrackIndependent(WaveTrack* track) void ODManager::MakeWaveTrackIndependent(
const std::shared_ptr< WaveTrack > &track)
{ {
ODWaveTrackTaskQueue* owner=NULL; ODWaveTrackTaskQueue* owner=NULL;
mQueuesMutex.Lock(); mQueuesMutex.Lock();
for(unsigned int i=0;i<mQueues.size();i++) for(unsigned int i=0;i<mQueues.size();i++)
{ {
if(mQueues[i]->ContainsWaveTrack(track)) if(mQueues[i]->ContainsWaveTrack(track.get()))
{ {
owner = mQueues[i].get(); owner = mQueues[i].get();
break; break;
@ -519,7 +509,10 @@ void ODManager::MakeWaveTrackIndependent(WaveTrack* track)
///better design in the future. ///better design in the future.
///@return returns success. Some ODTask conditions require that the tasks finish before merging. ///@return returns success. Some ODTask conditions require that the tasks finish before merging.
///e.g. they have different effects being processed at the same time. ///e.g. they have different effects being processed at the same time.
bool ODManager::MakeWaveTrackDependent(WaveTrack* dependentTrack,WaveTrack* masterTrack) bool ODManager::MakeWaveTrackDependent(
const std::shared_ptr< WaveTrack > &dependentTrack,
WaveTrack* masterTrack
)
{ {
//First, check to see if the task lists are mergeable. If so, we can simply add this track to the other task and queue, //First, check to see if the task lists are mergeable. If so, we can simply add this track to the other task and queue,
//then DELETE this one. //then DELETE this one.
@ -535,7 +528,7 @@ bool ODManager::MakeWaveTrackDependent(WaveTrack* dependentTrack,WaveTrack* mast
{ {
masterQueue = mQueues[i].get(); masterQueue = mQueues[i].get();
} }
else if(mQueues[i]->ContainsWaveTrack(dependentTrack)) else if(mQueues[i]->ContainsWaveTrack(dependentTrack.get()))
{ {
dependentQueue = mQueues[i].get(); dependentQueue = mQueues[i].get();
dependentIndex = i; dependentIndex = i;

View File

@ -67,19 +67,20 @@ class ODManager final
///Wakes the queue loop up by signalling its condition variable. ///Wakes the queue loop up by signalling its condition variable.
void SignalTaskQueueLoop(); void SignalTaskQueueLoop();
///removes a wavetrack and notifies its associated tasks to stop using its reference.
void RemoveWaveTrack(WaveTrack* track);
///if it shares a queue/task, creates a NEW queue/task for the track, and removes it from any previously existing tasks. ///if it shares a queue/task, creates a NEW queue/task for the track, and removes it from any previously existing tasks.
void MakeWaveTrackIndependent(WaveTrack* track); void MakeWaveTrackIndependent( const std::shared_ptr< WaveTrack > &track);
///attach the track in question to another, already existing track's queues and tasks. Remove the task/tracks. ///attach the track in question to another, already existing track's queues and tasks. Remove the task/tracks.
///Returns success if it was possible.. Some ODTask conditions make it impossible until the Tasks finish. ///Returns success if it was possible.. Some ODTask conditions make it impossible until the Tasks finish.
bool MakeWaveTrackDependent(WaveTrack* dependentTrack,WaveTrack* masterTrack); bool MakeWaveTrackDependent(
const std::shared_ptr< WaveTrack > &dependentTrack,
WaveTrack* masterTrack
);
///if oldTrack is being watched, ///if oldTrack is being watched,
///replace the wavetrack whose wavecache the gui watches for updates ///replace the wavetrack whose wavecache the gui watches for updates
void ReplaceWaveTrack(Track *oldTrack, Track *newTrack); void ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr< Track > &newTrack);
///Adds a task to the running queue. Threas-safe. ///Adds a task to the running queue. Threas-safe.
void AddTask(ODTask* task); void AddTask(ODTask* task);

View File

@ -182,7 +182,7 @@ bool ODTask::IsTaskAssociatedWithProject(AudacityProject* proj)
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(int i=0;i<(int)mWaveTracks.size();i++) for(int i=0;i<(int)mWaveTracks.size();i++)
{ {
if(mWaveTracks[i]==tr) if ( mWaveTracks[i].lock().get() == tr )
{ {
//if we find one, then the project is associated with us;return true //if we find one, then the project is associated with us;return true
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();
@ -252,19 +252,19 @@ bool ODTask::IsComplete()
} }
WaveTrack* ODTask::GetWaveTrack(int i) std::shared_ptr< WaveTrack > ODTask::GetWaveTrack(int i)
{ {
WaveTrack* track = NULL; std::shared_ptr< WaveTrack > track;
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
if(i<(int)mWaveTracks.size()) if(i<(int)mWaveTracks.size())
track = mWaveTracks[i]; track = mWaveTracks[i].lock();
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();
return track; return track;
} }
///Sets the wavetrack that will be analyzed for ODPCMAliasBlockFiles that will ///Sets the wavetrack that will be analyzed for ODPCMAliasBlockFiles that will
///have their summaries computed and written to disk. ///have their summaries computed and written to disk.
void ODTask::AddWaveTrack(WaveTrack* track) void ODTask::AddWaveTrack( const std::shared_ptr< WaveTrack > &track)
{ {
mWaveTracks.push_back(track); mWaveTracks.push_back(track);
} }
@ -321,7 +321,7 @@ void ODTask::DemandTrackUpdate(WaveTrack* track, double seconds)
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(track == mWaveTracks[i]) if ( track == mWaveTracks[i].lock().get() )
{ {
auto newDemandSample = (sampleCount)(seconds * track->GetRate()); auto newDemandSample = (sampleCount)(seconds * track->GetRate());
demandSampleChanged = newDemandSample != GetDemandSample(); demandSampleChanged = newDemandSample != GetDemandSample();
@ -342,21 +342,22 @@ void ODTask::StopUsingWaveTrack(WaveTrack* track)
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(mWaveTracks[i] == track) if(mWaveTracks[i].lock().get() == track)
mWaveTracks[i]=NULL; mWaveTracks[i].reset();
} }
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();
} }
///Replaces all instances to a wavetrack with a NEW one, effectively transferring the task. ///Replaces all instances to a wavetrack with a NEW one, effectively transferring the task.
void ODTask::ReplaceWaveTrack(Track *oldTrack, Track *newTrack) void ODTask::ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr< Track > &newTrack)
{ {
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(oldTrack == mWaveTracks[i]) if(oldTrack == mWaveTracks[i].lock().get())
{ {
mWaveTracks[i] = static_cast<WaveTrack*>( newTrack ); mWaveTracks[i] = std::static_pointer_cast<WaveTrack>( newTrack );
} }
} }
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();

View File

@ -84,12 +84,13 @@ class ODTask /* not final */
///Replaces all instances to a wavetrack with a NEW one, effectively transferring the task. ///Replaces all instances to a wavetrack with a NEW one, effectively transferring the task.
///ODTask has no wavetrack, so it does nothing. But subclasses that do should override this. ///ODTask has no wavetrack, so it does nothing. But subclasses that do should override this.
virtual void ReplaceWaveTrack(Track *oldTrack, Track *newTrack); virtual void ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr< Track > &newTrack);
///Adds a WaveTrack to do the task for ///Adds a WaveTrack to do the task for
void AddWaveTrack(WaveTrack* track); void AddWaveTrack( const std::shared_ptr< WaveTrack > &track);
virtual int GetNumWaveTracks(); virtual int GetNumWaveTracks();
virtual WaveTrack* GetWaveTrack(int i); virtual std::shared_ptr< WaveTrack > GetWaveTrack(int i);
///changes the tasks associated with this Waveform to process the task from a different point in the track ///changes the tasks associated with this Waveform to process the task from a different point in the track
virtual void DemandTrackUpdate(WaveTrack* track, double seconds); virtual void DemandTrackUpdate(WaveTrack* track, double seconds);
@ -156,7 +157,7 @@ class ODTask /* not final */
//for a function not a member var. //for a function not a member var.
ODLock mBlockUntilTerminateMutex; ODLock mBlockUntilTerminateMutex;
std::vector<WaveTrack*> mWaveTracks; std::vector< std::weak_ptr< WaveTrack > > mWaveTracks;
ODLock mWaveTrackMutex; ODLock mWaveTrackMutex;
sampleCount mDemandSample; sampleCount mDemandSample;

View File

@ -64,7 +64,8 @@ bool ODWaveTrackTaskQueue::CanMergeWith(ODWaveTrackTaskQueue* otherQueue)
/// sets the NeedODUpdateFlag since we don't want the head task to finish without haven't dealt with the depednent /// sets the NeedODUpdateFlag since we don't want the head task to finish without haven't dealt with the depednent
/// ///
///@param track the track to bring into the tasks AND tracklist for this queue ///@param track the track to bring into the tasks AND tracklist for this queue
void ODWaveTrackTaskQueue::MergeWaveTrack(WaveTrack* track) void ODWaveTrackTaskQueue::MergeWaveTrack(
const std::shared_ptr< WaveTrack > &track)
{ {
AddWaveTrack(track); AddWaveTrack(track);
mTasksMutex.Lock(); mTasksMutex.Lock();
@ -83,7 +84,7 @@ bool ODWaveTrackTaskQueue::ContainsWaveTrack(const WaveTrack* track)
mTracksMutex.Lock(); mTracksMutex.Lock();
for(unsigned int i=0;i<mTracks.size();i++) for(unsigned int i=0;i<mTracks.size();i++)
{ {
if(mTracks[i]==track) if ( mTracks[i].lock().get() == track )
{ {
mTracksMutex.Unlock(); mTracksMutex.Unlock();
return true; return true;
@ -93,7 +94,8 @@ bool ODWaveTrackTaskQueue::ContainsWaveTrack(const WaveTrack* track)
return false; return false;
} }
///Adds a track to the associated list. ///Adds a track to the associated list.
void ODWaveTrackTaskQueue::AddWaveTrack(WaveTrack* track) void ODWaveTrackTaskQueue::AddWaveTrack(
const std::shared_ptr< WaveTrack > &track)
{ {
mTracksMutex.Lock(); mTracksMutex.Lock();
@ -117,8 +119,7 @@ void ODWaveTrackTaskQueue::AddTask(std::unique_ptr<ODTask> &&mtask)
{ {
//task->GetWaveTrack(i) may return NULL, but we handle it by checking before using. //task->GetWaveTrack(i) may return NULL, but we handle it by checking before using.
//The other worry that the WaveTrack returned and was deleted in the meantime is also //The other worry that the WaveTrack returned and was deleted in the meantime is also
//handled since mQueuesMutex is locked one up in the stack from here, //handled by keeping standard weak pointers to tracks, which give thread safety.
//and WaveTrack deletion is bound to that.
mTracks.push_back(task->GetWaveTrack(i)); mTracks.push_back(task->GetWaveTrack(i));
} }
@ -126,32 +127,15 @@ void ODWaveTrackTaskQueue::AddTask(std::unique_ptr<ODTask> &&mtask)
} }
///Removes a track from the list. Also notifies mTasks to stop using references
///to the instance in a thread-safe manner (may block)
void ODWaveTrackTaskQueue::RemoveWaveTrack(WaveTrack* track)
{
if(track)
{
mTasksMutex.Lock();
for(unsigned int i=0;i<mTasks.size();i++)
mTasks[i]->StopUsingWaveTrack(track);
mTasksMutex.Unlock();
mTracksMutex.Lock();
for(unsigned int i=0;i<mTracks.size();i++)
if(mTracks[i]==track)
mTracks.erase(mTracks.begin()+i--);//decrement i after the removal.
mTracksMutex.Unlock();
}
}
//if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it. //if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it.
void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track) void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(
const std::shared_ptr< WaveTrack > &track)
{ {
// First remove expired weak pointers
Compress();
mTracksMutex.Lock(); mTracksMutex.Lock();
if(mTracks.size()<2) if(mTracks.size()<2)
{ {
//if there is only one track, it is already independent. //if there is only one track, it is already independent.
@ -161,17 +145,16 @@ void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track)
for(unsigned int i=0;i<mTracks.size();i++) for(unsigned int i=0;i<mTracks.size();i++)
{ {
if(mTracks[i]==track) if ( mTracks[i].lock() == track )
{ {
mTracksMutex.Unlock();//release the lock, since RemoveWaveTrack is a public threadsafe method. mTracks[i].reset();
RemoveWaveTrack(mTracks[i]);
//clone the items in order and add them to the ODManager. //clone the items in order and add them to the ODManager.
mTasksMutex.Lock(); mTasksMutex.Lock();
for(unsigned int j=0;j<mTasks.size();j++) for(unsigned int j=0;j<mTasks.size();j++)
{ {
auto task = mTasks[j]->Clone(); auto task = mTasks[j]->Clone();
task->AddWaveTrack(track); mTasks[j]->StopUsingWaveTrack( track.get() );
//AddNewTask requires us to relinquish this lock. However, it is safe because ODManager::MakeWaveTrackIndependent //AddNewTask requires us to relinquish this lock. However, it is safe because ODManager::MakeWaveTrackIndependent
//has already locked the m_queuesMutex. //has already locked the m_queuesMutex.
mTasksMutex.Unlock(); mTasksMutex.Unlock();
@ -181,7 +164,6 @@ void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track)
mTasksMutex.Lock(); mTasksMutex.Lock();
} }
mTasksMutex.Unlock(); mTasksMutex.Unlock();
mTracksMutex.Lock();
break; break;
} }
} }
@ -207,7 +189,8 @@ void ODWaveTrackTaskQueue::DemandTrackUpdate(WaveTrack* track, double seconds)
//Replaces all instances of a wavetracck with a NEW one (effectively transferes the task.) //Replaces all instances of a wavetracck with a NEW one (effectively transferes the task.)
void ODWaveTrackTaskQueue::ReplaceWaveTrack(Track *oldTrack, Track *newTrack) void ODWaveTrackTaskQueue::ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr<Track> &newTrack)
{ {
if(oldTrack) if(oldTrack)
{ {
@ -218,26 +201,17 @@ void ODWaveTrackTaskQueue::ReplaceWaveTrack(Track *oldTrack, Track *newTrack)
mTracksMutex.Lock(); mTracksMutex.Lock();
for(unsigned int i=0;i<mTracks.size();i++) for(unsigned int i=0;i<mTracks.size();i++)
if(mTracks[i]==oldTrack) if ( mTracks[i].lock().get() == oldTrack )
mTracks[i] = static_cast<WaveTrack*>( newTrack ); mTracks[i] = std::static_pointer_cast<WaveTrack>( newTrack );
mTracksMutex.Unlock(); mTracksMutex.Unlock();
} }
} }
//returns the wavetrack at position x.
WaveTrack* ODWaveTrackTaskQueue::GetWaveTrack(size_t x)
{
WaveTrack* ret = NULL;
mTracksMutex.Lock();
if (x < mTracks.size())
ret = mTracks[x];
mTracksMutex.Unlock();
return ret;
}
///returns the number of wavetracks in this queue. ///returns the number of wavetracks in this queue.
int ODWaveTrackTaskQueue::GetNumWaveTracks() int ODWaveTrackTaskQueue::GetNumWaveTracks()
{ {
Compress();
int ret = 0; int ret = 0;
mTracksMutex.Lock(); mTracksMutex.Lock();
ret=mTracks.size(); ret=mTracks.size();
@ -271,6 +245,8 @@ ODTask* ODWaveTrackTaskQueue::GetTask(size_t x)
//returns true if either tracks or tasks are empty //returns true if either tracks or tasks are empty
bool ODWaveTrackTaskQueue::IsEmpty() bool ODWaveTrackTaskQueue::IsEmpty()
{ {
Compress();
bool isEmpty; bool isEmpty;
mTracksMutex.Lock(); mTracksMutex.Lock();
isEmpty = mTracks.size()<=0; isEmpty = mTracks.size()<=0;
@ -342,3 +318,13 @@ void ODWaveTrackTaskQueue::FillTipForWaveTrack( const WaveTrack * t, wxString &t
} }
} }
void ODWaveTrackTaskQueue::Compress()
{
mTracksMutex.Lock();
auto begin = mTracks.begin(), end = mTracks.end(),
new_end = std::remove_if( begin, end,
[]( const std::weak_ptr<WaveTrack> &ptr ){ return ptr.expired(); } );
mTracks.erase( new_end, end );
mTracksMutex.Unlock();
}

View File

@ -42,31 +42,26 @@ class ODWaveTrackTaskQueue final
///Adds a track to the associated list. ///Adds a track to the associated list.
void AddWaveTrack(WaveTrack* track); void AddWaveTrack( const std::shared_ptr< WaveTrack > &track);
///Removes a track from the list. Also notifies mTasks to stop using references
///to the instance in a thread-safe manner (may block)
void RemoveWaveTrack(WaveTrack* track);
///changes the tasks associated with this Waveform to process the task from a different point in the track ///changes the tasks associated with this Waveform to process the task from a different point in the track
void DemandTrackUpdate(WaveTrack* track, double seconds); void DemandTrackUpdate(WaveTrack* track, double seconds);
///replaces all instances of a WaveTrack within this task with another. ///replaces all instances of a WaveTrack within this task with another.
void ReplaceWaveTrack(Track *oldTrack, Track *newTrack); void ReplaceWaveTrack(Track *oldTrack,
const std::shared_ptr<Track> &newTrack);
//if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it. //if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it.
void MakeWaveTrackIndependent(WaveTrack* track); void MakeWaveTrackIndependent( const std::shared_ptr< WaveTrack > &track);
///returns whether or not this queue's task list and another's can merge together, as when we make two mono tracks stereo. ///returns whether or not this queue's task list and another's can merge together, as when we make two mono tracks stereo.
bool CanMergeWith(ODWaveTrackTaskQueue* otherQueue); bool CanMergeWith(ODWaveTrackTaskQueue* otherQueue);
void MergeWaveTrack(WaveTrack* track); void MergeWaveTrack( const std::shared_ptr< WaveTrack > &track);
//returns true if the agrument is in the WaveTrack list. //returns true if the agrument is in the WaveTrack list.
bool ContainsWaveTrack(const WaveTrack* track); bool ContainsWaveTrack(const WaveTrack* track);
//returns the wavetrack at position x.
WaveTrack* GetWaveTrack(size_t x);
///returns the number of wavetracks in this queue. ///returns the number of wavetracks in this queue.
int GetNumWaveTracks(); int GetNumWaveTracks();
@ -96,12 +91,15 @@ class ODWaveTrackTaskQueue final
protected: protected:
// Remove expired weak pointers to tracks
void Compress();
//because we need to save this around for the tool tip. //because we need to save this around for the tool tip.
wxString mTipMsg; wxString mTipMsg;
///the list of tracks associated with this queue. ///the list of tracks associated with this queue.
std::vector<WaveTrack*> mTracks; std::vector< std::weak_ptr< WaveTrack > > mTracks;
ODLock mTracksMutex; ODLock mTracksMutex;
///the list of tasks associated with the tracks. This class owns these tasks. ///the list of tasks associated with the tracks. This class owns these tasks.

View File

@ -889,7 +889,8 @@ void WaveTrackMenuTable::OnMergeStereo(wxCommandEvent &)
//On Demand - join the queues together. //On Demand - join the queues together.
if (ODManager::IsInstanceCreated()) if (ODManager::IsInstanceCreated())
if (!ODManager::Instance()->MakeWaveTrackDependent(partner, pTrack)) if (!ODManager::Instance()
->MakeWaveTrackDependent(partner->SharedPointer<WaveTrack>(), pTrack))
{ {
; ;
//TODO: in the future, we will have to check the return value of MakeWaveTrackDependent - //TODO: in the future, we will have to check the return value of MakeWaveTrackDependent -
@ -927,7 +928,8 @@ void WaveTrackMenuTable::SplitStereo(bool stereo)
//On Demand - have each channel add its own. //On Demand - have each channel add its own.
if (ODManager::IsInstanceCreated()) if (ODManager::IsInstanceCreated())
ODManager::Instance()->MakeWaveTrackIndependent(channel); ODManager::Instance()->MakeWaveTrackIndependent(
channel->SharedPointer<WaveTrack>() );
//make sure no channel is smaller than its minimum height //make sure no channel is smaller than its minimum height
if (view.GetHeight() < view.GetMinimizedHeight()) if (view.GetHeight() < view.GetMinimizedHeight())
view.SetHeight(view.GetMinimizedHeight()); view.SetHeight(view.GetMinimizedHeight());