mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-16 17:41:14 +01:00
Remove trailing spaces.
This commit is contained in:
@@ -35,41 +35,41 @@ class ODComputeSummaryTask:public ODTask
|
||||
/// Constructs an ODTask
|
||||
ODComputeSummaryTask();
|
||||
virtual ~ODComputeSummaryTask(){};
|
||||
|
||||
|
||||
virtual ODTask* Clone();
|
||||
|
||||
|
||||
///Subclasses should override to return respective type.
|
||||
virtual unsigned int GetODType(){return eODPCMSummary;}
|
||||
|
||||
|
||||
///Return the task name
|
||||
virtual const char* GetTaskName(){return "ODComputeSummaryTask";}
|
||||
|
||||
|
||||
virtual const wxChar* GetTip(){return _("Import complete. Calculating waveform");}
|
||||
|
||||
|
||||
virtual bool UsesCustomWorkUntilPercentage(){return true;}
|
||||
virtual float ComputeNextWorkUntilPercentageComplete();
|
||||
|
||||
|
||||
///releases memory that the ODTask owns. Subclasses should override.
|
||||
virtual void Terminate();
|
||||
|
||||
|
||||
protected:
|
||||
///recalculates the percentage complete.
|
||||
virtual void CalculatePercentComplete();
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
virtual void DoSomeInternal();
|
||||
|
||||
|
||||
///Readjusts the blockfile order in the default manner. If we have had an ODRequest
|
||||
///Then it updates in the OD manner.
|
||||
virtual void Update();
|
||||
|
||||
|
||||
///Orders the input as either On-Demand or default layered order.
|
||||
void OrderBlockFiles(std::vector<ODPCMAliasBlockFile*> &unorderedBlocks);
|
||||
|
||||
///tells us whether or not Update has been run at least once.
|
||||
///tells us whether or not Update has been run at least once.
|
||||
void MarkUpdateRan();
|
||||
bool HasUpdateRan();
|
||||
|
||||
|
||||
//mBlockFiles is touched on several threads- the OD terminate thread, and the task thread, so we need to mutex it.
|
||||
ODLock mBlockFilesMutex;
|
||||
std::vector<ODPCMAliasBlockFile*> mBlockFiles;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <wx/window.h>
|
||||
#endif
|
||||
|
||||
#include "../Experimental.h"
|
||||
#include "../Experimental.h"
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
#ifdef EXPERIMENTAL_OD_FFMPEG
|
||||
@@ -60,22 +60,22 @@ public:
|
||||
///This should handle unicode converted to UTF-8 on mac/linux, but OD TODO:check on windows
|
||||
ODFFmpegDecoder(const wxString & fileName, streamContext** scs, int numStreams,WaveTrack*** channels, AVFormatContext* formatContext, int streamIndex);
|
||||
virtual ~ODFFmpegDecoder();
|
||||
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
///This is file specific, so subclasses must implement this only.
|
||||
///the buffer was defined like
|
||||
///samplePtr sampleData = NewSamples(mLen, floatSample);
|
||||
///this->ReadData(sampleData, floatSample, 0, mLen);
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
virtual int Decode(samplePtr & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel);
|
||||
|
||||
///This is a must implement abstract virtual in the superclass.
|
||||
///This is a must implement abstract virtual in the superclass.
|
||||
///However it doesn't do anything because ImportFFMpeg does all that for us.
|
||||
virtual bool ReadHeader() {return true;}
|
||||
|
||||
|
||||
bool SeekingAllowed() ;
|
||||
|
||||
|
||||
private:
|
||||
void InsertCache(FFMpegDecodeCache* cache);
|
||||
|
||||
@@ -85,13 +85,13 @@ private:
|
||||
///! Reads next audio frame
|
||||
///\return pointer to the stream context structure to which the frame belongs to or NULL on error, or 1 if stream is not to be imported.
|
||||
streamContext* ReadNextFrame();
|
||||
|
||||
|
||||
///! Decodes the frame
|
||||
///\param sc - stream context (from ReadNextFrame)
|
||||
///\param flushing - true if flushing (no more frames left), false otherwise
|
||||
///\return 0 on success, -1 if it can't decode any further
|
||||
int DecodeFrame(streamContext *sc, bool flushing);
|
||||
|
||||
|
||||
int mNumStreams;
|
||||
streamContext **mScs; //!< Array of pointers to stream contexts. Length is mNumStreams.
|
||||
WaveTrack*** mChannels;
|
||||
@@ -100,13 +100,13 @@ private:
|
||||
int mNumSamplesInCache;
|
||||
sampleCount mCurrentPos; //the index of the next sample to be decoded
|
||||
sampleCount mCurrentLen; //length of the last packet decoded
|
||||
|
||||
|
||||
bool mSeekingAllowedStatus;
|
||||
int mStreamIndex;
|
||||
};
|
||||
|
||||
|
||||
//------ ODDecodeFFmpegTask definitions
|
||||
//------ ODDecodeFFmpegTask definitions
|
||||
ODDecodeFFmpegTask::ODDecodeFFmpegTask(void* scs,int numStreams, WaveTrack*** channels, void* formatContext, int streamIndex)
|
||||
{
|
||||
mScs=scs;
|
||||
@@ -149,7 +149,7 @@ ODFileDecoder* ODDecodeFFmpegTask::CreateFileDecoder(const wxString & fileName)
|
||||
|
||||
/// subclasses need to override this if they cannot always seek.
|
||||
/// seeking will be enabled once this is true.
|
||||
bool ODFFmpegDecoder::SeekingAllowed()
|
||||
bool ODFFmpegDecoder::SeekingAllowed()
|
||||
{
|
||||
return false;
|
||||
/*
|
||||
@@ -157,7 +157,7 @@ bool ODFFmpegDecoder::SeekingAllowed()
|
||||
return mSeekingAllowedStatus == ODFFMPEG_SEEKING_TEST_SUCCESS;
|
||||
|
||||
//we can seek if the following checks pass:
|
||||
//-sample rate is less than the reciprocal of the time_base of the seeking stream.
|
||||
//-sample rate is less than the reciprocal of the time_base of the seeking stream.
|
||||
//-a seek test has been made and dts updates as expected.
|
||||
//we want to clone this to run a seek test.
|
||||
AVFormatContext* ic = (AVFormatContext*)mFormatContext;
|
||||
@@ -168,27 +168,27 @@ bool ODFFmpegDecoder::SeekingAllowed()
|
||||
for (unsigned int i = 0; i < ic->nb_streams; i++)
|
||||
{
|
||||
if (ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
audioStreamExists = true;
|
||||
{
|
||||
audioStreamExists = true;
|
||||
st = ic->streams[i];
|
||||
if(st->duration <= 0 || st->codec->sample_rate <= 0)
|
||||
goto test_failed;
|
||||
|
||||
//if the time base reciprocal is less than the sample rate it means we can't accurately represent a sample with the timestamp in av.
|
||||
float time_base_inv = ((float)st->time_base.den/st->time_base.num);
|
||||
|
||||
//if the time base reciprocal is less than the sample rate it means we can't accurately represent a sample with the timestamp in av.
|
||||
float time_base_inv = ((float)st->time_base.den/st->time_base.num);
|
||||
if(time_base_inv < st->codec->sample_rate)
|
||||
goto test_failed;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!audioStreamExists)
|
||||
goto test_failed;
|
||||
//TODO: now try a seek and see if dts/pts (decode/presentation timestamp) is updated as we expected it to be.
|
||||
//TODO: now try a seek and see if dts/pts (decode/presentation timestamp) is updated as we expected it to be.
|
||||
//This should be done using a new AVFormatContext clone so that we don't ruin the file pointer if we fail.
|
||||
// url_fseek(mFormatContext->pb,0,SEEK_SET);
|
||||
// url_fseek(mFormatContext->pb,0,SEEK_SET);
|
||||
|
||||
|
||||
|
||||
AVFormatContext* tempContext;
|
||||
int err;
|
||||
err = ufile_fopen_input(&tempContext, mFName);
|
||||
@@ -230,8 +230,8 @@ mCurrentLen(0),
|
||||
mSeekingAllowedStatus(ODFFMPEG_SEEKING_TEST_UNKNOWN),
|
||||
mStreamIndex(streamIndex)
|
||||
{
|
||||
PickFFmpegLibs();
|
||||
|
||||
PickFFmpegLibs();
|
||||
|
||||
//do a shallow copy of the 2d array.
|
||||
mChannels = new WaveTrack **[mNumStreams];
|
||||
|
||||
@@ -251,8 +251,8 @@ mStreamIndex(streamIndex)
|
||||
stream_delay = mScs[streamIndex]->m_stream->start_time;
|
||||
}
|
||||
mCurrentPos = double(stream_delay) / AV_TIME_BASE;
|
||||
|
||||
//TODO: add a ref counter to scs? This will be necessary if we want to allow copy and paste of not-yet decoded
|
||||
|
||||
//TODO: add a ref counter to scs? This will be necessary if we want to allow copy and paste of not-yet decoded
|
||||
//ODDecodeBlockFiles that point to FFmpeg files.
|
||||
}
|
||||
|
||||
@@ -273,15 +273,15 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
|
||||
delete mScs[i];
|
||||
}
|
||||
free(mScs);
|
||||
|
||||
|
||||
//delete our caches.
|
||||
while(mDecodeCache.size())
|
||||
{
|
||||
free(mDecodeCache[0]->samplePtr);
|
||||
delete mDecodeCache[0];
|
||||
mDecodeCache.erase(mDecodeCache.begin());
|
||||
mDecodeCache.erase(mDecodeCache.begin());
|
||||
}
|
||||
|
||||
|
||||
//free the channel pointer arrays
|
||||
for (int s = 0; s < mNumStreams; s++)
|
||||
{
|
||||
@@ -295,7 +295,7 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
|
||||
//this value controls this amount. this should be a value that is much larger than the payload for a single packet, and around block file size around 1-10 secs.
|
||||
#define kDecodeSampleAllowance 400000
|
||||
//number of jump backwards seeks
|
||||
#define kMaxSeekRewindAttempts 8
|
||||
#define kMaxSeekRewindAttempts 8
|
||||
int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel)
|
||||
{
|
||||
format = mScs[mStreamIndex]->m_osamplefmt;
|
||||
@@ -303,17 +303,17 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
data = NewSamples(len, format);
|
||||
samplePtr bufStart = data;
|
||||
streamContext* sc = NULL;
|
||||
|
||||
|
||||
int nChannels;
|
||||
|
||||
// printf("start %llu len %llu\n", start, len);
|
||||
|
||||
// printf("start %llu len %llu\n", start, len);
|
||||
//TODO update this to work with seek - this only works linearly now.
|
||||
if(mCurrentPos > start && mCurrentPos <= start+len + kDecodeSampleAllowance)
|
||||
{
|
||||
//this next call takes data, start and len as reference variables and updates them to reflect the new area that is needed.
|
||||
FillDataFromCache(bufStart, format, start,len,channel);
|
||||
}
|
||||
|
||||
|
||||
bool seeking = false;
|
||||
//look at the decoding timestamp and see if the next sample that will be decoded is not the next sample we need.
|
||||
if(len && (mCurrentPos > start + len || mCurrentPos + kDecodeSampleAllowance < start ) && SeekingAllowed()) {
|
||||
@@ -321,14 +321,14 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
AVStream* st = sc->m_stream;
|
||||
int stindex = -1;
|
||||
uint64_t targetts;
|
||||
|
||||
//printf("attempting seek to %llu\n", start);
|
||||
|
||||
//printf("attempting seek to %llu\n", start);
|
||||
//we have to find the index for this stream.
|
||||
for (unsigned int i = 0; i < mFormatContext->nb_streams; i++) {
|
||||
if (mFormatContext->streams[i] == sc->m_stream )
|
||||
stindex =i;
|
||||
}
|
||||
|
||||
|
||||
if(stindex >=0) {
|
||||
int numAttempts = 0;
|
||||
//reset mCurrentPos to a bogus value
|
||||
@@ -336,18 +336,18 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
while(numAttempts++ < kMaxSeekRewindAttempts && mCurrentPos > start) {
|
||||
//we want to move slightly before the start of the block file, but not too far ahead
|
||||
targetts = (start-kDecodeSampleAllowance*numAttempts/kMaxSeekRewindAttempts) * ((double)st->time_base.den/(st->time_base.num * st->codec->sample_rate ));
|
||||
if(targetts<0)
|
||||
if(targetts<0)
|
||||
targetts=0;
|
||||
|
||||
//printf("attempting seek to %llu, attempts %d\n", targetts, numAttempts);
|
||||
//printf("attempting seek to %llu, attempts %d\n", targetts, numAttempts);
|
||||
if(av_seek_frame(mFormatContext,stindex,targetts,0) >= 0){
|
||||
//find out the dts we've seekd to.
|
||||
//find out the dts we've seekd to.
|
||||
sampleCount actualDecodeStart = 0.5 + st->codec->sample_rate * st->cur_dts * ((double)st->time_base.num/st->time_base.den); //this is mostly safe because den is usually 1 or low number but check for high values.
|
||||
|
||||
|
||||
mCurrentPos = actualDecodeStart;
|
||||
seeking = true;
|
||||
|
||||
//if the seek was past our desired position, rewind a bit.
|
||||
//if the seek was past our desired position, rewind a bit.
|
||||
//printf("seek ok to %llu samps, float: %f\n",actualDecodeStart,actualDecodeStartDouble);
|
||||
} else {
|
||||
printf("seek failed");
|
||||
@@ -356,14 +356,14 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
}
|
||||
if(mCurrentPos>start){
|
||||
mSeekingAllowedStatus = (bool)ODFFMPEG_SEEKING_TEST_FAILED;
|
||||
// url_fseek(mFormatContext->pb,sc->m_pkt.pos,SEEK_SET);
|
||||
// url_fseek(mFormatContext->pb,sc->m_pkt.pos,SEEK_SET);
|
||||
printf("seek fail, reverting to previous pos\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool firstpass = true;
|
||||
|
||||
|
||||
//we decode up to the end of the blockfile
|
||||
while (len>0 && (mCurrentPos < start+len) && (sc = ReadNextFrame()) != NULL)
|
||||
{
|
||||
@@ -378,7 +378,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
// for some formats
|
||||
// The only other case for inserting silence is for initial offset and ImportFFmpeg.cpp does this for us
|
||||
if (seeking) {
|
||||
actualDecodeStart = 0.52 + (sc->m_stream->codec->sample_rate * sc->m_pkt.dts
|
||||
actualDecodeStart = 0.52 + (sc->m_stream->codec->sample_rate * sc->m_pkt.dts
|
||||
* ((double)sc->m_stream->time_base.num / sc->m_stream->time_base.den));
|
||||
//this is mostly safe because den is usually 1 or low number but check for high values.
|
||||
|
||||
@@ -398,9 +398,9 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
FFMpegDecodeCache* cache = new FFMpegDecodeCache;
|
||||
|
||||
//printf("skipping/zeroing %i samples. - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",amt,actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len);
|
||||
|
||||
|
||||
//put it in the cache so the other channels can use it.
|
||||
cache->numChannels = sc->m_stream->codec->channels;
|
||||
cache->numChannels = sc->m_stream->codec->channels;
|
||||
cache->len = amt;
|
||||
cache->start=start;
|
||||
// 8 bit and 16 bit audio output from ffmpeg means
|
||||
@@ -414,7 +414,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
cache->samplePtr = (uint8_t*) malloc(amt * cache->numChannels * SAMPLE_SIZE(format));
|
||||
|
||||
memset(cache->samplePtr, 0, amt * cache->numChannels * SAMPLE_SIZE(format));
|
||||
|
||||
|
||||
InsertCache(cache);
|
||||
}
|
||||
firstpass=false;
|
||||
@@ -431,7 +431,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
{
|
||||
av_free_packet(&sc->m_pkt);
|
||||
sc->m_pktValid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,14 +446,14 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
|
||||
{
|
||||
av_free_packet(&mScs[i]->m_pkt);
|
||||
mScs[i]->m_pktValid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//this next call takes data, start and len as reference variables and updates them to reflect the new area that is needed.
|
||||
FillDataFromCache(bufStart, format, start, len, channel);
|
||||
|
||||
|
||||
// CHECK: not sure if we need this. In any case it has to be updated for the new float case (not just int16)
|
||||
//if for some reason we couldn't get the samples, fill them with silence
|
||||
/*
|
||||
@@ -475,10 +475,10 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
if(mDecodeCache.size() <= 0)
|
||||
return 0;
|
||||
int samplesFilled=0;
|
||||
|
||||
//do a search for the best position to start at.
|
||||
|
||||
//do a search for the best position to start at.
|
||||
//Guess that the array is evenly spaced from end to end - (dictionary sort)
|
||||
//assumes the array is sorted.
|
||||
//assumes the array is sorted.
|
||||
//all we need for this to work is a location in the cache array
|
||||
//that has a start time of less than our start sample, but try to get closer with binary search
|
||||
int searchStart = 0;
|
||||
@@ -491,7 +491,7 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
while(searchStart+1<searchEnd)
|
||||
{
|
||||
guess = (searchStart+searchEnd)/2;//find a midpoint. //searchStart+ (searchEnd-searchStart)* ((float)start - mDecodeCache[searchStart]->start )/mDecodeCache[searchEnd]->start;
|
||||
|
||||
|
||||
//we want guess to point at the first index that hits even if there are duplicate start times (which can happen)
|
||||
if(mDecodeCache[guess]->start+mDecodeCache[guess]->len >= start)
|
||||
searchEnd = --guess;
|
||||
@@ -499,15 +499,15 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
searchStart = guess;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//this is a sorted array
|
||||
for(int i=searchStart; i < (int)mDecodeCache.size(); i++)
|
||||
{
|
||||
{
|
||||
//check for a cache hit - be careful to include the first/last sample an nothing more.
|
||||
//we only accept cache hits that touch either end - no piecing out of the middle.
|
||||
//this way the amount to be decoded remains set.
|
||||
if(start < mDecodeCache[i]->start+mDecodeCache[i]->len &&
|
||||
start + len > mDecodeCache[i]->start)
|
||||
start + len > mDecodeCache[i]->start)
|
||||
{
|
||||
uint8_t* outBuf;
|
||||
outBuf = (uint8_t*)data;
|
||||
@@ -515,12 +515,12 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
//a method of dealing with this yet, and it won't happen very often.
|
||||
if(start<mDecodeCache[i]->start && start+len > mDecodeCache[i]->start+mDecodeCache[i]->len)
|
||||
continue;
|
||||
|
||||
|
||||
int samplesHit;
|
||||
int hitStartInCache;
|
||||
int hitStartInRequest;
|
||||
int nChannels = mDecodeCache[i]->numChannels;
|
||||
samplesHit = FFMIN(start+len,mDecodeCache[i]->start+mDecodeCache[i]->len)
|
||||
samplesHit = FFMIN(start+len,mDecodeCache[i]->start+mDecodeCache[i]->len)
|
||||
- FFMAX(mDecodeCache[i]->start,start);
|
||||
//find the start of the hit relative to the cache buffer start.
|
||||
hitStartInCache = FFMAX(0,start-mDecodeCache[i]->start);
|
||||
@@ -537,24 +537,24 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
//printf("u8 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
((int16_t *)outBuf)[outIndex] = (int16_t) (((uint8_t*)mDecodeCache[i]->samplePtr)[inIndex] - 0x80) << 8;
|
||||
break;
|
||||
|
||||
|
||||
case SAMPLE_FMT_S16:
|
||||
//printf("u16 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
((int16_t *)outBuf)[outIndex] = ((int16_t*)mDecodeCache[i]->samplePtr)[inIndex];
|
||||
break;
|
||||
|
||||
|
||||
case SAMPLE_FMT_S32:
|
||||
//printf("s32 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
//printf("s32 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
((float *)outBuf)[outIndex] = (float) ((int32_t*)mDecodeCache[i]->samplePtr)[inIndex] * (1.0 / (1 << 31));
|
||||
break;
|
||||
|
||||
|
||||
case SAMPLE_FMT_FLT:
|
||||
//printf("f in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
((float *)outBuf)[outIndex] = (float) ((float*)mDecodeCache[i]->samplePtr)[inIndex];
|
||||
break;
|
||||
|
||||
|
||||
case SAMPLE_FMT_DBL:
|
||||
//printf("dbl in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
//printf("dbl in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||
((float *)outBuf)[outIndex] = (float) ((double*)mDecodeCache[i]->samplePtr)[inIndex];
|
||||
break;
|
||||
|
||||
@@ -566,7 +566,7 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
}
|
||||
//update the cursor
|
||||
samplesFilled += samplesHit;
|
||||
|
||||
|
||||
//update the input start/len params - if the end was hit we can take off just len.
|
||||
//otherwise, we can assume only the front of the request buffer was hit since we don't allow it to be split.
|
||||
if(start < mDecodeCache[i]->start)
|
||||
@@ -601,7 +601,7 @@ int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
|
||||
|
||||
if (ret == 0 && sc->m_frameValid) {
|
||||
//stick it in the cache.
|
||||
//TODO- consider growing/unioning a few cache buffers like WaveCache does.
|
||||
//TODO- consider growing/unioning a few cache buffers like WaveCache does.
|
||||
//however we can't use wavecache as it isn't going to handle our stereo interleaved part, and isn't for samples
|
||||
//However if other ODDecode tasks need this, we should do a new class for caching.
|
||||
FFMpegDecodeCache* cache = new FFMpegDecodeCache;
|
||||
@@ -613,7 +613,7 @@ int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
|
||||
cache->samplePtr = (uint8_t*) malloc(sc->m_decodedAudioSamplesValidSiz);
|
||||
cache->samplefmt = sc->m_samplefmt;
|
||||
memcpy(cache->samplePtr, sc->m_decodedAudioSamples, sc->m_decodedAudioSamplesValidSiz);
|
||||
|
||||
|
||||
InsertCache(cache);
|
||||
}
|
||||
return ret;
|
||||
@@ -621,11 +621,11 @@ int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
|
||||
|
||||
void ODFFmpegDecoder::InsertCache(FFMpegDecodeCache* cache) {
|
||||
int searchStart = 0;
|
||||
int searchEnd = mDecodeCache.size(); //size() is also a valid insert index.
|
||||
int searchEnd = mDecodeCache.size(); //size() is also a valid insert index.
|
||||
int guess = 0;
|
||||
//first just guess that the cache is contiguous and we can just use math to figure it out like a dictionary
|
||||
//by guessing where our hit will be.
|
||||
|
||||
|
||||
// printf("inserting cache start %llu, mCurrentPos %llu\n", cache->start, mCurrentPos);
|
||||
while(searchStart<searchEnd)
|
||||
{
|
||||
@@ -641,13 +641,13 @@ void ODFFmpegDecoder::InsertCache(FFMpegDecodeCache* cache) {
|
||||
searchStart = ++guess;
|
||||
}
|
||||
mCurrentLen = cache->len;
|
||||
mCurrentPos=cache->start+cache->len;
|
||||
mCurrentPos=cache->start+cache->len;
|
||||
mDecodeCache.insert(mDecodeCache.begin()+guess, cache);
|
||||
// mDecodeCache.push_back(cache);
|
||||
|
||||
|
||||
mNumSamplesInCache+=cache->len;
|
||||
|
||||
//if the cache is too big, drop some.
|
||||
|
||||
//if the cache is too big, drop some.
|
||||
while(mNumSamplesInCache>kMaxSamplesInCache)
|
||||
{
|
||||
int dropindex;
|
||||
@@ -656,7 +656,7 @@ void ODFFmpegDecoder::InsertCache(FFMpegDecodeCache* cache) {
|
||||
mNumSamplesInCache-=mDecodeCache[dropindex]->len;
|
||||
free(mDecodeCache[dropindex]->samplePtr);
|
||||
delete mDecodeCache[dropindex];
|
||||
mDecodeCache.erase(mDecodeCache.begin()+dropindex);
|
||||
mDecodeCache.erase(mDecodeCache.begin()+dropindex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ class ODDecodeFFmpegTask:public ODDecodeTask
|
||||
virtual ODTask* Clone();
|
||||
///Creates an ODFileDecoder that decodes a file of filetype the subclass handles.
|
||||
virtual ODFileDecoder* CreateFileDecoder(const wxString & fileName);
|
||||
|
||||
///Lets other classes know that this class handles the ffmpeg type
|
||||
|
||||
///Lets other classes know that this class handles the ffmpeg type
|
||||
///Subclasses should override to return respective type.
|
||||
virtual unsigned int GetODType(){return eODFFMPEG;}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <wx/file.h>
|
||||
#include <wx/ffile.h>
|
||||
|
||||
#ifdef USE_LIBID3TAG
|
||||
#ifdef USE_LIBID3TAG
|
||||
extern "C" {
|
||||
#include <id3tag.h>
|
||||
}
|
||||
@@ -85,8 +85,8 @@ void ODFLACFile::metadata_callback(const FLAC__StreamMetadata *metadata)
|
||||
void ODFLACFile::error_callback(FLAC__StreamDecoderErrorStatus status)
|
||||
{
|
||||
mWasError = true;
|
||||
|
||||
|
||||
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
||||
@@ -109,16 +109,16 @@ void ODFLACFile::error_callback(FLAC__StreamDecoderErrorStatus status)
|
||||
FLAC__StreamDecoderWriteStatus ODFLACFile::write_callback(const FLAC__Frame *frame,
|
||||
const FLAC__int32 * const buffer[])
|
||||
{
|
||||
|
||||
|
||||
unsigned int bytesToCopy = frame->header.blocksize;
|
||||
if(bytesToCopy>mDecoder->mDecodeBufferLen-mDecoder->mDecodeBufferWritePosition)
|
||||
bytesToCopy=mDecoder->mDecodeBufferLen-mDecoder->mDecodeBufferWritePosition;
|
||||
|
||||
|
||||
//the decodeBuffer was allocated to be the same format as the flac buffer, so we can do a straight up memcpy.
|
||||
memcpy(mDecoder->mDecodeBuffer+SAMPLE_SIZE(mDecoder->mFormat)*mDecoder->mDecodeBufferWritePosition,buffer[mDecoder->mTargetChannel],SAMPLE_SIZE(mDecoder->mFormat) * bytesToCopy);
|
||||
|
||||
|
||||
mDecoder->mDecodeBufferWritePosition+=bytesToCopy;
|
||||
/*
|
||||
/*
|
||||
short *tmp=new short[frame->header.blocksize];
|
||||
|
||||
for (unsigned int chn=0; chn<mDecoder->mNumChannels; chn++) {
|
||||
@@ -142,10 +142,10 @@ FLAC__StreamDecoderWriteStatus ODFLACFile::write_callback(const FLAC__Frame *fra
|
||||
*/
|
||||
|
||||
mDecoder->mSamplesDone += frame->header.blocksize;
|
||||
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
// return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
|
||||
|
||||
// mDecoder->mUpdateResult = mDecoder->mProgress->Update((wxULongLong_t) mDecoder->mSamplesDone, mDecoder->mNumSamples != 0 ? (wxULongLong_t)mDecoder->mNumSamples : 1);
|
||||
/*
|
||||
if (mDecoder->mUpdateResult != eProgressSuccess)
|
||||
@@ -159,44 +159,44 @@ FLAC__StreamDecoderWriteStatus ODFLACFile::write_callback(const FLAC__Frame *fra
|
||||
|
||||
|
||||
//--Decoder stuff:
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
///This is file specific, so subclasses must implement this only.
|
||||
///the buffer was defined like
|
||||
///samplePtr sampleData = NewSamples(mLen, floatSample);
|
||||
///this->ReadData(sampleData, floatSample, 0, mLen);
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
int ODFlacDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel)
|
||||
{
|
||||
|
||||
//we need to lock this so the target stays fixed over the seek/write callback.
|
||||
mFlacFileLock.Lock();
|
||||
|
||||
|
||||
bool usingCache=mLastDecodeStartSample==start;
|
||||
if(usingCache)
|
||||
{
|
||||
//we've just decoded this, so lets use a cache. (often so for
|
||||
//we've just decoded this, so lets use a cache. (often so for
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
mDecodeBufferWritePosition=0;
|
||||
mDecodeBufferLen = len;
|
||||
|
||||
data = NewSamples(len, mFormat);
|
||||
mDecodeBuffer=data;
|
||||
format = mFormat;
|
||||
|
||||
|
||||
mTargetChannel=channel;
|
||||
|
||||
|
||||
if(!mFile->seek_absolute(start))
|
||||
{
|
||||
mFlacFileLock.Unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while(mDecodeBufferWritePosition<mDecodeBufferLen)
|
||||
mFile->process_single();
|
||||
|
||||
|
||||
mFlacFileLock.Unlock();
|
||||
if(!usingCache)
|
||||
{
|
||||
@@ -206,9 +206,9 @@ int ODFlacDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount s
|
||||
//calculate summary happen in ODDecodeBlockFile::WriteODDecodeBlockFile, where this method is also called.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
///Read header. Subclasses must override. Probably should save the info somewhere.
|
||||
///Ideally called once per decoding of a file. This complicates the task because
|
||||
///Ideally called once per decoding of a file. This complicates the task because
|
||||
///returns true if the file exists and the header was read alright.
|
||||
|
||||
//Note:we are not using LEGACY_FLAC defs (see ImportFlac.cpp FlacImportFileHandle::Init()
|
||||
@@ -219,7 +219,7 @@ bool ODFlacDecoder::ReadHeader()
|
||||
//we want to use the native flac type for quick conversion.
|
||||
/* (sampleFormat)
|
||||
gPrefs->Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample);*/
|
||||
if(mFile)
|
||||
if(mFile)
|
||||
delete mFile;
|
||||
mFile = new ODFLACFile(this);
|
||||
|
||||
@@ -252,11 +252,11 @@ bool ODFlacDecoder::ReadHeader()
|
||||
// This probably is not a FLAC file at all
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MarkInitialized();
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ODFLACFile* ODFlacDecoder::GetFlacFile()
|
||||
{
|
||||
@@ -264,7 +264,7 @@ ODFLACFile* ODFlacDecoder::GetFlacFile()
|
||||
}
|
||||
|
||||
ODFlacDecoder::~ODFlacDecoder(){
|
||||
if(mFile)
|
||||
if(mFile)
|
||||
{
|
||||
mFile->finish();
|
||||
delete mFile;
|
||||
@@ -290,7 +290,7 @@ ODFileDecoder* ODDecodeFlacTask::CreateFileDecoder(const wxString & fileName)
|
||||
cnt = binaryFile.Read(query, sizeof(query));
|
||||
cnt = id3_tag_query(query, cnt);
|
||||
binaryFile.Seek(cnt);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char buf[5];
|
||||
cnt = binaryFile.Read(buf, 4);
|
||||
@@ -298,9 +298,9 @@ ODFileDecoder* ODDecodeFlacTask::CreateFileDecoder(const wxString & fileName)
|
||||
|
||||
if (cnt == wxInvalidOffset || strncmp(buf, FLAC_HEADER, 4) != 0) {
|
||||
// File is not a FLAC file
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Open the file for import
|
||||
ODFlacDecoder *decoder = new ODFlacDecoder(fileName);
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
This is an abstract class that subclasses will have to derive the types
|
||||
from. For any type there should only be one ODDecodeTask associated with
|
||||
a given track.
|
||||
a given track.
|
||||
There could be the ODBlockFiles of several FLACs in one track (after copy and pasting),
|
||||
so things aren't as simple as they seem - the implementation needs to be
|
||||
robust enough to allow all the user changes such as copy/paste, delete, and so on.
|
||||
@@ -49,13 +49,13 @@ class ODDecodeFlacTask:public ODDecodeTask
|
||||
/// Constructs an ODTask
|
||||
ODDecodeFlacTask(){}
|
||||
virtual ~ODDecodeFlacTask();
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ODTask* Clone();
|
||||
///Creates an ODFileDecoder that decodes a file of filetype the subclass handles.
|
||||
virtual ODFileDecoder* CreateFileDecoder(const wxString & fileName);
|
||||
|
||||
///Lets other classes know that this class handles flac
|
||||
|
||||
///Lets other classes know that this class handles flac
|
||||
///Subclasses should override to return respective type.
|
||||
virtual unsigned int GetODType(){return eODFLAC;}
|
||||
};
|
||||
@@ -71,7 +71,7 @@ class ODFLACFile : public FLAC::Decoder::File
|
||||
set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
set_metadata_respond(FLAC__METADATA_TYPE_STREAMINFO);
|
||||
}
|
||||
|
||||
|
||||
bool get_was_error() const
|
||||
{
|
||||
return mWasError;
|
||||
@@ -81,7 +81,7 @@ class ODFLACFile : public FLAC::Decoder::File
|
||||
ODFlacDecoder *mDecoder;
|
||||
bool mWasError;
|
||||
wxArrayString mComments;
|
||||
|
||||
|
||||
protected:
|
||||
virtual FLAC__StreamDecoderWriteStatus write_callback(const FLAC__Frame *frame,
|
||||
const FLAC__int32 * const buffer[]);
|
||||
@@ -98,20 +98,20 @@ public:
|
||||
///This should handle unicode converted to UTF-8 on mac/linux, but OD TODO:check on windows
|
||||
ODFlacDecoder(const wxString & fileName):ODFileDecoder(fileName),mSamplesDone(0){mFile=NULL;}
|
||||
virtual ~ODFlacDecoder();
|
||||
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
///This is file specific, so subclasses must implement this only.
|
||||
///the buffer was defined like
|
||||
///samplePtr sampleData = NewSamples(mLen, floatSample);
|
||||
///this->ReadData(sampleData, floatSample, 0, mLen);
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
///This class should call ReadHeader() first, so it knows the length, and can prepare
|
||||
///the file object if it needs to.
|
||||
virtual int Decode(samplePtr & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel);
|
||||
|
||||
|
||||
|
||||
///Read header. Subclasses must override. Probably should save the info somewhere.
|
||||
///Ideally called once per decoding of a file. This complicates the task because
|
||||
virtual bool ReadHeader();
|
||||
///Ideally called once per decoding of a file. This complicates the task because
|
||||
virtual bool ReadHeader();
|
||||
|
||||
///FLAC specific file (inherited from FLAC::Decoder::File)
|
||||
ODFLACFile* GetFlacFile();
|
||||
|
||||
@@ -26,9 +26,9 @@ ODDecodeTask::ODDecodeTask()
|
||||
mMaxBlockFiles = 0;
|
||||
mComputedBlockFiles = 0;
|
||||
}
|
||||
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
void ODDecodeTask::DoSomeInternal()
|
||||
{
|
||||
if(mBlockFiles.size()<=0)
|
||||
@@ -38,20 +38,20 @@ void ODDecodeTask::DoSomeInternal()
|
||||
mPercentCompleteMutex.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ODDecodeBlockFile* bf;
|
||||
ODFileDecoder* decoder;
|
||||
sampleCount blockStartSample = 0;
|
||||
sampleCount blockEndSample = 0;
|
||||
bool success =false;
|
||||
|
||||
|
||||
for(size_t i=0; i < mWaveTracks.size() && mBlockFiles.size();i++)
|
||||
{
|
||||
bf = mBlockFiles[0];
|
||||
|
||||
|
||||
int ret = 1;
|
||||
|
||||
//first check to see if the ref count is at least 2. It should have one
|
||||
|
||||
//first check to see if the ref count is at least 2. It should have one
|
||||
//from when we added it to this instance's mBlockFiles array, and one from
|
||||
//the Wavetrack/sequence. If it doesn't it has been deleted and we should forget it.
|
||||
if(bf->RefCount()>=2)
|
||||
@@ -67,7 +67,7 @@ void ODDecodeTask::DoSomeInternal()
|
||||
bf->SetODFileDecoder(decoder);
|
||||
ret = bf->DoWriteBlockFile();
|
||||
bf->UnlockRead();
|
||||
|
||||
|
||||
if(ret >= 0) {
|
||||
success = true;
|
||||
blockStartSample = bf->GetStart();
|
||||
@@ -81,13 +81,13 @@ void ODDecodeTask::DoSomeInternal()
|
||||
//because now there is less work to do.
|
||||
mMaxBlockFiles--;
|
||||
}
|
||||
|
||||
|
||||
//Release the refcount we placed on it if we are successful
|
||||
if(ret >= 0 ) {
|
||||
bf->Deref();
|
||||
//take it out of the array - we are done with it.
|
||||
mBlockFiles.erase(mBlockFiles.begin());
|
||||
|
||||
|
||||
//upddate the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should
|
||||
//because this loop runs a number of times equal to the number of tracks, they probably are getting processed in
|
||||
//the next iteration at the same sample window.
|
||||
@@ -99,8 +99,8 @@ void ODDecodeTask::DoSomeInternal()
|
||||
}
|
||||
mWaveTrackMutex.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//update percentage complete.
|
||||
CalculatePercentComplete();
|
||||
}
|
||||
@@ -112,7 +112,7 @@ void ODDecodeTask::CalculatePercentComplete()
|
||||
mPercentCompleteMutex.Unlock();
|
||||
}
|
||||
|
||||
bool ODDecodeTask::SeekingAllowed()
|
||||
bool ODDecodeTask::SeekingAllowed()
|
||||
{
|
||||
for (unsigned int i = 0; i < mDecoders.size(); i++) {
|
||||
if(!mDecoders[i]->SeekingAllowed())
|
||||
@@ -126,9 +126,9 @@ void ODDecodeTask::Update()
|
||||
{
|
||||
|
||||
std::vector<ODDecodeBlockFile*> tempBlocks;
|
||||
|
||||
|
||||
mWaveTrackMutex.Lock();
|
||||
|
||||
|
||||
for(size_t j=0;j<mWaveTracks.size();j++)
|
||||
{
|
||||
if(mWaveTracks[j])
|
||||
@@ -136,21 +136,21 @@ void ODDecodeTask::Update()
|
||||
WaveClip *clip;
|
||||
BlockArray *blocks;
|
||||
Sequence *seq;
|
||||
|
||||
|
||||
//gather all the blockfiles that we should process in the wavetrack.
|
||||
WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();
|
||||
|
||||
|
||||
while(node) {
|
||||
clip = node->GetData();
|
||||
seq = clip->GetSequence();
|
||||
//TODO:this lock is way to big since the whole file is one sequence. find a way to break it down.
|
||||
seq->LockDeleteUpdateMutex();
|
||||
|
||||
|
||||
//See Sequence::Delete() for why need this for now..
|
||||
blocks = clip->GetSequenceBlockArray();
|
||||
int i;
|
||||
int insertCursor;
|
||||
|
||||
|
||||
insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
|
||||
for(i=0; i<(int)blocks->GetCount(); i++)
|
||||
{
|
||||
@@ -160,24 +160,24 @@ void ODDecodeTask::Update()
|
||||
blocks->Item(i)->f->Ref();
|
||||
((ODDecodeBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start);
|
||||
((ODDecodeBlockFile*)blocks->Item(i)->f)->SetClipOffset((sampleCount)(clip->GetStartTime()*clip->GetRate()));
|
||||
|
||||
|
||||
//these will always be linear within a sequence-lets take advantage of this by keeping a cursor.
|
||||
while(insertCursor<(int)tempBlocks.size()&&
|
||||
(sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) <
|
||||
while(insertCursor<(int)tempBlocks.size()&&
|
||||
(sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) <
|
||||
(sampleCount)(((ODDecodeBlockFile*)blocks->Item(i)->f)->GetStart()+((ODDecodeBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
|
||||
insertCursor++;
|
||||
|
||||
|
||||
tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODDecodeBlockFile*)blocks->Item(i)->f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
seq->UnlockDeleteUpdateMutex();
|
||||
node = node->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
mWaveTrackMutex.Unlock();
|
||||
|
||||
|
||||
//get the new order.
|
||||
OrderBlockFiles(tempBlocks);
|
||||
}
|
||||
@@ -194,23 +194,23 @@ void ODDecodeTask::OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlo
|
||||
//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
|
||||
//(which the user sets by clicking.) note that this code is pretty hacky - it assumes that the array is sorted in time.
|
||||
|
||||
|
||||
//find the startpoint
|
||||
sampleCount processStartSample = GetDemandSample();
|
||||
sampleCount processStartSample = GetDemandSample();
|
||||
for(int i= ((int)unorderedBlocks.size())-1;i>= 0;i--)
|
||||
{
|
||||
//check to see if the refcount is at least two before we add it to the list.
|
||||
//There should be one Ref() from the one added by this ODTask, and one from the track.
|
||||
//There should be one Ref() from the one added by this ODTask, and one from the track.
|
||||
//If there isn't, then the block was deleted for some reason and we should ignore it.
|
||||
if(unorderedBlocks[i]->RefCount()>=2)
|
||||
{
|
||||
//test if the blockfiles are near the task cursor. we use the last mBlockFiles[0] as our point of reference
|
||||
//and add ones that are closer.
|
||||
//and add ones that are closer.
|
||||
//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 ||
|
||||
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
|
||||
@@ -230,11 +230,11 @@ void ODDecodeTask::OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlo
|
||||
unorderedBlocks[i]->Deref();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///changes the tasks associated with this Waveform to process the task from a different point in the track
|
||||
///this is overridden from ODTask because certain classes don't allow users to seek sometimes, or not at all.
|
||||
void ODDecodeTask::DemandTrackUpdate(WaveTrack* track, double seconds)
|
||||
@@ -266,7 +266,7 @@ ODFileDecoder* ODDecodeTask::GetOrCreateMatchingFileDecoder(ODDecodeBlockFile* b
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//otherwise, create and add one, and return it.
|
||||
if(!ret)
|
||||
{
|
||||
@@ -297,7 +297,7 @@ bool ODFileDecoder::IsInitialized()
|
||||
bool ret;
|
||||
mInitedLock.Lock();
|
||||
ret = mInited;
|
||||
mInitedLock.Unlock();
|
||||
mInitedLock.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -306,6 +306,6 @@ void ODFileDecoder::MarkInitialized()
|
||||
{
|
||||
mInitedLock.Lock();
|
||||
mInited=true;
|
||||
mInitedLock.Unlock();
|
||||
mInitedLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
This is an abstract class that subclasses will have to derive the types
|
||||
from. For any type there should only be one ODDecodeTask associated with
|
||||
a given track.
|
||||
a given track.
|
||||
There could be the ODBlockFiles of several FLACs in one track (after copy and pasting),
|
||||
so things aren't as simple as they seem - the implementation needs to be
|
||||
robust enough to allow all the user changes such as copy/paste, delete, and so on.
|
||||
@@ -42,26 +42,26 @@ class ODDecodeTask:public ODTask
|
||||
public:
|
||||
ODDecodeTask();
|
||||
virtual ~ODDecodeTask(){};
|
||||
|
||||
|
||||
virtual ODTask* Clone()=0;
|
||||
|
||||
|
||||
virtual bool SeekingAllowed();
|
||||
|
||||
|
||||
///changes the tasks associated with this Waveform to process the task from a different point in the track
|
||||
///this is overridden from ODTask because certain classes don't allow users to seek sometimes, or not at all.
|
||||
virtual void DemandTrackUpdate(WaveTrack* track, double seconds);
|
||||
|
||||
|
||||
///Return the task name
|
||||
virtual const char* GetTaskName(){return "ODDecodeTask";}
|
||||
|
||||
|
||||
virtual const wxChar* GetTip(){return _("Decoding Waveform");}
|
||||
|
||||
|
||||
///Subclasses should override to return respective type.
|
||||
virtual unsigned int GetODType(){return eODNone;}
|
||||
|
||||
|
||||
///Creates an ODFileDecoder that decodes a file of filetype the subclass handles.
|
||||
virtual ODFileDecoder* CreateFileDecoder(const wxString & fileName)=0;
|
||||
|
||||
|
||||
///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.
|
||||
///Blocks that have IsDataAvailable()==false are blockfiles to be decoded. if BlockFile::GetDecodeType()==ODDecodeTask::GetODType() then
|
||||
@@ -69,27 +69,27 @@ class ODDecodeTask:public ODTask
|
||||
///be called from the decoding thread.
|
||||
virtual ODFileDecoder* GetOrCreateMatchingFileDecoder(ODDecodeBlockFile* blockFile);
|
||||
virtual int GetNumFileDecoders();
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
///recalculates the percentage complete.
|
||||
virtual void CalculatePercentComplete();
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
|
||||
///Computes and writes the data for one BlockFile if it still has a refcount.
|
||||
virtual void DoSomeInternal();
|
||||
|
||||
|
||||
///Readjusts the blockfile order in the default manner. If we have had an ODRequest
|
||||
///Then it updates in the OD manner.
|
||||
virtual void Update();
|
||||
|
||||
|
||||
///Orders the input as either On-Demand or default layered order.
|
||||
void OrderBlockFiles(std::vector<ODDecodeBlockFile*> &unorderedBlocks);
|
||||
|
||||
|
||||
|
||||
std::vector<ODDecodeBlockFile*> mBlockFiles;
|
||||
std::vector<ODFileDecoder*> mDecoders;
|
||||
|
||||
|
||||
int mMaxBlockFiles;
|
||||
int mComputedBlockFiles;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ in a background thread.
|
||||
#include "../WaveTrack.h"
|
||||
#include "../Project.h"
|
||||
//temporarilly commented out till it is added to all projects
|
||||
//#include "../Profiler.h"
|
||||
//#include "../Profiler.h"
|
||||
|
||||
|
||||
DEFINE_EVENT_TYPE(EVT_ODTASK_COMPLETE)
|
||||
@@ -38,30 +38,30 @@ ODTask::ODTask()
|
||||
mTerminate = false;
|
||||
mNeedsODUpdate=false;
|
||||
mIsRunning = false;
|
||||
|
||||
|
||||
mTaskNumber=sTaskNumber++;
|
||||
|
||||
|
||||
mDemandSample=0;
|
||||
}
|
||||
|
||||
//outside code must ensure this task is not scheduled again.
|
||||
void ODTask::TerminateAndBlock()
|
||||
{
|
||||
{
|
||||
//one mutex pair for the value of mTerminate
|
||||
mTerminateMutex.Lock();
|
||||
mTerminate=true;
|
||||
//release all data the derived class may have allocated
|
||||
mTerminateMutex.Unlock();
|
||||
|
||||
|
||||
//and one mutex pair for the exit of the function
|
||||
mBlockUntilTerminateMutex.Lock();
|
||||
//TODO lock mTerminate?
|
||||
mBlockUntilTerminateMutex.Unlock();
|
||||
|
||||
//wait till we are out of doSome() to terminate.
|
||||
|
||||
//wait till we are out of doSome() to terminate.
|
||||
Terminate();
|
||||
}
|
||||
|
||||
|
||||
///Do a modular part of the task. For example, if the task is to load the entire file, load one BlockFile.
|
||||
///Relies on DoSomeInternal(), which is the subclasses must implement.
|
||||
///@param amountWork the percent amount of the total job to do. 1.0 represents the entire job. the default of 0.0
|
||||
@@ -74,11 +74,11 @@ void ODTask::DoSome(float amountWork)
|
||||
// printf("%s %i subtask starting on new thread with priority\n", GetTaskName(),GetTaskNumber());
|
||||
|
||||
mDoingTask=mTaskStarted=true;
|
||||
|
||||
|
||||
float workUntil = amountWork+PercentComplete();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//check periodically to see if we should exit.
|
||||
mTerminateMutex.Lock();
|
||||
if(mTerminate)
|
||||
@@ -87,45 +87,45 @@ void ODTask::DoSome(float amountWork)
|
||||
SetIsRunning(false);
|
||||
mBlockUntilTerminateMutex.Unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mTerminateMutex.Unlock();
|
||||
|
||||
Update();
|
||||
|
||||
|
||||
Update();
|
||||
|
||||
|
||||
if(UsesCustomWorkUntilPercentage())
|
||||
workUntil = ComputeNextWorkUntilPercentageComplete();
|
||||
|
||||
|
||||
if(workUntil<PercentComplete())
|
||||
workUntil = PercentComplete();
|
||||
|
||||
|
||||
//Do Some of the task.
|
||||
|
||||
|
||||
mTerminateMutex.Lock();
|
||||
while(PercentComplete() < workUntil && PercentComplete() < 1.0 && !mTerminate)
|
||||
{
|
||||
wxThread::This()->Yield();
|
||||
//release within the loop so we can cut the number of iterations short
|
||||
|
||||
|
||||
DoSomeInternal(); //keep the terminate mutex on so we don't remo
|
||||
mTerminateMutex.Unlock();
|
||||
mTerminateMutex.Unlock();
|
||||
//check to see if ondemand has been called
|
||||
if(GetNeedsODUpdate() && PercentComplete() < 1.0)
|
||||
ODUpdate();
|
||||
|
||||
|
||||
|
||||
|
||||
//But add the mutex lock back before we check the value again.
|
||||
mTerminateMutex.Lock();
|
||||
}
|
||||
mTerminateMutex.Unlock();
|
||||
mDoingTask=false;
|
||||
|
||||
|
||||
mTerminateMutex.Lock();
|
||||
//if it is not done, put it back onto the ODManager queue.
|
||||
if(PercentComplete() < 1.0&& !mTerminate)
|
||||
{
|
||||
ODManager::Instance()->AddTask(this);
|
||||
|
||||
|
||||
//we did a bit of progress - we should allow a resave.
|
||||
AudacityProject::AllProjectsDeleteLock();
|
||||
for(unsigned i=0; i<gAudacityProjects.GetCount(); i++)
|
||||
@@ -139,7 +139,7 @@ void ODTask::DoSome(float amountWork)
|
||||
}
|
||||
AudacityProject::AllProjectsDeleteUnlock();
|
||||
|
||||
|
||||
|
||||
// printf("%s %i is %f done\n", GetTaskName(),GetTaskNumber(),PercentComplete());
|
||||
}
|
||||
else
|
||||
@@ -148,16 +148,16 @@ void ODTask::DoSome(float amountWork)
|
||||
//static int tempLog =0;
|
||||
//if(++tempLog % 5==0)
|
||||
//END_TASK_PROFILING("On Demand Drag and Drop 5 80 mb files into audacity, 5 wavs per task");
|
||||
//END_TASK_PROFILING("On Demand open an 80 mb wav stereo file");
|
||||
|
||||
//END_TASK_PROFILING("On Demand open an 80 mb wav stereo file");
|
||||
|
||||
wxCommandEvent event( EVT_ODTASK_COMPLETE );
|
||||
AudacityProject::AllProjectsDeleteLock();
|
||||
|
||||
|
||||
for(unsigned i=0; i<gAudacityProjects.GetCount(); i++)
|
||||
{
|
||||
if(IsTaskAssociatedWithProject(gAudacityProjects[i]))
|
||||
{
|
||||
//this assumes tasks are only associated with one project.
|
||||
//this assumes tasks are only associated with one project.
|
||||
gAudacityProjects[i]->AddPendingEvent( event );
|
||||
//mark the changes so that the project can be resaved.
|
||||
gAudacityProjects[i]->GetUndoManager()->SetODChangesFlag();
|
||||
@@ -179,10 +179,10 @@ bool ODTask::IsTaskAssociatedWithProject(AudacityProject* proj)
|
||||
TrackListIterator iter1(tracks);
|
||||
Track *tr = iter1.First();
|
||||
|
||||
while (tr)
|
||||
while (tr)
|
||||
{
|
||||
//go over all tracks in the project
|
||||
if (tr->GetKind() == Track::Wave)
|
||||
if (tr->GetKind() == Track::Wave)
|
||||
{
|
||||
//look inside our task's track list for one that matches this projects one.
|
||||
mWaveTrackMutex.Lock();
|
||||
@@ -199,7 +199,7 @@ bool ODTask::IsTaskAssociatedWithProject(AudacityProject* proj)
|
||||
}
|
||||
tr = iter1.Next();
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -216,7 +216,7 @@ void ODTask::SetIsRunning(bool value)
|
||||
mIsRunning=value;
|
||||
mIsRunningMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
bool ODTask::IsRunning()
|
||||
{
|
||||
bool ret;
|
||||
@@ -224,8 +224,8 @@ bool ODTask::IsRunning()
|
||||
ret= mIsRunning;
|
||||
mIsRunningMutex.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sampleCount ODTask::GetDemandSample()
|
||||
{
|
||||
sampleCount retval;
|
||||
@@ -234,16 +234,16 @@ sampleCount ODTask::GetDemandSample()
|
||||
mDemandSampleMutex.Unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void ODTask::SetDemandSample(sampleCount sample)
|
||||
{
|
||||
|
||||
|
||||
mDemandSampleMutex.Lock();
|
||||
mDemandSample=sample;
|
||||
mDemandSampleMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///return the amount of the task that has been completed. 0.0 to 1.0
|
||||
float ODTask::PercentComplete()
|
||||
{
|
||||
@@ -252,8 +252,8 @@ float ODTask::PercentComplete()
|
||||
mPercentCompleteMutex.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
///return
|
||||
|
||||
///return
|
||||
bool ODTask::IsComplete()
|
||||
{
|
||||
return PercentComplete() >= 1.0 && !IsRunning();
|
||||
@@ -319,7 +319,7 @@ void ODTask::RecalculatePercentComplete()
|
||||
CalculatePercentComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///changes the tasks associated with this Waveform to process the task from a different point in the track
|
||||
///@param track the track to update
|
||||
///@param seconds the point in the track from which the tasks associated with track should begin processing from.
|
||||
@@ -330,18 +330,18 @@ void ODTask::DemandTrackUpdate(WaveTrack* track, double seconds)
|
||||
for(size_t i=0;i<mWaveTracks.size();i++)
|
||||
{
|
||||
if(track == mWaveTracks[i])
|
||||
{
|
||||
{
|
||||
sampleCount newDemandSample = (sampleCount)(seconds * track->GetRate());
|
||||
demandSampleChanged = newDemandSample != GetDemandSample();
|
||||
SetDemandSample(newDemandSample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mWaveTrackMutex.Unlock();
|
||||
|
||||
|
||||
if(demandSampleChanged)
|
||||
SetNeedsODUpdate();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,6 @@ void ODTask::ReplaceWaveTrack(WaveTrack* oldTrack,WaveTrack* newTrack)
|
||||
{
|
||||
mWaveTracks[i] = newTrack;
|
||||
}
|
||||
}
|
||||
}
|
||||
mWaveTrackMutex.Unlock();
|
||||
}
|
||||
|
||||
@@ -50,73 +50,73 @@ class ODTask
|
||||
|
||||
/// Constructs an ODTask
|
||||
ODTask();
|
||||
|
||||
|
||||
virtual ~ODTask(){};
|
||||
|
||||
|
||||
//clones everything except information about the tracks.
|
||||
virtual ODTask* Clone()=0;
|
||||
|
||||
|
||||
///Subclasses should override to return respective type.
|
||||
virtual unsigned int GetODType(){return eODNone;}
|
||||
|
||||
|
||||
|
||||
///Do a modular part of the task. For example, if the task is to load the entire file, load one BlockFile.
|
||||
///Relies on DoSomeInternal(), which is the subclasses must implement.
|
||||
///@param amountWork the percent amount of the total job to do. 1.0 represents the entire job. the default of 0.0
|
||||
/// will do the smallest unit of work possible
|
||||
void DoSome(float amountWork=0.0);
|
||||
|
||||
|
||||
///Call DoSome until PercentComplete >= 1.0
|
||||
void DoAll();
|
||||
|
||||
|
||||
virtual float PercentComplete();
|
||||
|
||||
|
||||
virtual bool UsesCustomWorkUntilPercentage(){return false;}
|
||||
virtual float ComputeNextWorkUntilPercentageComplete(){return 1.0;}
|
||||
|
||||
|
||||
///returns whether or not this task and another task can merge together, as when we make two mono tracks stereo.
|
||||
///for Loading/Summarizing, this is not an issue because the entire track is processed
|
||||
///Effects that affect portions of a track will need to check this.
|
||||
virtual bool CanMergeWith(ODTask* otherTask){return strcmp(GetTaskName(),otherTask->GetTaskName())==0;}
|
||||
|
||||
virtual bool CanMergeWith(ODTask* otherTask){return strcmp(GetTaskName(),otherTask->GetTaskName())==0;}
|
||||
|
||||
virtual void StopUsingWaveTrack(WaveTrack* track);
|
||||
|
||||
|
||||
///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.
|
||||
virtual void ReplaceWaveTrack(WaveTrack* oldTrack,WaveTrack* newTrack);
|
||||
|
||||
|
||||
///Adds a WaveTrack to do the task for
|
||||
void AddWaveTrack(WaveTrack* track);
|
||||
virtual int GetNumWaveTracks();
|
||||
virtual WaveTrack* GetWaveTrack(int i);
|
||||
|
||||
|
||||
///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);
|
||||
|
||||
|
||||
bool IsComplete();
|
||||
|
||||
|
||||
void TerminateAndBlock();
|
||||
///releases memory that the ODTask owns. Subclasses should override.
|
||||
virtual void Terminate(){}
|
||||
|
||||
|
||||
virtual const char* GetTaskName(){return "ODTask";}
|
||||
|
||||
|
||||
virtual sampleCount GetDemandSample();
|
||||
|
||||
|
||||
virtual void SetDemandSample(sampleCount sample);
|
||||
|
||||
|
||||
///does an od update and then recalculates the data.
|
||||
virtual void RecalculatePercentComplete();
|
||||
|
||||
|
||||
///returns the number of tasks created before this instance.
|
||||
int GetTaskNumber(){return mTaskNumber;}
|
||||
|
||||
|
||||
void SetNeedsODUpdate();
|
||||
bool GetNeedsODUpdate();
|
||||
void ResetNeedsODUpdate();
|
||||
|
||||
|
||||
virtual const wxChar* GetTip()=0;
|
||||
|
||||
|
||||
///returns true if the task is associated with the project.
|
||||
virtual bool IsTaskAssociatedWithProject(AudacityProject* proj);
|
||||
|
||||
@@ -124,26 +124,26 @@ class ODTask
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
///calculates the percentage complete from existing data.
|
||||
virtual void CalculatePercentComplete() = 0;
|
||||
|
||||
///pure virtual function that does some part of the task this object represents.
|
||||
///this function is meant to be called repeatedly until the IsComplete is true.
|
||||
virtual void CalculatePercentComplete() = 0;
|
||||
|
||||
///pure virtual function that does some part of the task this object represents.
|
||||
///this function is meant to be called repeatedly until the IsComplete is true.
|
||||
///Does the smallest unit of work for this task.
|
||||
virtual void DoSomeInternal() = 0;
|
||||
|
||||
|
||||
///virtual method called before DoSomeInternal is used from DoSome.
|
||||
virtual void Update(){}
|
||||
|
||||
|
||||
///virtual method called in DoSome everytime the user has demanded some OD function so that the
|
||||
///ODTask can readjust its computation order. By default just calls Update(), but subclasses with
|
||||
///special needs can override this
|
||||
virtual void ODUpdate();
|
||||
|
||||
|
||||
void SetIsRunning(bool value);
|
||||
|
||||
|
||||
|
||||
|
||||
int mTaskNumber;
|
||||
volatile float mPercentComplete;
|
||||
@@ -154,23 +154,23 @@ class ODTask
|
||||
ODLock mTerminateMutex;
|
||||
//for a function not a member var.
|
||||
ODLock mBlockUntilTerminateMutex;
|
||||
|
||||
|
||||
std::vector<WaveTrack*> mWaveTracks;
|
||||
ODLock mWaveTrackMutex;
|
||||
|
||||
|
||||
volatile sampleCount mDemandSample;
|
||||
ODLock mDemandSampleMutex;
|
||||
|
||||
|
||||
volatile bool mIsRunning;
|
||||
ODLock mIsRunningMutex;
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
volatile bool mNeedsODUpdate;
|
||||
ODLock mNeedsODUpdateMutex;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
ODTaskThread.cpp
|
||||
|
||||
|
||||
Created by Michael Chinen (mchinen) on 6/8/08
|
||||
Audacity(R) is copyright (c) 1999-2008 Audacity Team.
|
||||
License: GPL v2. See License.txt.
|
||||
@@ -28,16 +28,16 @@ ODTaskThread::ODTaskThread(ODTask* task)
|
||||
{
|
||||
mTask=task;
|
||||
#ifdef __WXMAC__
|
||||
mDestroy = false;
|
||||
mDestroy = false;
|
||||
mThread = NULL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef __WXMAC__
|
||||
|
||||
|
||||
void ODTaskThread::Entry()
|
||||
#else
|
||||
#else
|
||||
void *ODTaskThread::Entry()
|
||||
|
||||
#endif
|
||||
@@ -46,11 +46,11 @@ void *ODTaskThread::Entry()
|
||||
//wxThread::This()->SetPriority( 40);
|
||||
//Do at least 5 percent of the task
|
||||
mTask->DoSome(0.05f);
|
||||
|
||||
|
||||
//release the thread count so that the ODManager knows how many active threads are alive.
|
||||
ODManager::Instance()->DecrementCurrentThreads();
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __WXMAC__
|
||||
return NULL;
|
||||
#endif
|
||||
@@ -65,7 +65,7 @@ ODCondition::ODCondition(ODLock *lock)
|
||||
}
|
||||
ODCondition::~ODCondition()
|
||||
{
|
||||
pthread_cond_destroy (condition);
|
||||
pthread_cond_destroy (condition);
|
||||
free(condition);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ void ODCondition::Signal()
|
||||
{
|
||||
pthread_cond_signal(condition);
|
||||
}
|
||||
|
||||
|
||||
void ODCondition::Broadcast()
|
||||
{
|
||||
pthread_cond_broadcast(condition);
|
||||
@@ -82,7 +82,6 @@ void ODCondition::Wait()
|
||||
{
|
||||
pthread_cond_wait(condition,m_lock->mutex);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
ODTaskThread.h
|
||||
|
||||
|
||||
Created by Michael Chinen (mchinen) on 6/8/08
|
||||
Audacity(R) is copyright (c) 1999-2008 Audacity Team.
|
||||
License: GPL v2. See License.txt.
|
||||
@@ -64,7 +64,7 @@ class ODTaskThread {
|
||||
void Run() {
|
||||
pthread_create(&mThread, NULL, callback, this);
|
||||
}
|
||||
|
||||
|
||||
///Specifies the priority the thread will run at. Currently doesn't work.
|
||||
///@param priority value from 0 (min priority) to 100 (max priority)
|
||||
void SetPriority(int priority)
|
||||
@@ -86,7 +86,7 @@ class ODLock {
|
||||
mutex = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
|
||||
pthread_mutex_init (mutex, NULL);
|
||||
}
|
||||
|
||||
|
||||
void Lock()
|
||||
{
|
||||
pthread_mutex_lock (mutex);
|
||||
@@ -96,19 +96,19 @@ class ODLock {
|
||||
{
|
||||
pthread_mutex_unlock (mutex);
|
||||
}
|
||||
|
||||
|
||||
virtual ~ODLock()
|
||||
{
|
||||
pthread_mutex_destroy (mutex);
|
||||
pthread_mutex_destroy (mutex);
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class ODCondition; //needs friendship for wait()
|
||||
pthread_mutex_t *mutex ;
|
||||
};
|
||||
|
||||
class ODCondition
|
||||
class ODCondition
|
||||
{
|
||||
public:
|
||||
ODCondition(ODLock *lock);
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
void Wait();
|
||||
|
||||
|
||||
protected:
|
||||
pthread_cond_t *condition;
|
||||
ODLock* m_lock;
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
//void Signal();
|
||||
//void Broadcast();
|
||||
//void Wait();
|
||||
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ tasks associated with a WaveTrack.
|
||||
ODWaveTrackTaskQueue::ODWaveTrackTaskQueue()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ODWaveTrackTaskQueue::~ODWaveTrackTaskQueue()
|
||||
{
|
||||
//we need to delete all ODTasks. We will have to block or wait until block for the active ones.
|
||||
@@ -34,7 +34,7 @@ ODWaveTrackTaskQueue::~ODWaveTrackTaskQueue()
|
||||
ODManager::Instance()->RemoveTaskIfInQueue(mTasks[i]);
|
||||
delete mTasks[i];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
///returns whether or not this queue's task list and another's can merge together, as when we make two mono tracks stereo.
|
||||
@@ -43,7 +43,7 @@ bool ODWaveTrackTaskQueue::CanMergeWith(ODWaveTrackTaskQueue* otherQueue)
|
||||
//have to be very careful when dealing with two lists that need to be locked.
|
||||
if(GetNumTasks()!=otherQueue->GetNumTasks())
|
||||
return false;
|
||||
|
||||
|
||||
mTasksMutex.Lock();
|
||||
for(unsigned int i=0;i<mTasks.size();i++)
|
||||
{
|
||||
@@ -88,15 +88,15 @@ bool ODWaveTrackTaskQueue::ContainsWaveTrack(WaveTrack* track)
|
||||
}
|
||||
mTracksMutex.Unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
///Adds a track to the associated list.
|
||||
void ODWaveTrackTaskQueue::AddWaveTrack(WaveTrack* track)
|
||||
{
|
||||
|
||||
|
||||
mTracksMutex.Lock();
|
||||
if(track)
|
||||
mTracks.push_back(track);
|
||||
|
||||
|
||||
mTracksMutex.Unlock();
|
||||
}
|
||||
|
||||
@@ -105,18 +105,18 @@ void ODWaveTrackTaskQueue::AddTask(ODTask* task)
|
||||
mTasksMutex.Lock();
|
||||
mTasks.push_back(task);
|
||||
mTasksMutex.Unlock();
|
||||
|
||||
//take all of the tracks in the task.
|
||||
|
||||
//take all of the tracks in the task.
|
||||
mTracksMutex.Lock();
|
||||
for(int i=0;i<task->GetNumWaveTracks();i++)
|
||||
{
|
||||
//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,
|
||||
//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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mTracksMutex.Unlock();
|
||||
|
||||
}
|
||||
@@ -127,22 +127,22 @@ 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)
|
||||
{
|
||||
|
||||
@@ -153,14 +153,14 @@ void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track)
|
||||
mTracksMutex.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for(unsigned int i=0;i<mTracks.size();i++)
|
||||
{
|
||||
if(mTracks[i]==track)
|
||||
{
|
||||
mTracksMutex.Unlock();//release the lock, since RemoveWaveTrack is a public threadsafe method.
|
||||
RemoveWaveTrack(mTracks[i]);
|
||||
|
||||
|
||||
//clone the items in order and add them to the ODManager.
|
||||
mTasksMutex.Lock();
|
||||
ODTask* task;
|
||||
@@ -170,7 +170,7 @@ void ODWaveTrackTaskQueue::MakeWaveTrackIndependent(WaveTrack* track)
|
||||
task->AddWaveTrack(track);
|
||||
//AddNewTask requires us to relinquish this lock. However, it is safe because ODManager::MakeWaveTrackIndependent
|
||||
//has already locked the m_queuesMutex.
|
||||
mTasksMutex.Unlock();
|
||||
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);
|
||||
@@ -196,7 +196,7 @@ void ODWaveTrackTaskQueue::DemandTrackUpdate(WaveTrack* track, double seconds)
|
||||
{
|
||||
mTasks[i]->DemandTrackUpdate(track,seconds);
|
||||
}
|
||||
|
||||
|
||||
mTracksMutex.Unlock();
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ void ODWaveTrackTaskQueue::ReplaceWaveTrack(WaveTrack* oldTrack, WaveTrack* newT
|
||||
for(unsigned int i=0;i<mTasks.size();i++)
|
||||
mTasks[i]->ReplaceWaveTrack(oldTrack,newTrack);
|
||||
mTasksMutex.Unlock();
|
||||
|
||||
|
||||
mTracksMutex.Lock();
|
||||
for(unsigned int i=0;i<mTracks.size();i++)
|
||||
if(mTracks[i]==oldTrack)
|
||||
@@ -250,7 +250,7 @@ int ODWaveTrackTaskQueue::GetNumTasks()
|
||||
mTasksMutex.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
///returns a ODTask at position x
|
||||
ODTask* ODWaveTrackTaskQueue::GetTask(size_t x)
|
||||
{
|
||||
@@ -261,8 +261,8 @@ ODTask* ODWaveTrackTaskQueue::GetTask(size_t x)
|
||||
mTasksMutex.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//returns true if either tracks or tasks are empty
|
||||
bool ODWaveTrackTaskQueue::IsEmpty()
|
||||
@@ -271,14 +271,14 @@ bool ODWaveTrackTaskQueue::IsEmpty()
|
||||
mTracksMutex.Lock();
|
||||
isEmpty = mTracks.size()<=0;
|
||||
mTracksMutex.Unlock();
|
||||
|
||||
|
||||
mTasksMutex.Lock();
|
||||
isEmpty = isEmpty || mTasks.size()<=0;
|
||||
isEmpty = isEmpty || mTasks.size()<=0;
|
||||
mTasksMutex.Unlock();
|
||||
|
||||
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
|
||||
//returns true if the foremost task exists and is empty.
|
||||
bool ODWaveTrackTaskQueue::IsFrontTaskComplete()
|
||||
{
|
||||
@@ -288,16 +288,16 @@ bool ODWaveTrackTaskQueue::IsFrontTaskComplete()
|
||||
//there is a chance the task got updated and now has more to do, (like when it is joined with a new track)
|
||||
//check.
|
||||
mTasks[0]->RecalculatePercentComplete();
|
||||
bool ret;
|
||||
bool ret;
|
||||
ret = mTasks[0]->IsComplete();
|
||||
mTasksMutex.Unlock();
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
mTasksMutex.Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///Removes and deletes the front task from the list.
|
||||
void ODWaveTrackTaskQueue::RemoveFrontTask()
|
||||
{
|
||||
@@ -310,7 +310,7 @@ void ODWaveTrackTaskQueue::RemoveFrontTask()
|
||||
}
|
||||
mTasksMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
///gets the front task for immediate execution
|
||||
ODTask* ODWaveTrackTaskQueue::GetFrontTask()
|
||||
{
|
||||
@@ -329,13 +329,13 @@ void ODWaveTrackTaskQueue::FillTipForWaveTrack( WaveTrack * t, const wxChar ** p
|
||||
{
|
||||
if(ContainsWaveTrack(t) && GetNumTasks())
|
||||
{
|
||||
|
||||
|
||||
// if(GetNumTasks()==1)
|
||||
mTipMsg.Printf(_("%s %2.0f%% complete. Click to change task focal point."), GetFrontTask()->GetTip(), GetFrontTask()->PercentComplete()*100.0 );
|
||||
// else
|
||||
// msg.Printf(_("%s %n additional tasks remaining."), GetFrontTask()->GetTip().c_str(), GetNumTasks());
|
||||
|
||||
|
||||
*ppTip = mTipMsg.c_str();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,74 +36,74 @@ class ODWaveTrackTaskQueue
|
||||
|
||||
/// Constructs an ODWaveTrackTaskQueue
|
||||
ODWaveTrackTaskQueue();
|
||||
|
||||
|
||||
virtual ~ODWaveTrackTaskQueue();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///Adds a track to the associated list.
|
||||
void AddWaveTrack(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);
|
||||
|
||||
void RemoveWaveTrack(WaveTrack* 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);
|
||||
|
||||
///replaces all instances of a WaveTrack within this task with another.
|
||||
void ReplaceWaveTrack(WaveTrack* oldTrack,WaveTrack* newTrack);
|
||||
|
||||
//if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it.
|
||||
|
||||
///replaces all instances of a WaveTrack within this task with another.
|
||||
void ReplaceWaveTrack(WaveTrack* oldTrack,WaveTrack* newTrack);
|
||||
|
||||
//if the wavetrack is in this queue, and is not the only wavetrack, clones the tasks and schedules it.
|
||||
void MakeWaveTrackIndependent(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.
|
||||
virtual bool CanMergeWith(ODWaveTrackTaskQueue* otherQueue);
|
||||
virtual bool CanMergeWith(ODWaveTrackTaskQueue* otherQueue);
|
||||
void MergeWaveTrack(WaveTrack* track);
|
||||
|
||||
|
||||
|
||||
//returns true if the agrument is in the WaveTrack list.
|
||||
bool ContainsWaveTrack(WaveTrack* track);
|
||||
|
||||
|
||||
//returns the wavetrack at position x.
|
||||
WaveTrack* GetWaveTrack(size_t x);
|
||||
|
||||
|
||||
///returns the number of wavetracks in this queue.
|
||||
int GetNumWaveTracks();
|
||||
|
||||
///Add a task to the queue.
|
||||
|
||||
///Add a task to the queue.
|
||||
void AddTask(ODTask* task);
|
||||
|
||||
|
||||
//returns true if either tracks or tasks are empty
|
||||
bool IsEmpty();
|
||||
|
||||
|
||||
//returns true if the foremost task exists and is empty.
|
||||
bool IsFrontTaskComplete();
|
||||
|
||||
|
||||
///Removes and deletes the front task from the list.
|
||||
void RemoveFrontTask();
|
||||
|
||||
|
||||
///Schedules the front task for immediate execution
|
||||
ODTask* GetFrontTask();
|
||||
|
||||
|
||||
///returns the number of ODTasks in this queue
|
||||
int GetNumTasks();
|
||||
|
||||
|
||||
///returns a ODTask at position x
|
||||
ODTask* GetTask(size_t x);
|
||||
|
||||
|
||||
///fills in the status bar message for a given track
|
||||
void FillTipForWaveTrack( WaveTrack * t, const wxChar ** ppTip );
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
//because we need to save this around for the tool tip.
|
||||
wxString mTipMsg;
|
||||
|
||||
|
||||
|
||||
|
||||
///the list of tracks associated with this queue.
|
||||
std::vector<WaveTrack*> mTracks;
|
||||
ODLock mTracksMutex;
|
||||
|
||||
|
||||
///the list of tasks associated with the tracks. This class owns these tasks.
|
||||
std::vector<ODTask*> mTasks;
|
||||
ODLock mTasksMutex;
|
||||
|
||||
Reference in New Issue
Block a user