1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49:41 +02:00

Merge branch 'master' into scrubbing

This commit is contained in:
Paul Licameli 2015-05-26 20:23:06 -04:00
commit 4af87a1879
24 changed files with 428 additions and 95 deletions

View File

@ -79,6 +79,7 @@ typedef enum
// Generic pointer to sample data
// ----------------------------------------------------------------------------
typedef char *samplePtr;
typedef const char *constSamplePtr;
// ----------------------------------------------------------------------------
// The type for plugin IDs

View File

@ -301,6 +301,7 @@ writing audio.
#include "RingBuffer.h"
#include "Prefs.h"
#include "Project.h"
#include "TimeTrack.h"
#include "WaveTrack.h"
#include "AutoRecovery.h"

View File

@ -326,7 +326,6 @@ void BatchProcessDialog::OnApplyToFiles(wxCommandEvent & WXUNUSED(event))
mList->SetItemImage(i, 1, 1);
mList->EnsureVisible(i);
project->OnRemoveTracks();
project->Import(files[i]);
project->OnSelectAll();
if (!mBatchCommands.ApplyChain()) {
@ -338,8 +337,8 @@ void BatchProcessDialog::OnApplyToFiles(wxCommandEvent & WXUNUSED(event))
}
UndoManager *um = project->GetUndoManager();
um->ClearStates();
project->OnSelectAll();
project->OnRemoveTracks();
project->OnSelectAll();
project->OnRemoveTracks();
}
project->OnRemoveTracks();
}

View File

@ -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).

View File

@ -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); }

View File

@ -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"

View File

@ -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);
}

View File

@ -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);

View File

@ -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"

View File

@ -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
//

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -143,8 +143,8 @@ audio tracks.
*//*******************************************************************/
#include "Audacity.h"
#include "AudacityApp.h"
#include "TrackArtist.h"
#include "AudacityApp.h"
#include "float_cast.h"
#include <math.h>
@ -1749,8 +1749,9 @@ void TrackArtist::DrawSpectrum(WaveTrack *track,
return;
}
WaveTrackCache cache(track);
for (WaveClipList::compatibility_iterator it = track->GetClipIterator(); it; it = it->GetNext()) {
DrawClipSpectrum(track, it->GetData(), dc, r, viewInfo, autocorrelation, logF);
DrawClipSpectrum(cache, it->GetData(), dc, r, viewInfo, autocorrelation, logF);
}
}
@ -1822,7 +1823,7 @@ AColor::ColorGradientChoice ChooseColorSet( float bin0, float bin1, float selBin
void TrackArtist::DrawClipSpectrum(WaveTrack *track,
void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
WaveClip *clip,
wxDC & dc,
const wxRect & r,
@ -1830,6 +1831,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
bool autocorrelation,
bool logF)
{
const WaveTrack *const track = cache.GetTrack();
enum { MONOCHROME_LINE = 230, COLORED_LINE = 0 };
enum { DASH_LENGTH = 10 /* pixels */ };
@ -1962,7 +1965,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
float *freq = new float[mid.width * half];
sampleCount *where = new sampleCount[mid.width+1];
bool updated = clip->GetSpectrogram(freq, where, mid.width,
bool updated = clip->GetSpectrogram(cache, freq, where, mid.width,
t0, pps, autocorrelation);
int ifreq = lrint(rate/2);

View File

@ -29,6 +29,7 @@ class wxHashTable;
class Track;
class WaveTrack;
class WaveTrackCache;
class WaveClip;
class NoteTrack;
class LabelTrack;
@ -141,7 +142,7 @@ class AUDACITY_DLL_API TrackArtist {
bool drawEnvelope, bool drawSamples, bool drawSliders,
bool dB, bool muted);
void DrawClipSpectrum(WaveTrack *track, WaveClip *clip,
void DrawClipSpectrum(WaveTrackCache &cache, WaveClip *clip,
wxDC & dc, const wxRect & r, const ViewInfo *viewInfo,
bool autocorrelation, bool logF);

View File

@ -25,6 +25,8 @@ drawing). Cache's the Spectrogram frequency samples.
*//*******************************************************************/
#include "WaveClip.h"
#include <math.h>
#include <memory>
#include <vector>
@ -32,7 +34,6 @@ drawing). Cache's the Spectrogram frequency samples.
#include "Spectrum.h"
#include "Prefs.h"
#include "WaveClip.h"
#include "Envelope.h"
#include "Resample.h"
#include "Project.h"
@ -753,10 +754,11 @@ bool WaveClip::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
return true;
}
bool WaveClip::GetSpectrogram(float *freq, sampleCount *where,
int numPixels,
double t0, double pixelsPerSecond,
bool autocorrelation)
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
float *freq, sampleCount *where,
int numPixels,
double t0, double pixelsPerSecond,
bool autocorrelation)
{
int minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
@ -912,6 +914,7 @@ bool WaveClip::GetSpectrogram(float *freq, sampleCount *where,
}
}
float *useBuffer;
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
float *buffer = new float[windowSize*fftSkipPoints1];
mSpecCache->fftSkipPointsOld = fftSkipPoints;
@ -952,6 +955,7 @@ bool WaveClip::GetSpectrogram(float *freq, sampleCount *where,
}
else
{
bool copy = !autocorrelation;
float *adj = buffer;
start -= windowSize >> 1;
@ -960,42 +964,58 @@ bool WaveClip::GetSpectrogram(float *freq, sampleCount *where,
*adj++ = 0;
len += start;
start = 0;
copy = true;
}
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
copy = true;
if (start + len*fftSkipPoints1 > mSequence->GetNumSamples()) {
int newlen = (mSequence->GetNumSamples() - start)/fftSkipPoints1;
for (i = newlen*fftSkipPoints1; i < (sampleCount)len*fftSkipPoints1; i++)
adj[i] = 0;
len = newlen;
}
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
if (start + len > mSequence->GetNumSamples()) {
int newlen = mSequence->GetNumSamples() - start;
for (i = newlen; i < (sampleCount)len; i++)
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
adj[i] = 0;
len = newlen;
copy = true;
}
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
if (len > 0) {
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
useBuffer = (float*)(waveTrackCache.Get(floatSample,
floor(0.5 + start + mOffset * mRate),
len * fftSkipPoints1));
memmove(adj, useBuffer, len * fftSkipPoints1 * sizeof(float));
if (fftSkipPoints) {
// TODO: (maybe) alternatively change Get to include skipping of points
int j=0;
for (int i=0; i < len; i++) {
adj[i]=adj[j];
j+=fftSkipPoints1;
}
}
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
useBuffer = (float*)(waveTrackCache.Get(floatSample,
floor(0.5 + start + mOffset * mRate), len));
if (copy)
memmove(adj, useBuffer, len * sizeof(float));
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
}
if (len > 0)
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
mSequence->Get((samplePtr)adj, floatSample, start, len*fftSkipPoints1);
if (fftSkipPoints) {
// TODO: (maybe) alternatively change Get to include skipping of points
int j=0;
for (int i=0; i < len; i++) {
adj[i]=adj[j];
j+=fftSkipPoints1;
}
}
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
mSequence->Get((samplePtr)adj, floatSample, start, len);
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
if (copy)
useBuffer = buffer;
#ifdef EXPERIMENTAL_USE_REALFFTF
if(autocorrelation) {
ComputeSpectrum(buffer, windowSize, windowSize,
ComputeSpectrum(useBuffer, windowSize, windowSize,
mRate, &mSpecCache->freq[half * x],
autocorrelation, windowType);
} else {
ComputeSpectrumUsingRealFFTf(buffer, hFFT, mWindow, mWindowSize, &mSpecCache->freq[half * x]);
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, mWindowSize, &mSpecCache->freq[half * x]);
}
#else // EXPERIMENTAL_USE_REALFFTF
ComputeSpectrum(buffer, windowSize, windowSize,

View File

@ -31,6 +31,7 @@
class Envelope;
class WaveCache;
class WaveTrackCache;
class SpecCache;
class SpecPxCache {
@ -140,7 +141,8 @@ public:
* calculations and Contrast */
bool GetWaveDisplay(float *min, float *max, float *rms,int* bl, sampleCount *where,
int numPixels, double t0, double pixelsPerSecond, bool &isLoadingOD);
bool GetSpectrogram(float *buffer, sampleCount *where,
bool GetSpectrogram(WaveTrackCache &cache,
float *buffer, sampleCount *where,
int numPixels,
double t0, double pixelsPerSecond,
bool autocorrelation);

View File

@ -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;
}

View File

@ -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__

10
src/prefs/ModulePrefs.cpp Normal file → Executable file
View File

@ -53,6 +53,7 @@ void ModulePrefs::GetAllModuleStatuses(){
// The old modules might be still around, and we do not want to use them.
mModules.Clear();
mStatuses.Clear();
mPaths.Clear();
// Iterate through all Modules listed in prefs.
@ -63,7 +64,7 @@ void ModulePrefs::GetAllModuleStatuses(){
int iStatus;
gPrefs->Read( str, &iStatus, kModuleDisabled );
wxString fname;
gPrefs->Read( wxString( wxT("/Module/path:") ) + str, &fname, wxEmptyString );
gPrefs->Read( wxString( wxT("/ModulePath/") ) + str, &fname, wxEmptyString );
if( fname != wxEmptyString && wxFileExists( fname ) ){
if( iStatus > kModuleNew ){
iStatus = kModuleNew;
@ -72,6 +73,7 @@ void ModulePrefs::GetAllModuleStatuses(){
//wxLogDebug( wxT("Entry: %s Value: %i"), str.c_str(), iStatus );
mModules.Add( str );
mStatuses.Add( iStatus );
mPaths.Add( fname );
}
bCont = gPrefs->GetNextEntry(str, dummy);
}
@ -129,8 +131,8 @@ bool ModulePrefs::Apply()
ShuttleGui S(this, eIsSavingToPrefs);
PopulateOrExchange(S);
int i;
for(i=0;i<(int)mModules.GetCount();i++)
SetModuleStatus( mModules[i], mStatuses[i] );
for(i=0;i<(int)mPaths.GetCount();i++)
SetModuleStatus( mPaths[i], mStatuses[i] );
return true;
}
@ -154,7 +156,7 @@ void ModulePrefs::SetModuleStatus( wxString fname, int iStatus ){
wxString ShortName = wxFileName( fname ).GetName();
wxString PrefName = wxString( wxT("/Module/") ) + ShortName.Lower();
gPrefs->Write( PrefName, iStatus );
PrefName = wxString( wxT("/Module/path:") ) + ShortName.Lower();
PrefName = wxString( wxT("/ModulePath/") ) + ShortName.Lower();
gPrefs->Write( PrefName, fname );
gPrefs->Flush();
}

1
src/prefs/ModulePrefs.h Normal file → Executable file
View File

@ -47,6 +47,7 @@ class ModulePrefs:public PrefsPanel
void PopulateOrExchange(ShuttleGui & S);
wxArrayString mModules;
wxArrayInt mStatuses;
wxArrayString mPaths;
};
#endif