mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 08:09:32 +02:00
checking in cleanup of on-demand files following james' review. also speeds up od cursor updating when user clicks for on-demand
This commit is contained in:
parent
016c6ce796
commit
5ccce1ed4b
@ -99,6 +99,12 @@ class ODDecodeBlockFile : public SimpleBlockFile
|
|||||||
///Gets the value that indicates where the first sample in this block corresponds to the global sequence/clip. Only for display use.
|
///Gets the value that indicates where the first sample in this block corresponds to the global sequence/clip. Only for display use.
|
||||||
sampleCount GetStart(){return mStart;}
|
sampleCount GetStart(){return mStart;}
|
||||||
|
|
||||||
|
//returns the number of samples from the beginning of the track that this blockfile starts at
|
||||||
|
sampleCount GetGlobalStart(){return mClipOffset+mStart;}
|
||||||
|
|
||||||
|
//returns the number of samples from the beginning of the track that this blockfile ends at
|
||||||
|
sampleCount GetGlobalEnd(){return mClipOffset+mStart+GetLength();}
|
||||||
|
|
||||||
//Below calls are overrided just so we can take wxlog calls out, which are not threadsafe.
|
//Below calls are overrided just so we can take wxlog calls out, which are not threadsafe.
|
||||||
|
|
||||||
/// Reads the specified data from the aliased file using libsndfile
|
/// Reads the specified data from the aliased file using libsndfile
|
||||||
|
@ -110,6 +110,13 @@ class ODPCMAliasBlockFile : public PCMAliasBlockFile
|
|||||||
///Gets the number of samples the clip associated with this blockfile is offset by.
|
///Gets the number of samples the clip associated with this blockfile is offset by.
|
||||||
sampleCount GetClipOffset(){return mClipOffset;}
|
sampleCount GetClipOffset(){return mClipOffset;}
|
||||||
|
|
||||||
|
//returns the number of samples from the beginning of the track that this blockfile starts at
|
||||||
|
sampleCount GetGlobalStart(){return mClipOffset+mStart;}
|
||||||
|
|
||||||
|
//returns the number of samples from the beginning of the track that this blockfile ends at
|
||||||
|
sampleCount GetGlobalEnd(){return mClipOffset+mStart+GetLength();}
|
||||||
|
|
||||||
|
|
||||||
//Below calls are overrided just so we can take wxlog calls out, which are not threadsafe.
|
//Below calls are overrided just so we can take wxlog calls out, which are not threadsafe.
|
||||||
|
|
||||||
/// Reads the specified data from the aliased file using libsndfile
|
/// Reads the specified data from the aliased file using libsndfile
|
||||||
|
@ -102,7 +102,10 @@ void ODComputeSummaryTask::DoSomeInternal()
|
|||||||
//take it out of the array - we are done with it.
|
//take it out of the array - we are done with it.
|
||||||
mBlockFiles.erase(mBlockFiles.begin());
|
mBlockFiles.erase(mBlockFiles.begin());
|
||||||
|
|
||||||
|
//This is a bit of a convenience in case someone tries to terminate the task by closing the trackpanel or window.
|
||||||
|
//ODComputeSummaryTask::Terminate() uses this lock to remove everything, and we don't want it to wait since the UI is being blocked.
|
||||||
mBlockFilesMutex.Unlock();
|
mBlockFilesMutex.Unlock();
|
||||||
|
wxThread::This()->Yield();
|
||||||
mBlockFilesMutex.Lock();
|
mBlockFilesMutex.Lock();
|
||||||
|
|
||||||
|
|
||||||
@ -187,21 +190,22 @@ void ODComputeSummaryTask::Update()
|
|||||||
|
|
||||||
//gather all the blockfiles that we should process in the wavetrack.
|
//gather all the blockfiles that we should process in the wavetrack.
|
||||||
WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();
|
WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();
|
||||||
|
|
||||||
int numBlocksDone;
|
|
||||||
while(node) {
|
while(node) {
|
||||||
clip = node->GetData();
|
clip = node->GetData();
|
||||||
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.
|
//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.
|
||||||
seq->LockDeleteUpdateMutex();
|
seq->LockDeleteUpdateMutex();
|
||||||
|
|
||||||
//See Sequence::Delete() for why need this for now..
|
//See Sequence::Delete() for why need this for now..
|
||||||
|
//We don't need the mBlockFilesMutex here because it is only for the vector list.
|
||||||
|
//These are existing blocks, and its wavetrack or blockfiles won't be deleted because
|
||||||
|
//of the respective mWaveTrackMutex lock and LockDeleteUpdateMutex() call.
|
||||||
blocks = clip->GetSequenceBlockArray();
|
blocks = clip->GetSequenceBlockArray();
|
||||||
int i;
|
int i;
|
||||||
int numBlocksIn;
|
|
||||||
int insertCursor;
|
int insertCursor;
|
||||||
|
|
||||||
numBlocksIn=0;
|
|
||||||
insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
|
insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
|
||||||
|
|
||||||
for(i=0; i<(int)blocks->GetCount(); i++)
|
for(i=0; i<(int)blocks->GetCount(); i++)
|
||||||
@ -219,21 +223,9 @@ void ODComputeSummaryTask::Update()
|
|||||||
(sampleCount)(((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetStart()+((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
|
(sampleCount)(((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetStart()+((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
|
||||||
insertCursor++;
|
insertCursor++;
|
||||||
|
|
||||||
|
|
||||||
tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODPCMAliasBlockFile*)blocks->Item(i)->f);
|
tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODPCMAliasBlockFile*)blocks->Item(i)->f);
|
||||||
|
|
||||||
//this next bit ensures that we are spacing the blockfiles over multiple wavetracks evenly.
|
|
||||||
//if((j+1)*numBlocksIn>tempBlocks.size())
|
|
||||||
// tempBlocks.push_back((ODPCMAliasBlockFile*)blocks->Item(i)->f);
|
|
||||||
// else
|
|
||||||
// tempBlocks.insert(tempBlocks.begin()+(j+1)*numBlocksIn, (ODPCMAliasBlockFile*)blocks->Item(i)->f);
|
|
||||||
//
|
|
||||||
|
|
||||||
numBlocksIn++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
numBlocksDone = numBlocksIn;
|
|
||||||
|
|
||||||
seq->UnlockDeleteUpdateMutex();
|
seq->UnlockDeleteUpdateMutex();
|
||||||
node = node->GetNext();
|
node = node->GetNext();
|
||||||
}
|
}
|
||||||
@ -260,7 +252,8 @@ void ODComputeSummaryTask::OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &un
|
|||||||
mBlockFiles.clear();
|
mBlockFiles.clear();
|
||||||
//TODO:order the blockfiles into our queue in a fancy convenient way. (this could be user-prefs)
|
//TODO:order the blockfiles into our queue in a fancy convenient way. (this could be user-prefs)
|
||||||
//for now just put them in linear. We start the order from the first block that includes the ondemand sample
|
//for now just put them in linear. We start the order from the first block that includes the ondemand sample
|
||||||
//(which the user sets by clicking.) note that this code is pretty hacky - it assumes that the array is sorted in time.
|
//(which the user sets by clicking.)
|
||||||
|
//Note that this code assumes that the array is sorted in time.
|
||||||
|
|
||||||
//find the startpoint
|
//find the startpoint
|
||||||
sampleCount processStartSample = GetDemandSample();
|
sampleCount processStartSample = GetDemandSample();
|
||||||
@ -271,9 +264,12 @@ void ODComputeSummaryTask::OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &un
|
|||||||
//If there isn't, then the block was deleted for some reason and we should ignore it.
|
//If there isn't, then the block was deleted for some reason and we should ignore it.
|
||||||
if(unorderedBlocks[i]->RefCount()>=2)
|
if(unorderedBlocks[i]->RefCount()>=2)
|
||||||
{
|
{
|
||||||
if(mBlockFiles.size() && (unorderedBlocks[i]->GetStart()+unorderedBlocks[i]->GetClipOffset()) + unorderedBlocks[i]->GetLength() >=processStartSample &&
|
//test if the blockfiles are near the task cursor. we use the last mBlockFiles[0] as our point of reference
|
||||||
( (mBlockFiles[0]->GetStart()+mBlockFiles[0]->GetClipOffset()) + mBlockFiles[0]->GetLength() < processStartSample ||
|
//and add ones that are closer.
|
||||||
(unorderedBlocks[i]->GetStart()+unorderedBlocks[i]->GetClipOffset()) <= (mBlockFiles[0]->GetStart() +mBlockFiles[0]->GetClipOffset()))
|
if(mBlockFiles.size() &&
|
||||||
|
unorderedBlocks[i]->GetGlobalEnd() >= processStartSample &&
|
||||||
|
( mBlockFiles[0]->GetGlobalEnd() < processStartSample ||
|
||||||
|
unorderedBlocks[i]->GetGlobalStart() <= mBlockFiles[0]->GetGlobalStart())
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
//insert at the front of the list if we get blockfiles that are after the demand sample
|
//insert at the front of the list if we get blockfiles that are after the demand sample
|
||||||
@ -294,10 +290,4 @@ void ODComputeSummaryTask::OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &un
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ODComputeSummaryTask::ODUpdate()
|
|
||||||
{
|
|
||||||
//clear old blockFiles and do something smarter.
|
|
||||||
|
|
||||||
}
|
|
@ -68,9 +68,6 @@ protected:
|
|||||||
///Then it updates in the OD manner.
|
///Then it updates in the OD manner.
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
|
|
||||||
///Readjusts the blockfile order to start at the new cursor.
|
|
||||||
virtual void ODUpdate();
|
|
||||||
|
|
||||||
///Orders the input as either On-Demand or default layered order.
|
///Orders the input as either On-Demand or default layered order.
|
||||||
void OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &unorderedBlocks);
|
void OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &unorderedBlocks);
|
||||||
|
|
||||||
|
@ -124,8 +124,7 @@ void ODDecodeTask::Update()
|
|||||||
|
|
||||||
//gather all the blockfiles that we should process in the wavetrack.
|
//gather all the blockfiles that we should process in the wavetrack.
|
||||||
WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();
|
WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();
|
||||||
|
|
||||||
int numBlocksDone;
|
|
||||||
while(node) {
|
while(node) {
|
||||||
clip = node->GetData();
|
clip = node->GetData();
|
||||||
seq = clip->GetSequence();
|
seq = clip->GetSequence();
|
||||||
@ -135,11 +134,8 @@ void ODDecodeTask::Update()
|
|||||||
//See Sequence::Delete() for why need this for now..
|
//See Sequence::Delete() for why need this for now..
|
||||||
blocks = clip->GetSequenceBlockArray();
|
blocks = clip->GetSequenceBlockArray();
|
||||||
int i;
|
int i;
|
||||||
int numBlocksIn;
|
|
||||||
int insertCursor;
|
int insertCursor;
|
||||||
|
|
||||||
numBlocksIn=0;
|
|
||||||
|
|
||||||
insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
|
insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
|
||||||
for(i=0; i<(int)blocks->GetCount(); i++)
|
for(i=0; i<(int)blocks->GetCount(); i++)
|
||||||
{
|
{
|
||||||
@ -156,12 +152,9 @@ void ODDecodeTask::Update()
|
|||||||
(sampleCount)(((ODDecodeBlockFile*)blocks->Item(i)->f)->GetStart()+((ODDecodeBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
|
(sampleCount)(((ODDecodeBlockFile*)blocks->Item(i)->f)->GetStart()+((ODDecodeBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
|
||||||
insertCursor++;
|
insertCursor++;
|
||||||
|
|
||||||
|
|
||||||
tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODDecodeBlockFile*)blocks->Item(i)->f);
|
tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODDecodeBlockFile*)blocks->Item(i)->f);
|
||||||
numBlocksIn++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
numBlocksDone = numBlocksIn;
|
|
||||||
|
|
||||||
seq->UnlockDeleteUpdateMutex();
|
seq->UnlockDeleteUpdateMutex();
|
||||||
node = node->GetNext();
|
node = node->GetNext();
|
||||||
@ -196,10 +189,14 @@ void ODDecodeTask::OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlo
|
|||||||
//If there isn't, then the block was deleted for some reason and we should ignore it.
|
//If there isn't, then the block was deleted for some reason and we should ignore it.
|
||||||
if(unorderedBlocks[i]->RefCount()>=2)
|
if(unorderedBlocks[i]->RefCount()>=2)
|
||||||
{
|
{
|
||||||
if(mBlockFiles.size() && (unorderedBlocks[i]->GetStart()+unorderedBlocks[i]->GetClipOffset()) + unorderedBlocks[i]->GetLength() >=processStartSample &&
|
//test if the blockfiles are near the task cursor. we use the last mBlockFiles[0] as our point of reference
|
||||||
( (mBlockFiles[0]->GetStart()+mBlockFiles[0]->GetClipOffset()) + mBlockFiles[0]->GetLength() < processStartSample ||
|
//and add ones that are closer.
|
||||||
(unorderedBlocks[i]->GetStart()+unorderedBlocks[i]->GetClipOffset()) <= (mBlockFiles[0]->GetStart() +mBlockFiles[0]->GetClipOffset()))
|
//since the order is linear right to left, this will add blocks so that the ones on the right side of the target
|
||||||
)
|
//are processed first, with the ones closer being processed earlier. Then the ones on the left side get processed.
|
||||||
|
if(mBlockFiles.size() &&
|
||||||
|
unorderedBlocks[i]->GetGlobalEnd() >= processStartSample &&
|
||||||
|
( mBlockFiles[0]->GetGlobalEnd() < processStartSample ||
|
||||||
|
unorderedBlocks[i]->GetGlobalStart() <= mBlockFiles[0]->GetGlobalStart()) )
|
||||||
{
|
{
|
||||||
//insert at the front of the list if we get blockfiles that are after the demand sample
|
//insert at the front of the list if we get blockfiles that are after the demand sample
|
||||||
mBlockFiles.insert(mBlockFiles.begin()+0,unorderedBlocks[i]);
|
mBlockFiles.insert(mBlockFiles.begin()+0,unorderedBlocks[i]);
|
||||||
@ -221,13 +218,6 @@ void ODDecodeTask::OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ODDecodeTask::ODUpdate()
|
|
||||||
{
|
|
||||||
//clear old blockFiles and do something smarter.
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///there could be the ODBlockFiles of several FLACs in one track (after copy and pasting)
|
///there could be the ODBlockFiles of several FLACs in one track (after copy and pasting)
|
||||||
///so we keep a list of decoders that keep track of the file names, etc, and check the blocks against them.
|
///so we keep a list of decoders that keep track of the file names, etc, and check the blocks against them.
|
||||||
|
@ -80,9 +80,6 @@ protected:
|
|||||||
///Then it updates in the OD manner.
|
///Then it updates in the OD manner.
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
|
|
||||||
///Readjusts the blockfile order to start at the new cursor.
|
|
||||||
virtual void ODUpdate();
|
|
||||||
|
|
||||||
///Orders the input as either On-Demand or default layered order.
|
///Orders the input as either On-Demand or default layered order.
|
||||||
void OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlocks);
|
void OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlocks);
|
||||||
|
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
/*
|
/**********************************************************************
|
||||||
* ODManager.cpp
|
|
||||||
* Audacity
|
Audacity - A Digital Audio Editor
|
||||||
*
|
Copyright 1999-2010 Audacity Team
|
||||||
* Created by apple on 6/8/08.
|
File License: wxWidgets
|
||||||
* Copyright 2008 __MyCompanyName__. All rights reserved.
|
|
||||||
*
|
Michael Chinen
|
||||||
*/
|
|
||||||
|
******************************************************************//**
|
||||||
|
|
||||||
|
\file ODManager.cpp
|
||||||
|
\brief Singleton ODManager class. Is the bridge between client side
|
||||||
|
ODTask requests and internals.
|
||||||
|
|
||||||
|
*//*******************************************************************/
|
||||||
|
|
||||||
#include "ODManager.h"
|
#include "ODManager.h"
|
||||||
#include "ODTask.h"
|
#include "ODTask.h"
|
||||||
@ -24,82 +31,17 @@ bool gPause=false; //to be loaded in and used with Pause/Resume before ODMan ini
|
|||||||
/// a flag that is set if we have loaded some OD blockfiles from PCM.
|
/// a flag that is set if we have loaded some OD blockfiles from PCM.
|
||||||
bool sHasLoadedOD=false;
|
bool sHasLoadedOD=false;
|
||||||
|
|
||||||
|
ODManager* ODManager::pMan=NULL;
|
||||||
|
//init the accessor function pointer - use the first time version of the interface fetcher
|
||||||
|
//first we need to typedef the function pointer type because the compiler doesn't support it in the raw
|
||||||
|
typedef ODManager* (*pfodman)();
|
||||||
|
pfodman ODManager::Instance = &(ODManager::InstanceFirstTime);
|
||||||
|
|
||||||
//libsndfile is not threadsafe - this deals with it
|
//libsndfile is not threadsafe - this deals with it
|
||||||
ODLock sLibSndFileMutex;
|
ODLock sLibSndFileMutex;
|
||||||
|
|
||||||
DEFINE_EVENT_TYPE(EVT_ODTASK_UPDATE)
|
DEFINE_EVENT_TYPE(EVT_ODTASK_UPDATE)
|
||||||
|
|
||||||
//OD files are "greater than" non OD files, to produce a sort that has
|
|
||||||
//OD Files at the end
|
|
||||||
int CompareODFileName(const wxString& first, const wxString& second)
|
|
||||||
{
|
|
||||||
bool firstIsOD = false;
|
|
||||||
bool secondIsOD = false;
|
|
||||||
|
|
||||||
if(first.EndsWith(wxT("wav"))||first.EndsWith(wxT("WAV"))||
|
|
||||||
first.EndsWith(wxT("wave"))||first.EndsWith(wxT("WAVE"))||
|
|
||||||
first.EndsWith(wxT("Wav"))||first.EndsWith(wxT("Wave"))||
|
|
||||||
first.EndsWith(wxT("aif"))||first.EndsWith(wxT("AIF"))||
|
|
||||||
first.EndsWith(wxT("aiff"))||first.EndsWith(wxT("AIFF"))||
|
|
||||||
first.EndsWith(wxT("aiff"))||first.EndsWith(wxT("Aif")) )
|
|
||||||
{
|
|
||||||
firstIsOD=true;
|
|
||||||
}
|
|
||||||
if(second.EndsWith(wxT("wav"))||second.EndsWith(wxT("WAV"))||
|
|
||||||
second.EndsWith(wxT("wave"))||second.EndsWith(wxT("WAVE"))||
|
|
||||||
second.EndsWith(wxT("Wav"))||second.EndsWith(wxT("Wave"))||
|
|
||||||
second.EndsWith(wxT("aif"))||second.EndsWith(wxT("AIF"))||
|
|
||||||
second.EndsWith(wxT("aiff"))||second.EndsWith(wxT("AIFF"))||
|
|
||||||
second.EndsWith(wxT("aiff"))||second.EndsWith(wxT("Aif")) )
|
|
||||||
{
|
|
||||||
secondIsOD=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(firstIsOD && !secondIsOD)
|
|
||||||
return 1;
|
|
||||||
else if(secondIsOD&&!firstIsOD)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return first.Cmp(second);
|
|
||||||
}
|
|
||||||
|
|
||||||
//same as above but OD is less than non-OD
|
|
||||||
int CompareODFirstFileName(const wxString& first, const wxString& second)
|
|
||||||
{
|
|
||||||
bool firstIsOD = false;
|
|
||||||
bool secondIsOD = false;
|
|
||||||
|
|
||||||
if(first.EndsWith(wxT("wav"))||first.EndsWith(wxT("WAV"))||
|
|
||||||
first.EndsWith(wxT("wave"))||first.EndsWith(wxT("WAVE"))||
|
|
||||||
first.EndsWith(wxT("Wav"))||first.EndsWith(wxT("Wave"))||
|
|
||||||
first.EndsWith(wxT("aif"))||first.EndsWith(wxT("AIF"))||
|
|
||||||
first.EndsWith(wxT("aiff"))||first.EndsWith(wxT("AIFF"))||
|
|
||||||
first.EndsWith(wxT("aiff"))||first.EndsWith(wxT("Aif")) )
|
|
||||||
{
|
|
||||||
firstIsOD=true;
|
|
||||||
}
|
|
||||||
if(second.EndsWith(wxT("wav"))||second.EndsWith(wxT("WAV"))||
|
|
||||||
second.EndsWith(wxT("wave"))||second.EndsWith(wxT("WAVE"))||
|
|
||||||
second.EndsWith(wxT("Wav"))||second.EndsWith(wxT("Wave"))||
|
|
||||||
second.EndsWith(wxT("aif"))||second.EndsWith(wxT("AIF"))||
|
|
||||||
second.EndsWith(wxT("aiff"))||second.EndsWith(wxT("AIFF"))||
|
|
||||||
second.EndsWith(wxT("aiff"))||second.EndsWith(wxT("Aif")) )
|
|
||||||
{
|
|
||||||
secondIsOD=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(firstIsOD && !secondIsOD)
|
|
||||||
return -1;
|
|
||||||
else if(secondIsOD&&!firstIsOD)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
//if they are both OD-files, or both non-OD-files, use a normal string comparison
|
|
||||||
//to get alphabetical sorting
|
|
||||||
return first.Cmp(second);
|
|
||||||
}
|
|
||||||
|
|
||||||
//using this with wxStringArray::Sort will give you a list that
|
//using this with wxStringArray::Sort will give you a list that
|
||||||
//is alphabetical, without depending on case. If you use the
|
//is alphabetical, without depending on case. If you use the
|
||||||
//default sort, you will get strings with 'R' before 'a', because it is in caps.
|
//default sort, you will get strings with 'R' before 'a', because it is in caps.
|
||||||
@ -130,7 +72,7 @@ ODManager::ODManager()
|
|||||||
mQueueNotEmptyCond = new ODCondition(&mQueueNotEmptyCondLock);
|
mQueueNotEmptyCond = new ODCondition(&mQueueNotEmptyCondLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
//private constructor - delete with static method Quit()
|
//private destructor - delete with static method Quit()
|
||||||
ODManager::~ODManager()
|
ODManager::~ODManager()
|
||||||
{
|
{
|
||||||
//get rid of all the queues. The queues get rid of the tasks, so we don't worry abut them.
|
//get rid of all the queues. The queues get rid of the tasks, so we don't worry abut them.
|
||||||
@ -182,6 +124,7 @@ void ODManager::SignalTaskQueueLoop()
|
|||||||
void ODManager::RemoveTaskIfInQueue(ODTask* task)
|
void ODManager::RemoveTaskIfInQueue(ODTask* task)
|
||||||
{
|
{
|
||||||
mTasksMutex.Lock();
|
mTasksMutex.Lock();
|
||||||
|
//linear search okay for now, (probably only 1-5 tasks exist at a time.)
|
||||||
for(unsigned int i=0;i<mTasks.size();i++)
|
for(unsigned int i=0;i<mTasks.size();i++)
|
||||||
{
|
{
|
||||||
if(mTasks[i]==task)
|
if(mTasks[i]==task)
|
||||||
@ -206,8 +149,7 @@ void ODManager::AddNewTask(ODTask* task, bool lockMutex)
|
|||||||
mQueuesMutex.Lock();
|
mQueuesMutex.Lock();
|
||||||
for(unsigned int i=0;i<mQueues.size();i++)
|
for(unsigned int i=0;i<mQueues.size();i++)
|
||||||
{
|
{
|
||||||
//search for a task containing the lead track.
|
//search for a task containing the lead track. wavetrack removal is threadsafe and bound to the mQueuesMutex
|
||||||
//This may be buggy when adding tracks. We may have to do an exhaustive search instead.
|
|
||||||
//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)))
|
||||||
queue=mQueues[i];
|
queue=mQueues[i];
|
||||||
@ -234,24 +176,29 @@ void ODManager::AddNewTask(ODTask* task, bool lockMutex)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ODManager* ODManager::Instance()
|
|
||||||
{
|
|
||||||
static ODManager* man=NULL;
|
|
||||||
//this isn't 100% threadsafe but I think Okay for this purpose.
|
|
||||||
|
|
||||||
// wxLogDebug(wxT("Fetching Instance\n"));
|
|
||||||
|
|
||||||
|
//that switches out the mutex/null check.
|
||||||
|
ODManager* ODManager::InstanceFirstTime()
|
||||||
|
{
|
||||||
gODInitedMutex.Lock();
|
gODInitedMutex.Lock();
|
||||||
if(!man)
|
if(!pMan)
|
||||||
{
|
{
|
||||||
man = new ODManager();
|
pMan = new ODManager();
|
||||||
man->Init();
|
pMan->Init();
|
||||||
gManagerCreated = true;
|
gManagerCreated = true;
|
||||||
}
|
}
|
||||||
gODInitedMutex.Unlock();
|
gODInitedMutex.Unlock();
|
||||||
|
|
||||||
return man;
|
//change the accessor function to use the quicker method.
|
||||||
|
Instance = &(ODManager::InstanceNormal);
|
||||||
|
|
||||||
|
return pMan;
|
||||||
|
}
|
||||||
|
|
||||||
|
//faster method of instance fetching once init is done
|
||||||
|
ODManager* ODManager::InstanceNormal()
|
||||||
|
{
|
||||||
|
return pMan;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ODManager::IsInstanceCreated()
|
bool ODManager::IsInstanceCreated()
|
||||||
@ -278,7 +225,7 @@ void ODManager::Init()
|
|||||||
startThread->Run();
|
startThread->Run();
|
||||||
|
|
||||||
// printf("started thread from init\n");
|
// printf("started thread from init\n");
|
||||||
//destruction is taken care of by wx thread code. TODO:Check if pthreads code does this.
|
//destruction of thread is taken care of by thread library
|
||||||
}
|
}
|
||||||
|
|
||||||
void ODManager::DecrementCurrentThreads()
|
void ODManager::DecrementCurrentThreads()
|
||||||
@ -328,13 +275,7 @@ void ODManager::Start()
|
|||||||
mCurrentThreads++;
|
mCurrentThreads++;
|
||||||
mCurrentThreadsMutex.Unlock();
|
mCurrentThreadsMutex.Unlock();
|
||||||
//remove the head
|
//remove the head
|
||||||
mTasksMutex.Lock();
|
|
||||||
//task = mTasks[0];
|
|
||||||
|
|
||||||
//the thread will add it back to the array if the job is not yet done at the end of the thread's run.
|
|
||||||
//mTasks.erase(mTasks.begin());
|
|
||||||
mTasksMutex.Unlock();
|
|
||||||
|
|
||||||
//detach a new thread.
|
//detach a new thread.
|
||||||
thread = new ODTaskThread(mTasks[0]);//task);
|
thread = new ODTaskThread(mTasks[0]);//task);
|
||||||
|
|
||||||
@ -392,18 +333,21 @@ void ODManager::Start()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static function that prevents ODTasks from being scheduled
|
||||||
|
//does not stop currently running tasks from completing their immediate subtask,
|
||||||
|
//but presumably they will finish within a second
|
||||||
void ODManager::Pause(bool pause)
|
void ODManager::Pause(bool pause)
|
||||||
{
|
{
|
||||||
if(IsInstanceCreated())
|
if(IsInstanceCreated())
|
||||||
{
|
{
|
||||||
ODManager::Instance()->mPauseLock.Lock();
|
pMan->mPauseLock.Lock();
|
||||||
ODManager::Instance()->mPause = pause;
|
pMan->mPause = pause;
|
||||||
ODManager::Instance()->mPauseLock.Unlock();
|
pMan->mPauseLock.Unlock();
|
||||||
|
|
||||||
//we should check the queue again.
|
//we should check the queue again.
|
||||||
ODManager::Instance()->mQueueNotEmptyCondLock.Lock();
|
pMan->mQueueNotEmptyCondLock.Lock();
|
||||||
ODManager::Instance()->mQueueNotEmptyCond->Signal();
|
pMan->mQueueNotEmptyCond->Signal();
|
||||||
ODManager::Instance()->mQueueNotEmptyCondLock.Unlock();
|
pMan->mQueueNotEmptyCondLock.Unlock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -420,27 +364,29 @@ void ODManager::Quit()
|
|||||||
{
|
{
|
||||||
if(IsInstanceCreated())
|
if(IsInstanceCreated())
|
||||||
{
|
{
|
||||||
ODManager::Instance()->mTerminateMutex.Lock();
|
pMan->mTerminateMutex.Lock();
|
||||||
ODManager::Instance()->mTerminate = true;
|
pMan->mTerminate = true;
|
||||||
ODManager::Instance()->mTerminateMutex.Unlock();
|
pMan->mTerminateMutex.Unlock();
|
||||||
|
|
||||||
ODManager::Instance()->mTerminatedMutex.Lock();
|
pMan->mTerminatedMutex.Lock();
|
||||||
while(!ODManager::Instance()->mTerminated)
|
while(!pMan->mTerminated)
|
||||||
{
|
{
|
||||||
ODManager::Instance()->mTerminatedMutex.Unlock();
|
pMan->mTerminatedMutex.Unlock();
|
||||||
wxThread::Sleep(200);
|
wxThread::Sleep(200);
|
||||||
|
|
||||||
//signal the queue not empty condition since the ODMan thread will wait on the queue condition
|
//signal the queue not empty condition since the ODMan thread will wait on the queue condition
|
||||||
ODManager::Instance()->mQueueNotEmptyCondLock.Lock();
|
pMan->mQueueNotEmptyCondLock.Lock();
|
||||||
ODManager::Instance()->mQueueNotEmptyCond->Signal();
|
pMan->mQueueNotEmptyCond->Signal();
|
||||||
ODManager::Instance()->mQueueNotEmptyCondLock.Unlock();
|
pMan->mQueueNotEmptyCondLock.Unlock();
|
||||||
|
|
||||||
ODManager::Instance()->mTerminatedMutex.Lock();
|
pMan->mTerminatedMutex.Lock();
|
||||||
}
|
}
|
||||||
ODManager::Instance()->mTerminatedMutex.Unlock();
|
pMan->mTerminatedMutex.Unlock();
|
||||||
|
|
||||||
|
|
||||||
delete ODManager::Instance();
|
delete pMan;
|
||||||
|
//The above while loop waits for ODTasks to finish and the delete removes all tasks from the Queue.
|
||||||
|
//This function is called from the main audacity event thread, so there should not be more requests for pMan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,10 +518,7 @@ void ODManager::UpdateQueues()
|
|||||||
ODWaveTrackTaskQueue* queue;
|
ODWaveTrackTaskQueue* queue;
|
||||||
queue = mQueues[i];
|
queue = mQueues[i];
|
||||||
|
|
||||||
mQueuesMutex.Unlock();
|
|
||||||
AddTask(queue->GetFrontTask());
|
AddTask(queue->GetFrontTask());
|
||||||
mQueuesMutex.Lock();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ number of threads.
|
|||||||
|
|
||||||
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_ODTASK_UPDATE, -1)
|
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_ODTASK_UPDATE, -1)
|
||||||
|
|
||||||
///wxstring compare function for sorting filenames with od
|
///wxstring compare function for sorting case, which is needed to load correctly.
|
||||||
int CompareODFileName(const wxString& first, const wxString& second);
|
|
||||||
int CompareODFirstFileName(const wxString& first, const wxString& second);
|
|
||||||
int CompareNoCaseFileName(const wxString& first, const wxString& second);
|
int CompareNoCaseFileName(const wxString& first, const wxString& second);
|
||||||
/// A singleton that manages currently running Tasks on an arbitrary
|
/// A singleton that manages currently running Tasks on an arbitrary
|
||||||
/// number of threads.
|
/// number of threads.
|
||||||
@ -52,8 +50,13 @@ class ODWaveTrackTaskQueue;
|
|||||||
class ODManager
|
class ODManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
///Gets the singleton instance - this is a function pointer that points to one of the below two instance calls.
|
||||||
|
///Note that it is not a member function pointer since it is a static function.
|
||||||
|
static ODManager* (*Instance)();
|
||||||
///Gets the singleton instance
|
///Gets the singleton instance
|
||||||
static ODManager* Instance();
|
static ODManager* InstanceFirstTime();
|
||||||
|
///Gets the singleton instance
|
||||||
|
static ODManager* InstanceNormal();
|
||||||
|
|
||||||
///Kills the ODMananger Thread.
|
///Kills the ODMananger Thread.
|
||||||
static void Quit();
|
static void Quit();
|
||||||
@ -132,6 +135,8 @@ class ODManager
|
|||||||
///Remove references in our array to Tasks that have been completed/Schedule new ones
|
///Remove references in our array to Tasks that have been completed/Schedule new ones
|
||||||
void UpdateQueues();
|
void UpdateQueues();
|
||||||
|
|
||||||
|
//instance
|
||||||
|
static ODManager* pMan;
|
||||||
|
|
||||||
//List of tracks and their active and inactive tasks.
|
//List of tracks and their active and inactive tasks.
|
||||||
std::vector<ODWaveTrackTaskQueue*> mQueues;
|
std::vector<ODWaveTrackTaskQueue*> mQueues;
|
||||||
|
@ -110,7 +110,10 @@ void ODWaveTrackTaskQueue::AddTask(ODTask* task)
|
|||||||
mTracksMutex.Lock();
|
mTracksMutex.Lock();
|
||||||
for(int i=0;i<task->GetNumWaveTracks();i++)
|
for(int i=0;i<task->GetNumWaveTracks();i++)
|
||||||
{
|
{
|
||||||
//ODTask::GetWaveTrack is not threadsafe, but I think we are safe anyway, because the task isn't being run yet?
|
//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
|
||||||
|
//handled since mQueuesMutex is locked one up in the stack from here,
|
||||||
|
//and WaveTrack deletion is bound to that.
|
||||||
mTracks.push_back(task->GetWaveTrack(i));
|
mTracks.push_back(task->GetWaveTrack(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +168,11 @@ void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track)
|
|||||||
{
|
{
|
||||||
task=mTasks[j]->Clone();
|
task=mTasks[j]->Clone();
|
||||||
task->AddWaveTrack(track);
|
task->AddWaveTrack(track);
|
||||||
mTasksMutex.Unlock(); //AddNewTask assumes no locks.
|
//AddNewTask requires us to relinquish this lock. However, it is safe because ODManager::MakeWaveTrackIndependent
|
||||||
|
//has already locked the m_queuesMutex.
|
||||||
|
mTasksMutex.Unlock();
|
||||||
|
//AddNewTask locks the m_queuesMutex which is already locked by ODManager::MakeWaveTrackIndependent,
|
||||||
|
//so we pass a boolean flag telling it not to lock again.
|
||||||
ODManager::Instance()->AddNewTask(task,false);
|
ODManager::Instance()->AddNewTask(task,false);
|
||||||
mTasksMutex.Lock();
|
mTasksMutex.Lock();
|
||||||
}
|
}
|
||||||
@ -304,7 +311,7 @@ void ODWaveTrackTaskQueue::RemoveFrontTask()
|
|||||||
mTasksMutex.Unlock();
|
mTasksMutex.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Schedules the front task for immediate execution
|
///gets the front task for immediate execution
|
||||||
ODTask* ODWaveTrackTaskQueue::GetFrontTask()
|
ODTask* ODWaveTrackTaskQueue::GetFrontTask()
|
||||||
{
|
{
|
||||||
mTasksMutex.Lock();
|
mTasksMutex.Lock();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user