mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-01 08:09:41 +02:00
Preliminaries for bug 900
Create WaveTrackCache as a utility class but don't use it anywhere yet. The possible minor performance problem with effects is fixed by changes in WaveTrack::GetBestBlockSize().
This commit is contained in:
parent
16e0fe3e12
commit
bdc2839112
@ -79,6 +79,7 @@ typedef enum
|
||||
// Generic pointer to sample data
|
||||
// ----------------------------------------------------------------------------
|
||||
typedef char *samplePtr;
|
||||
typedef const char *constSamplePtr;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// The type for plugin IDs
|
||||
|
@ -301,6 +301,7 @@ writing audio.
|
||||
#include "RingBuffer.h"
|
||||
#include "Prefs.h"
|
||||
#include "Project.h"
|
||||
#include "TimeTrack.h"
|
||||
#include "WaveTrack.h"
|
||||
#include "AutoRecovery.h"
|
||||
|
||||
|
@ -29,6 +29,7 @@ for drawing different aspects of the label and its text box.
|
||||
*//*******************************************************************/
|
||||
|
||||
#include "Audacity.h"
|
||||
#include "LabelTrack.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -48,7 +49,6 @@ for drawing different aspects of the label and its text box.
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "AudioIO.h"
|
||||
#include "LabelTrack.h"
|
||||
#include "DirManager.h"
|
||||
#include "Internat.h"
|
||||
#include "Prefs.h"
|
||||
@ -1117,7 +1117,12 @@ bool LabelTrack::IsTextClipSupported()
|
||||
}
|
||||
|
||||
|
||||
double LabelTrack::GetStartTime()
|
||||
double LabelTrack::GetOffset() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
double LabelTrack::GetStartTime() const
|
||||
{
|
||||
int len = mLabels.Count();
|
||||
|
||||
@ -1127,7 +1132,7 @@ double LabelTrack::GetStartTime()
|
||||
return mLabels[0]->getT0();
|
||||
}
|
||||
|
||||
double LabelTrack::GetEndTime()
|
||||
double LabelTrack::GetEndTime() const
|
||||
{
|
||||
//we need to scan through all the labels, because the last
|
||||
//label might not have the right-most end (if there is overlap).
|
||||
|
@ -132,8 +132,9 @@ class AUDACITY_DLL_API LabelTrack : public Track
|
||||
|
||||
virtual int GetKind() const { return Label; }
|
||||
|
||||
virtual double GetStartTime();
|
||||
virtual double GetEndTime();
|
||||
virtual double GetOffset() const;
|
||||
virtual double GetStartTime() const;
|
||||
virtual double GetEndTime() const;
|
||||
|
||||
virtual Track *Duplicate() { return new LabelTrack(*this); }
|
||||
|
||||
|
@ -83,6 +83,7 @@ simplifies construction of menu items.
|
||||
#include "NoteTrack.h"
|
||||
#endif // USE_MIDI
|
||||
#include "Tags.h"
|
||||
#include "TimeTrack.h"
|
||||
#include "Mix.h"
|
||||
#include "AboutDialog.h"
|
||||
#include "Benchmark.h"
|
||||
|
@ -14,20 +14,20 @@
|
||||
*//*******************************************************************/
|
||||
|
||||
|
||||
#include "Audacity.h"
|
||||
#include "NoteTrack.h"
|
||||
|
||||
#include <wx/dc.h>
|
||||
#include <wx/brush.h>
|
||||
#include <wx/pen.h>
|
||||
#include <wx/intl.h>
|
||||
|
||||
#include "Audacity.h"
|
||||
|
||||
#if defined(USE_MIDI)
|
||||
#include <sstream>
|
||||
|
||||
#define ROUND(x) ((int) ((x) + 0.5))
|
||||
|
||||
#include "AColor.h"
|
||||
#include "NoteTrack.h"
|
||||
#include "DirManager.h"
|
||||
#include "Internat.h"
|
||||
#include "Prefs.h"
|
||||
@ -171,13 +171,17 @@ Track *NoteTrack::Duplicate()
|
||||
}
|
||||
|
||||
|
||||
double NoteTrack::GetStartTime()
|
||||
double NoteTrack::GetOffset() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
double NoteTrack::GetStartTime() const
|
||||
{
|
||||
return GetOffset();
|
||||
}
|
||||
|
||||
|
||||
double NoteTrack::GetEndTime()
|
||||
double NoteTrack::GetEndTime() const
|
||||
{
|
||||
return GetStartTime() + (mSeq ? mSeq->get_real_dur() : 0.0);
|
||||
}
|
||||
|
@ -61,8 +61,9 @@ class AUDACITY_DLL_API NoteTrack:public Track {
|
||||
|
||||
virtual int GetKind() const { return Note; }
|
||||
|
||||
virtual double GetStartTime();
|
||||
virtual double GetEndTime();
|
||||
virtual double GetOffset() const;
|
||||
virtual double GetStartTime() const;
|
||||
virtual double GetEndTime() const;
|
||||
|
||||
void WarpAndTransposeNotes(double t0, double t1,
|
||||
const TimeWarper &warper, double semitones);
|
||||
|
@ -113,6 +113,7 @@ scroll information. It also has some status flags.
|
||||
#include "Prefs.h"
|
||||
#include "Snap.h"
|
||||
#include "Tags.h"
|
||||
#include "TimeTrack.h"
|
||||
#include "Track.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "WaveTrack.h"
|
||||
|
@ -51,6 +51,46 @@ const wxChar *GetSampleFormatStr(sampleFormat format);
|
||||
AUDACITY_DLL_API samplePtr NewSamples(int count, sampleFormat format);
|
||||
AUDACITY_DLL_API void DeleteSamples(samplePtr p);
|
||||
|
||||
// RAII version of above
|
||||
class SampleBuffer {
|
||||
|
||||
public:
|
||||
SampleBuffer()
|
||||
: mCount(0), mPtr(0)
|
||||
{}
|
||||
SampleBuffer(int count, sampleFormat format)
|
||||
: mCount(count), mPtr(NewSamples(mCount, format))
|
||||
{}
|
||||
~SampleBuffer()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
// WARNING! May not preserve contents.
|
||||
void Resize(int count, sampleFormat format)
|
||||
{
|
||||
if (mCount < count) {
|
||||
Free();
|
||||
mPtr = NewSamples(count, format);
|
||||
mCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
void Free()
|
||||
{
|
||||
DeleteSamples(mPtr);
|
||||
mPtr = 0;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
samplePtr ptr() const { return mPtr; }
|
||||
|
||||
|
||||
private:
|
||||
samplePtr mPtr;
|
||||
int mCount;
|
||||
};
|
||||
|
||||
//
|
||||
// Copying, Converting and Clearing Samples
|
||||
//
|
||||
|
@ -799,6 +799,12 @@ unsigned int Sequence::GetODFlags()
|
||||
return ret;
|
||||
}
|
||||
|
||||
sampleCount Sequence::GetBlockStart(sampleCount position) const
|
||||
{
|
||||
int b = FindBlock(position);
|
||||
return mBlock->Item(b)->start;
|
||||
}
|
||||
|
||||
sampleCount Sequence::GetBestBlockSize(sampleCount start) const
|
||||
{
|
||||
// This method returns a nice number of samples you should try to grab in
|
||||
|
@ -159,9 +159,10 @@ class Sequence: public XMLTagHandler {
|
||||
float * outRMS) const;
|
||||
|
||||
//
|
||||
// Getting block size information
|
||||
// Getting block size and alignment information
|
||||
//
|
||||
|
||||
sampleCount GetBlockStart(sampleCount position) const;
|
||||
sampleCount GetBestBlockSize(sampleCount start) const;
|
||||
sampleCount GetMaxBlockSize() const;
|
||||
sampleCount GetIdealBlockSize() const;
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "Spectrum.h"
|
||||
#include "FFT.h"
|
||||
|
||||
bool ComputeSpectrum(float * data, int width,
|
||||
bool ComputeSpectrum(const float * data, int width,
|
||||
int windowSize,
|
||||
double WXUNUSED(rate), float *output,
|
||||
bool autocorrelation, int windowFunc)
|
||||
|
@ -22,7 +22,7 @@
|
||||
calculates windowSize/2 frequency samples
|
||||
*/
|
||||
|
||||
bool ComputeSpectrum(float * data, int width, int windowSize,
|
||||
bool ComputeSpectrum(const float * data, int width, int windowSize,
|
||||
double rate, float *out, bool autocorrelation,
|
||||
int windowFunc = eWinFuncHanning);
|
||||
|
||||
|
@ -43,11 +43,11 @@ class TimeTrack: public Track {
|
||||
|
||||
// TimeTrack parameters
|
||||
|
||||
virtual double GetOffset() { return 0.0; };
|
||||
virtual void SetOffset(double /* t */) {};
|
||||
virtual double GetOffset() const { return 0.0; }
|
||||
virtual void SetOffset(double /* t */) {}
|
||||
|
||||
virtual double GetStartTime() { return 0.0; };
|
||||
virtual double GetEndTime() { return 0.0; };
|
||||
virtual double GetStartTime() const { return 0.0; }
|
||||
virtual double GetEndTime() const { return 0.0; }
|
||||
|
||||
void Draw(wxDC & dc, const wxRect & r, double h, double pps);
|
||||
|
||||
|
22
src/Track.h
22
src/Track.h
@ -165,7 +165,7 @@ class AUDACITY_DLL_API Track: public XMLTagHandler
|
||||
void SetSolo (bool s) { mSolo = s; }
|
||||
|
||||
int GetChannel() const { return mChannel; }
|
||||
virtual double GetOffset () { return mOffset; }
|
||||
virtual double GetOffset() const = 0;
|
||||
|
||||
void Offset(double t) { SetOffset(GetOffset() + t); }
|
||||
virtual void SetOffset (double o) { mOffset = o; }
|
||||
@ -202,8 +202,8 @@ class AUDACITY_DLL_API Track: public XMLTagHandler
|
||||
// open the track from XML
|
||||
virtual bool GetErrorOpening() { return false; }
|
||||
|
||||
virtual double GetStartTime() { return 0.0; }
|
||||
virtual double GetEndTime() { return 0.0; }
|
||||
virtual double GetStartTime() const = 0;
|
||||
virtual double GetEndTime() const = 0;
|
||||
|
||||
// Checks if sync-lock is on and any track in its sync-lock group is selected.
|
||||
bool IsSyncLockSelected();
|
||||
@ -220,7 +220,7 @@ class AUDACITY_DLL_API TrackListIterator
|
||||
{
|
||||
public:
|
||||
TrackListIterator(TrackList * val = NULL);
|
||||
virtual ~TrackListIterator() {};
|
||||
virtual ~TrackListIterator() {}
|
||||
|
||||
// Iterate functions
|
||||
virtual Track *First(TrackList * val = NULL);
|
||||
@ -243,8 +243,8 @@ class AUDACITY_DLL_API TrackListCondIterator: public TrackListIterator
|
||||
{
|
||||
public:
|
||||
TrackListCondIterator(TrackList *val = NULL)
|
||||
: TrackListIterator(val) {};
|
||||
virtual ~TrackListCondIterator() {};
|
||||
: TrackListIterator(val) {}
|
||||
virtual ~TrackListCondIterator() {}
|
||||
|
||||
// Iteration functions
|
||||
Track *First(TrackList *val = NULL);
|
||||
@ -266,7 +266,7 @@ class AUDACITY_DLL_API TrackListOfKindIterator: public TrackListCondIterator
|
||||
{
|
||||
public:
|
||||
TrackListOfKindIterator(int kind, TrackList * val = NULL);
|
||||
virtual ~TrackListOfKindIterator() {};
|
||||
virtual ~TrackListOfKindIterator() {}
|
||||
|
||||
protected:
|
||||
virtual bool Condition(Track *t);
|
||||
@ -283,8 +283,8 @@ class AUDACITY_DLL_API TrackListOfKindIterator: public TrackListCondIterator
|
||||
class AUDACITY_DLL_API SelectedTrackListOfKindIterator: public TrackListOfKindIterator
|
||||
{
|
||||
public:
|
||||
SelectedTrackListOfKindIterator(int kind, TrackList * val = NULL) : TrackListOfKindIterator(kind, val) {};
|
||||
virtual ~SelectedTrackListOfKindIterator() {};
|
||||
SelectedTrackListOfKindIterator(int kind, TrackList * val = NULL) : TrackListOfKindIterator(kind, val) {}
|
||||
virtual ~SelectedTrackListOfKindIterator() {}
|
||||
|
||||
protected:
|
||||
bool Condition(Track *t);
|
||||
@ -299,7 +299,7 @@ class AUDACITY_DLL_API VisibleTrackIterator: public TrackListCondIterator
|
||||
{
|
||||
public:
|
||||
VisibleTrackIterator(AudacityProject *project);
|
||||
virtual ~VisibleTrackIterator() {};
|
||||
virtual ~VisibleTrackIterator() {}
|
||||
|
||||
protected:
|
||||
bool Condition(Track *t);
|
||||
@ -316,7 +316,7 @@ class AUDACITY_DLL_API SyncLockedTracksIterator : public TrackListIterator
|
||||
{
|
||||
public:
|
||||
SyncLockedTracksIterator(TrackList * val);
|
||||
virtual ~SyncLockedTracksIterator() {};
|
||||
virtual ~SyncLockedTracksIterator() {}
|
||||
|
||||
// Iterate functions
|
||||
Track *First(Track *member);
|
||||
|
@ -160,7 +160,7 @@ WaveTrack::~WaveTrack()
|
||||
|
||||
}
|
||||
|
||||
double WaveTrack::GetOffset()
|
||||
double WaveTrack::GetOffset() const
|
||||
{
|
||||
return GetStartTime();
|
||||
}
|
||||
@ -311,7 +311,7 @@ void WaveTrack::VirtualStereoInit()
|
||||
}
|
||||
#endif
|
||||
|
||||
float WaveTrack::GetChannelGain(int channel)
|
||||
float WaveTrack::GetChannelGain(int channel) const
|
||||
{
|
||||
float left = 1.0;
|
||||
float right = 1.0;
|
||||
@ -1361,18 +1361,34 @@ unsigned int WaveTrack::GetODFlags()
|
||||
}
|
||||
|
||||
|
||||
sampleCount WaveTrack::GetBestBlockSize(sampleCount s)
|
||||
sampleCount WaveTrack::GetBlockStart(sampleCount s) const
|
||||
{
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
{
|
||||
WaveClip* clip = it->GetData();
|
||||
const sampleCount startSample = (sampleCount)floor(0.5 + clip->GetStartTime()*mRate);
|
||||
const sampleCount endSample = startSample + clip->GetNumSamples();
|
||||
if (s >= startSample && s < endSample)
|
||||
return startSample + clip->GetSequence()->GetBlockStart(s - startSample);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sampleCount WaveTrack::GetBestBlockSize(sampleCount s) const
|
||||
{
|
||||
sampleCount bestBlockSize = GetMaxBlockSize();
|
||||
|
||||
for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
{
|
||||
WaveClip* clip = it->GetData();
|
||||
sampleCount startSample = (sampleCount)floor(clip->GetStartTime()*mRate + 0.5);
|
||||
sampleCount endSample = startSample + clip->GetNumSamples();
|
||||
if (s >= startSample && s < endSample)
|
||||
{
|
||||
bestBlockSize = clip->GetSequence()->GetMaxBlockSize();
|
||||
bestBlockSize = clip->GetSequence()->GetBestBlockSize(s - startSample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1380,10 +1396,11 @@ sampleCount WaveTrack::GetBestBlockSize(sampleCount s)
|
||||
return bestBlockSize;
|
||||
}
|
||||
|
||||
sampleCount WaveTrack::GetMaxBlockSize()
|
||||
sampleCount WaveTrack::GetMaxBlockSize() const
|
||||
{
|
||||
int maxblocksize = 0;
|
||||
for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
{
|
||||
WaveClip* clip = it->GetData();
|
||||
if (clip->GetSequence()->GetMaxBlockSize() > maxblocksize)
|
||||
@ -1619,7 +1636,7 @@ double WaveTrack::LongSamplesToTime(sampleCount pos)
|
||||
return ((double)pos) / mRate;
|
||||
}
|
||||
|
||||
double WaveTrack::GetStartTime()
|
||||
double WaveTrack::GetStartTime() const
|
||||
{
|
||||
bool found = false;
|
||||
double best = 0.0;
|
||||
@ -1627,7 +1644,8 @@ double WaveTrack::GetStartTime()
|
||||
if (mClips.IsEmpty())
|
||||
return 0;
|
||||
|
||||
for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
if (!found)
|
||||
{
|
||||
found = true;
|
||||
@ -1638,7 +1656,7 @@ double WaveTrack::GetStartTime()
|
||||
return best;
|
||||
}
|
||||
|
||||
double WaveTrack::GetEndTime()
|
||||
double WaveTrack::GetEndTime() const
|
||||
{
|
||||
bool found = false;
|
||||
double best = 0.0;
|
||||
@ -1646,7 +1664,8 @@ double WaveTrack::GetEndTime()
|
||||
if (mClips.IsEmpty())
|
||||
return 0;
|
||||
|
||||
for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
if (!found)
|
||||
{
|
||||
found = true;
|
||||
@ -1747,7 +1766,7 @@ bool WaveTrack::GetRMS(float *rms, double t0, double t1)
|
||||
}
|
||||
|
||||
bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, sampleCount len, fillFormat fill )
|
||||
sampleCount start, sampleCount len, fillFormat fill ) const
|
||||
{
|
||||
// Simple optimization: When this buffer is completely contained within one clip,
|
||||
// don't clear anything (because we won't have to). Otherwise, just clear
|
||||
@ -1755,9 +1774,9 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
|
||||
WaveClipList::compatibility_iterator it;
|
||||
|
||||
bool doClear = true;
|
||||
for (it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (it = const_cast<WaveTrack&>(*this).GetClipIterator(); it; it = it->GetNext())
|
||||
{
|
||||
WaveClip *clip = it->GetData();
|
||||
const WaveClip *const clip = it->GetData();
|
||||
if (start >= clip->GetStartSample() && start+len <= clip->GetEndSample())
|
||||
{
|
||||
doClear = false;
|
||||
@ -1783,9 +1802,9 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
|
||||
}
|
||||
}
|
||||
|
||||
for (it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (it = const_cast<WaveTrack&>(*this).GetClipIterator(); it; it = it->GetNext())
|
||||
{
|
||||
WaveClip *clip = it->GetData();
|
||||
const WaveClip *const clip = it->GetData();
|
||||
|
||||
sampleCount clipStart = clip->GetStartSample();
|
||||
sampleCount clipEnd = clip->GetEndSample();
|
||||
@ -1858,7 +1877,7 @@ bool WaveTrack::Set(samplePtr buffer, sampleFormat format,
|
||||
}
|
||||
|
||||
void WaveTrack::GetEnvelopeValues(double *buffer, int bufferLen,
|
||||
double t0, double tstep)
|
||||
double t0, double tstep) const
|
||||
{
|
||||
// Possibly nothing to do.
|
||||
if( bufferLen <= 0 )
|
||||
@ -1881,9 +1900,10 @@ void WaveTrack::GetEnvelopeValues(double *buffer, int bufferLen,
|
||||
|
||||
double startTime = t0;
|
||||
double endTime = t0+tstep*bufferLen;
|
||||
for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext())
|
||||
for (WaveClipList::compatibility_iterator it = const_cast<WaveTrack&>(*this).GetClipIterator();
|
||||
it; it = it->GetNext())
|
||||
{
|
||||
WaveClip *clip = it->GetData();
|
||||
WaveClip *const clip = it->GetData();
|
||||
|
||||
// IF clip intersects startTime..endTime THEN...
|
||||
double dClipStartTime = clip->GetStartTime();
|
||||
@ -2393,3 +2413,180 @@ void WaveTrack::SetAutoSaveIdent(int ident)
|
||||
{
|
||||
mAutoSaveIdent = ident;
|
||||
}
|
||||
|
||||
WaveTrackCache::~WaveTrackCache()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
void WaveTrackCache::SetTrack(const WaveTrack *pTrack)
|
||||
{
|
||||
if (mPTrack != pTrack) {
|
||||
if (pTrack) {
|
||||
mBufferSize = pTrack->GetMaxBlockSize();
|
||||
if (!mPTrack ||
|
||||
mPTrack->GetMaxBlockSize() != mBufferSize) {
|
||||
Free();
|
||||
mBuffers[0].data = new float[mBufferSize];
|
||||
mBuffers[1].data = new float[mBufferSize];
|
||||
}
|
||||
}
|
||||
else
|
||||
Free();
|
||||
mPTrack = pTrack;
|
||||
mNValidBuffers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
constSamplePtr WaveTrackCache::Get(sampleFormat format,
|
||||
sampleCount start, sampleCount len)
|
||||
{
|
||||
if (format == floatSample && len > 0) {
|
||||
const sampleCount end = start + len;
|
||||
|
||||
bool fillFirst = (mNValidBuffers < 1);
|
||||
bool fillSecond = (mNValidBuffers < 2);
|
||||
|
||||
// Discard cached results that we no longer need
|
||||
if (mNValidBuffers > 0 &&
|
||||
(end <= mBuffers[0].start ||
|
||||
start >= mBuffers[mNValidBuffers - 1].end())) {
|
||||
// Complete miss
|
||||
fillFirst = true;
|
||||
fillSecond = true;
|
||||
}
|
||||
else if (mNValidBuffers == 2 &&
|
||||
start >= mBuffers[1].start &&
|
||||
end > mBuffers[1].end()) {
|
||||
// Request starts in the second buffer and extends past it.
|
||||
// Discard the first buffer.
|
||||
// (But don't deallocate the buffer space.)
|
||||
float *save = mBuffers[0].data;
|
||||
mBuffers[0] = mBuffers[1];
|
||||
mBuffers[1].data = save;
|
||||
fillSecond = true;
|
||||
mNValidBuffers = 1;
|
||||
}
|
||||
else if (mNValidBuffers > 0 &&
|
||||
start < mBuffers[0].start &&
|
||||
0 <= mPTrack->GetBlockStart(start)) {
|
||||
// Request is not a total miss but starts before the cache,
|
||||
// and there is a clip to fetch from.
|
||||
// Not the access pattern for drawing spectrogram or playback,
|
||||
// but maybe scrubbing causes this.
|
||||
// Move the first buffer into second place, and later
|
||||
// refill the first.
|
||||
// (This case might be useful when marching backwards through
|
||||
// the track, as with scrubbing.)
|
||||
float *save = mBuffers[1].data;
|
||||
mBuffers[1] = mBuffers[0];
|
||||
mBuffers[0].data = save;
|
||||
fillFirst = true;
|
||||
// Cache is not in a consistent state yet
|
||||
mNValidBuffers = 0;
|
||||
}
|
||||
|
||||
// Refill buffers as needed
|
||||
if (fillFirst) {
|
||||
const sampleCount start0 = mPTrack->GetBlockStart(start);
|
||||
if (start0 >= 0) {
|
||||
const sampleCount len0 = mPTrack->GetBestBlockSize(start0);
|
||||
wxASSERT(len0 <= mBufferSize);
|
||||
if (!mPTrack->Get(samplePtr(mBuffers[0].data), floatSample, start0, len0))
|
||||
return false;
|
||||
mBuffers[0].start = start0;
|
||||
mBuffers[0].len = len0;
|
||||
if (!fillSecond &&
|
||||
mBuffers[0].end() != mBuffers[1].start)
|
||||
fillSecond = true;
|
||||
// Keep the partially updated state consistent:
|
||||
mNValidBuffers = fillSecond ? 1 : 2;
|
||||
}
|
||||
else {
|
||||
// Request may fall between the clips of a track.
|
||||
// Invalidate all. WaveTrack::Get() will return zeroes.
|
||||
mNValidBuffers = 0;
|
||||
fillSecond = false;
|
||||
}
|
||||
}
|
||||
wxASSERT(!fillSecond || mNValidBuffers > 0);
|
||||
if (fillSecond) {
|
||||
mNValidBuffers = 1;
|
||||
const sampleCount end0 = mBuffers[0].end();
|
||||
if (end > end0) {
|
||||
const sampleCount start1 = mPTrack->GetBlockStart(end0);
|
||||
if (start1 == end0) {
|
||||
const sampleCount len1 = mPTrack->GetBestBlockSize(start1);
|
||||
wxASSERT(len1 <= mBufferSize);
|
||||
if (!mPTrack->Get(samplePtr(mBuffers[1].data), floatSample, start1, len1))
|
||||
return false;
|
||||
mBuffers[1].start = start1;
|
||||
mBuffers[1].len = len1;
|
||||
mNValidBuffers = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
wxASSERT(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
|
||||
|
||||
samplePtr buffer = 0;
|
||||
sampleCount remaining = len;
|
||||
|
||||
// Possibly get an initial portion that is uncached
|
||||
const sampleCount initLen =
|
||||
mNValidBuffers < 1 ? len : std::min(len, mBuffers[0].start - start);
|
||||
if (initLen > 0) {
|
||||
// This might be fetching zeroes between clips
|
||||
mOverlapBuffer.Resize(len, format);
|
||||
if (!mPTrack->Get(mOverlapBuffer.ptr(), format, start, initLen))
|
||||
return 0;
|
||||
remaining -= initLen;
|
||||
start += initLen;
|
||||
buffer = mOverlapBuffer.ptr() + initLen * SAMPLE_SIZE(format);
|
||||
}
|
||||
|
||||
// Now satisfy the request from the buffers
|
||||
for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) {
|
||||
const sampleCount starti = start - mBuffers[ii].start;
|
||||
const sampleCount leni = std::min(remaining, mBuffers[ii].len - starti);
|
||||
if (leni == len) {
|
||||
// All is contiguous already. We can completely avoid copying
|
||||
return samplePtr(mBuffers[ii].data + starti);
|
||||
}
|
||||
else if (leni > 0) {
|
||||
if (buffer == 0) {
|
||||
mOverlapBuffer.Resize(len, format);
|
||||
buffer = mOverlapBuffer.ptr();
|
||||
}
|
||||
const size_t size = sizeof(float) * leni;
|
||||
memcpy(buffer, mBuffers[ii].data + starti, size);
|
||||
remaining -= leni;
|
||||
start += leni;
|
||||
buffer += size;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
// Very big request!
|
||||
// Fall back to direct fetch
|
||||
if (!mPTrack->Get(buffer, format, start, remaining))
|
||||
return false;
|
||||
}
|
||||
|
||||
return mOverlapBuffer.ptr();
|
||||
}
|
||||
|
||||
// Cache works only for float format.
|
||||
mOverlapBuffer.Resize(len, format);
|
||||
if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len))
|
||||
return mOverlapBuffer.ptr();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WaveTrackCache::Free()
|
||||
{
|
||||
mBuffers[0].Free();
|
||||
mBuffers[1].Free();
|
||||
mOverlapBuffer.Free();
|
||||
mNValidBuffers = 0;
|
||||
}
|
||||
|
@ -95,21 +95,21 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
||||
};
|
||||
|
||||
virtual ~WaveTrack();
|
||||
virtual double GetOffset();
|
||||
virtual double GetOffset() const;
|
||||
virtual void SetOffset (double o);
|
||||
|
||||
/** @brief Get the time at which the first clip in the track starts
|
||||
*
|
||||
* @return time in seconds, or zero if there are no clips in the track
|
||||
*/
|
||||
double GetStartTime();
|
||||
double GetStartTime() const;
|
||||
|
||||
/** @brief Get the time at which the last clip in the track ends, plus
|
||||
* recorded stuff
|
||||
*
|
||||
* @return time in seconds, or zero if there are no clips in the track.
|
||||
*/
|
||||
double GetEndTime();
|
||||
double GetEndTime() const;
|
||||
|
||||
//
|
||||
// Identifying the type of track
|
||||
@ -138,7 +138,7 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
||||
void SetPan(float newPan);
|
||||
#endif
|
||||
// Takes gain and pan into account
|
||||
float GetChannelGain(int channel);
|
||||
float GetChannelGain(int channel) const;
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
void SetVirtualState(bool state, bool half=false);
|
||||
#endif
|
||||
@ -231,11 +231,11 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
||||
/// guaranteed that the same samples are affected.
|
||||
///
|
||||
bool Get(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, sampleCount len, fillFormat fill=fillZero);
|
||||
sampleCount start, sampleCount len, fillFormat fill=fillZero) const;
|
||||
bool Set(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, sampleCount len);
|
||||
void GetEnvelopeValues(double *buffer, int bufferLen,
|
||||
double t0, double tstep);
|
||||
double t0, double tstep) const;
|
||||
bool GetMinMax(float *min, float *max,
|
||||
double t0, double t1);
|
||||
bool GetRMS(float *rms, double t0, double t1);
|
||||
@ -255,11 +255,12 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
||||
|
||||
//
|
||||
// Getting information about the track's internal block sizes
|
||||
// for efficiency
|
||||
// and alignment for efficiency
|
||||
//
|
||||
|
||||
sampleCount GetBestBlockSize(sampleCount t);
|
||||
sampleCount GetMaxBlockSize();
|
||||
sampleCount GetBlockStart(sampleCount t) const;
|
||||
sampleCount GetBestBlockSize(sampleCount t) const;
|
||||
sampleCount GetMaxBlockSize() const;
|
||||
sampleCount GetIdealBlockSize();
|
||||
|
||||
//
|
||||
@ -465,4 +466,49 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
||||
int mAutoSaveIdent;
|
||||
};
|
||||
|
||||
// This is meant to be a short-lived object, during whose lifetime,
|
||||
// the contents of the WaveTrack are known not to change. It can replace
|
||||
// repeated calls to WaveTrack::Get() (each of which opens and closes at least
|
||||
// one block file).
|
||||
class WaveTrackCache {
|
||||
public:
|
||||
explicit WaveTrackCache(const WaveTrack *pTrack = 0)
|
||||
: mPTrack(0)
|
||||
, mBufferSize(0)
|
||||
, mOverlapBuffer()
|
||||
, mNValidBuffers(0)
|
||||
{
|
||||
SetTrack(pTrack);
|
||||
}
|
||||
~WaveTrackCache();
|
||||
|
||||
const WaveTrack *GetTrack() const { return mPTrack; }
|
||||
void SetTrack(const WaveTrack *pTrack);
|
||||
|
||||
// Uses fillZero always
|
||||
// Returns null on failure
|
||||
// Returned pointer may be invalidated if Get is called again
|
||||
// Do not delete[] the pointer
|
||||
constSamplePtr Get(sampleFormat format, sampleCount start, sampleCount len);
|
||||
|
||||
private:
|
||||
void Free();
|
||||
|
||||
struct Buffer {
|
||||
float *data;
|
||||
sampleCount start;
|
||||
sampleCount len;
|
||||
|
||||
Buffer() : data(0), start(0), len(0) {}
|
||||
void Free() { delete[] data; data = 0; start = 0; len = 0; }
|
||||
sampleCount end() const { return start + len; }
|
||||
};
|
||||
|
||||
const WaveTrack *mPTrack;
|
||||
sampleCount mBufferSize;
|
||||
Buffer mBuffers[2];
|
||||
SampleBuffer mOverlapBuffer;
|
||||
int mNValidBuffers;
|
||||
};
|
||||
|
||||
#endif // __AUDACITY_WAVETRACK__
|
||||
|
Loading…
x
Reference in New Issue
Block a user