From 38f24a42efcb18142cfebdebd3fd3acf80f6a4cb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 3 Jun 2015 23:02:37 -0400 Subject: [PATCH] Don't invalidate SpecCache for changes of min, max, gain or range... ... because those do not affect it. They only affect the SpecPxCache. Did other things to that class: renamed fields, new constructors. --- src/TrackArtist.cpp | 4 + src/WaveClip.cpp | 193 +++++++++++++++++++++++++------------------- src/WaveClip.h | 4 + 3 files changed, 118 insertions(+), 83 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index e48ddcdb5..bca4ee442 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -2021,6 +2021,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, #endif //EXPERIMENTAL_FFT_Y_GRID if (!updated && clip->mSpecPxCache->valid && (clip->mSpecPxCache->len == mid.height * mid.width) + && gain == clip->mSpecPxCache->gain + && range == clip->mSpecPxCache->range #ifdef EXPERIMENTAL_FFT_Y_GRID && mFftYGrid==fftYGridOld #endif //EXPERIMENTAL_FFT_Y_GRID @@ -2037,6 +2039,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, delete clip->mSpecPxCache; clip->mSpecPxCache = new SpecPxCache(mid.width * mid.height); clip->mSpecPxCache->valid = true; + clip->mSpecPxCache->gain = gain; + clip->mSpecPxCache->range = range; #ifdef EXPERIMENTAL_FIND_NOTES fftFindNotesOld=mFftFindNotes; findNotesMinAOld=mFindNotesMinA; diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 94be7305d..34a5b119a 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -254,26 +254,58 @@ protected: class SpecCache { public: - SpecCache(int cacheLen, int half, bool autocorrelation) - { - minFreqOld = -1; - maxFreqOld = -1; - gainOld = -1; - rangeOld = -1; - windowTypeOld = -1; - windowSizeOld = -1; - zeroPaddingFactorOld = 1; - frequencyGainOld = false; + + // Make invalid cache + SpecCache() + : len(-1) + , ac(false) + , pps(-1.0) + , start(-1.0) + , windowType(-1) + , windowSize(-1) + , zeroPaddingFactor(-1) + , frequencyGain(-1) #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - fftSkipPointsOld = -1; + , fftSkipPoints(-1); #endif //EXPERIMENTAL_FFT_SKIP_POINTS - dirty = -1; - start = -1.0; - pps = 0.0; - len = cacheLen; - ac = autocorrelation; - freq = len ? new float[len*half] : 0; - where = new sampleCount[len+1]; + + , freq(NULL) + , where(NULL) + + , dirty(-1) + { + } + + // Make valid cache, to be filled in + SpecCache(int cacheLen, bool autocorrelation, + double pps_, double start_, int windowType_, int windowSize_, + int zeroPaddingFactor_, int frequencyGain_ +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + , int fftSkipPoints_ +#endif + ) + : len(cacheLen) + , ac(autocorrelation) + , pps(pps_) + , start(start_) + , windowType(windowType_) + , windowSize(windowSize_) + , zeroPaddingFactor(zeroPaddingFactor_) + , frequencyGain(frequencyGain_) +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + , fftSkipPoints(fftSkipPoints_); +#endif //EXPERIMENTAL_FFT_SKIP_POINTS + + // len columns, and so many rows, column-major. + // Don't take column literally -- this isn't pixel data yet, it's the + // raw data to be mapped onto the display. + , freq(len ? new float[len * ((windowSize * zeroPaddingFactor) / 2)] : 0) + + // Sample counts corresponding to the columns, and to one past the end. + , where(new sampleCount[len + 1]) + + , dirty(-1) + { where[0] = 0; } @@ -283,24 +315,21 @@ public: delete[] where; } - int minFreqOld; - int maxFreqOld; - int gainOld; - int rangeOld; - int windowTypeOld; - int windowSizeOld; - int zeroPaddingFactorOld; - int frequencyGainOld; + const sampleCount len; + const bool ac; + const double pps; + const double start; + const int windowType; + const int windowSize; + const int zeroPaddingFactor; + const int frequencyGain; #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - int fftSkipPointsOld; + const int fftSkipPoints; #endif //EXPERIMENTAL_FFT_SKIP_POINTS + float *const freq; + sampleCount *const where; + int dirty; - bool ac; - sampleCount len; - double start; - double pps; - sampleCount *where; - float *freq; }; #ifdef EXPERIMENTAL_USE_REALFFTF @@ -347,7 +376,7 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate) mWindow = NULL; #endif mZeroPaddingFactor = 1; - mSpecCache = new SpecCache(0, 1, false); + mSpecCache = new SpecCache(); mSpecPxCache = new SpecPxCache(1); mAppendBuffer = NULL; mAppendBufferLen = 0; @@ -376,7 +405,7 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager) mWindow = NULL; #endif mZeroPaddingFactor = 1; - mSpecCache = new SpecCache(0, 1, false); + mSpecCache = new SpecCache(); mSpecPxCache = new SpecPxCache(1); for (WaveClipList::compatibility_iterator it=orig.mCutLines.GetFirst(); it; it=it->GetNext()) @@ -499,7 +528,8 @@ namespace { inline void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen, double t0, double rate, double samplesPerPixel, - double &oldWhere0, double &denom, long &oldX0, long &oldXLast, double &correction) + double &oldWhere0, double &denom, long &oldX0, long &oldXLast, double &correction, + bool &overlap) { // Mitigate the accumulation of location errors // in copies of copies of ... of caches. @@ -533,6 +563,7 @@ void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen, denom < 0.5) { correction = 0.0; + overlap = false; } else { @@ -540,6 +571,7 @@ void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen, const double correction0 = where0 - guessWhere0; correction = std::max(-samplesPerPixel, std::min(samplesPerPixel, correction0)); wxASSERT(correction == correction0); + overlap = true; } } @@ -598,26 +630,32 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, return true; } - WaveCache *oldCache = mWaveCache; - - mWaveCache = new WaveCache(numPixels); - mWaveCache->pps = pixelsPerSecond; - mWaveCache->rate = mRate; - mWaveCache->start = t0; - double tstep = 1.0 / pixelsPerSecond; - double samplesPerPixel = mRate * tstep; + std::auto_ptr oldCache(mWaveCache); + mWaveCache = 0; double oldWhere0 = 0; double denom = 0; long oldX0 = 0, oldXLast = 0; double correction = 0.0; + bool overlap = false; + const double tstep = 1.0 / pixelsPerSecond; + const double samplesPerPixel = mRate * tstep; + if (match && oldCache->len > 0) { - findCorrection(oldCache->where, oldCache->len, mWaveCache->len, + findCorrection(oldCache->where, oldCache->len, numPixels, t0, mRate, samplesPerPixel, - oldWhere0, denom, oldX0, oldXLast, correction); + oldWhere0, denom, oldX0, oldXLast, correction, overlap); } + if (!overlap) + oldCache.reset(0); + + mWaveCache = new WaveCache(numPixels); + mWaveCache->pps = pixelsPerSecond; + mWaveCache->rate = mRate; + mWaveCache->start = t0; + fillWhere(mWaveCache->where, mWaveCache->len, 0.0, correction, t0, mRate, samplesPerPixel); @@ -630,7 +668,7 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, // Optimization: if the old cache is good and overlaps // with the current one, re-use as much of the cache as // possible - if (match && + if (match && overlap && denom >= 0.5 && oldX0 < oldCache->len && oldXLast > oldCache->start) { @@ -763,7 +801,6 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, } mWaveCache->dirty = mDirty; - delete oldCache; memcpy(min, mWaveCache->min, numPixels*sizeof(float)); memcpy(max, mWaveCache->max, numPixels*sizeof(float)); @@ -867,10 +904,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, double t0, double pixelsPerSecond, bool autocorrelation) { - int minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L); - int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L); - int range = gPrefs->Read(wxT("/Spectrum/Range"), 80L); - int gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L); int frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L); int windowType; int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); @@ -909,16 +942,12 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, const bool match = mSpecCache && mSpecCache->dirty == mDirty && - mSpecCache->minFreqOld == minFreq && - mSpecCache->maxFreqOld == maxFreq && - mSpecCache->rangeOld == range && - mSpecCache->gainOld == gain && - mSpecCache->windowTypeOld == windowType && - mSpecCache->windowSizeOld == windowSize && - mSpecCache->zeroPaddingFactorOld == zeroPaddingFactor && - mSpecCache->frequencyGainOld == frequencyGain && + mSpecCache->windowType == windowType && + mSpecCache->windowSize == windowSize && + mSpecCache->zeroPaddingFactor == zeroPaddingFactor && + mSpecCache->frequencyGain == frequencyGain && #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - mSpecCache->fftSkipPointsOld == fftSkipPoints && + mSpecCache->fftSkipPoints == fftSkipPoints && #endif //EXPERIMENTAL_FFT_SKIP_POINTS mSpecCache->ac == autocorrelation && mSpecCache->pps == pixelsPerSecond; @@ -931,14 +960,11 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, return false; //hit cache completely } - SpecCache *oldCache = mSpecCache; + std::auto_ptr oldCache(mSpecCache); + mSpecCache = 0; - mSpecCache = new SpecCache(numPixels, half, autocorrelation); - mSpecCache->pps = pixelsPerSecond; - mSpecCache->start = t0; - - bool *recalc = new bool[mSpecCache->len + 1]; - std::fill(&recalc[0], &recalc[mSpecCache->len + 1], true); + bool *recalc = new bool[numPixels + 1]; + std::fill(&recalc[0], &recalc[numPixels + 1], true); const double tstep = 1.0 / pixelsPerSecond; const double samplesPerPixel = mRate * tstep; @@ -949,21 +975,33 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, double denom = 0; long oldX0 = 0, oldXLast = 0; double correction = 0.0; + bool overlap = false; if (match && oldCache->len > 0) { - findCorrection(oldCache->where, oldCache->len, mSpecCache->len, + findCorrection(oldCache->where, oldCache->len, numPixels, t0, mRate, samplesPerPixel, - oldWhere0, denom, oldX0, oldXLast, correction); + oldWhere0, denom, oldX0, oldXLast, correction, overlap); } + if (!overlap) + oldCache.reset(0); + + mSpecCache = new SpecCache( + numPixels, autocorrelation, pixelsPerSecond, t0, + windowType, windowSize, zeroPaddingFactor, frequencyGain +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + , fftSkipPoints +#endif + ); + fillWhere(mSpecCache->where, mSpecCache->len, 0.5, correction, t0, mRate, samplesPerPixel); // Optimization: if the old cache is good and overlaps // with the current one, re-use as much of the cache as // possible - if (match && + if (match && overlap && denom >= 0.5 && oldX0 < oldCache->len && oldXLast > oldCache->start) { @@ -988,7 +1026,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, float *useBuffer = 0; #ifdef EXPERIMENTAL_FFT_SKIP_POINTS float *buffer = new float[fftLen*fftSkipPoints1]; - mSpecCache->fftSkipPointsOld = fftSkipPoints; #else //!EXPERIMENTAL_FFT_SKIP_POINTS float *buffer = new float[fftLen]; #endif //EXPERIMENTAL_FFT_SKIP_POINTS @@ -998,15 +1035,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, buffer[fftLen - ii - 1] = 0.0; } - mSpecCache->minFreqOld = minFreq; - mSpecCache->maxFreqOld = maxFreq; - mSpecCache->gainOld = gain; - mSpecCache->rangeOld = range; - mSpecCache->windowTypeOld = windowType; - mSpecCache->windowSizeOld = windowSize; - mSpecCache->zeroPaddingFactorOld = zeroPaddingFactor; - mSpecCache->frequencyGainOld = frequencyGain; - std::vector gainFactors; ComputeSpectrogramGainFactors(fftLen, frequencyGain, gainFactors); @@ -1101,7 +1129,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, delete[]buffer; delete[]recalc; - delete oldCache; mSpecCache->dirty = mDirty; memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float)); @@ -1759,7 +1786,7 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress) // Invalidate the spectrum display cache if (mSpecCache) delete mSpecCache; - mSpecCache = new SpecCache(0, 1, false); + mSpecCache = new SpecCache(); } return !error; diff --git a/src/WaveClip.h b/src/WaveClip.h index 86eeaec07..ba0e52cb2 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -43,6 +43,7 @@ public: len = cacheLen; values = new float[len]; valid = false; + range = gain = -1; } ~SpecPxCache() @@ -53,6 +54,9 @@ public: sampleCount len; float *values; bool valid; + + int range; + int gain; }; class WaveClip;