From 38f24a42efcb18142cfebdebd3fd3acf80f6a4cb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 3 Jun 2015 23:02:37 -0400 Subject: [PATCH 1/4] 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; From 952a22c8b1f65f0e8f3a807c8d705494a00b1df3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 4 Jun 2015 00:05:46 -0400 Subject: [PATCH 2/4] Created a global structure to hold spectrogram preferences... Don't read "/Spectrum/" preferences anywhere but in SpectrumPrefs.cpp. Don't store global values in TrackArtist. Possibly some day, there will be other instances of SpectrogramSettings so we can have independent per-track settings. --- src/TrackArtist.cpp | 143 +++++++++++++++--------------------- src/TrackArtist.h | 24 ------ src/TrackPanel.cpp | 9 ++- src/WaveClip.cpp | 23 ++++-- src/prefs/SpectrumPrefs.cpp | 64 +++++++++++++++- src/prefs/SpectrumPrefs.h | 42 +++++++++++ 6 files changed, 183 insertions(+), 122 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index bca4ee442..8b9d1f18a 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -173,6 +173,7 @@ audio tracks. #include "LabelTrack.h" #include "TimeTrack.h" #include "Prefs.h" +#include "prefs/SpectrumPrefs.h" #include "Sequence.h" #include "Spectrum.h" #include "ViewInfo.h" @@ -270,14 +271,6 @@ TrackArtist::TrackArtist() SetColours(); vruler = new Ruler(); - -#ifdef EXPERIMENTAL_FFT_Y_GRID - fftYGridOld=true; -#endif //EXPERIMENTAL_FFT_Y_GRID - -#ifdef EXPERIMENTAL_FIND_NOTES - fftFindNotesOld=false; -#endif } TrackArtist::~TrackArtist() @@ -811,14 +804,14 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & r) int maxFreq = GetSpectrumMaxFreq(freq); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - maxFreq/=(mFftSkipPoints+1); + maxFreq/=(fftSkipPoints+1); #endif //EXPERIMENTAL_FFT_SKIP_POINTS if(maxFreq > freq) maxFreq = freq; int minFreq = GetSpectrumMinFreq(0); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - minFreq/=(mFftSkipPoints+1); + minFreq/=(fftSkipPoints+1); #endif //EXPERIMENTAL_FFT_SKIP_POINTS if(minFreq < 0) minFreq = 0; @@ -857,14 +850,14 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & r) int maxFreq = GetSpectrumLogMaxFreq(freq); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - maxFreq/=(mFftSkipPoints+1); + maxFreq/=(fftSkipPoints+1); #endif //EXPERIMENTAL_FFT_SKIP_POINTS if(maxFreq > freq) maxFreq = freq; int minFreq = GetSpectrumLogMinFreq(freq/1000.0); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - minFreq/=(mFftSkipPoints+1); + minFreq/=(fftSkipPoints+1); #endif //EXPERIMENTAL_FFT_SKIP_POINTS if(minFreq < 1) minFreq = 1; @@ -1936,9 +1929,16 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, } #endif - int range = gPrefs->Read(wxT("/Spectrum/Range"), 80L); - int gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L); - + const SpectrogramSettings &settings = SpectrogramSettings::defaults(); + const bool &isGrayscale = settings.isGrayscale; + const int &range = settings.range; + const int &gain = settings.gain; +#ifdef EXPERIMENTAL_FIND_NOTES + const bool &fftFindNotes = settings.fftFindNotes; + const bool &findNotesMinA = settings.findNotesMinA; + const bool &numberOfMaxima = settings.numberOfMaxima; + const bool &findNotesQuantize = settings.findNotesQuantize; +#endif dc.SetPen(*wxTRANSPARENT_PEN); @@ -1959,7 +1959,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, t0, pps, autocorrelation); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L); + int fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints; int fftSkipPoints1 = fftSkipPoints + 1; #endif //EXPERIMENTAL_FFT_SKIP_POINTS @@ -2009,8 +2009,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, for (int y = 0; y < mid.height; y++) { float n = (float(y) / mid.height*scale2 - lmin2) * 12; float n2 = (float(y + 1) / mid.height*scale2 - lmin2) * 12; - float f = float(minFreq) / (mFftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2); - float f2 = float(minFreq) / (mFftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2); + float f = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2); + float f2 = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2); n = logf(f / 440) / log2 * 12; n2 = logf(f2 / 440) / log2 * 12; if (floor(n) < floor(n2)) @@ -2024,13 +2024,13 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, && gain == clip->mSpecPxCache->gain && range == clip->mSpecPxCache->range #ifdef EXPERIMENTAL_FFT_Y_GRID - && mFftYGrid==fftYGridOld + && fftYGrid==fftYGridOld #endif //EXPERIMENTAL_FFT_Y_GRID #ifdef EXPERIMENTAL_FIND_NOTES - && mFftFindNotes==fftFindNotesOld - && mFindNotesMinA==findNotesMinAOld - && mNumberOfMaxima==findNotesNOld - && mFindNotesQuantize==findNotesQuantizeOld + && fftFindNotes==fftFindNotesOld + && findNotesMinA==findNotesMinAOld + && numberOfMaxima==findNotesNOld + && findNotesQuantize==findNotesQuantizeOld #endif ) { // cache is up to date @@ -2042,17 +2042,17 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, clip->mSpecPxCache->gain = gain; clip->mSpecPxCache->range = range; #ifdef EXPERIMENTAL_FIND_NOTES - fftFindNotesOld=mFftFindNotes; - findNotesMinAOld=mFindNotesMinA; - findNotesNOld=mNumberOfMaxima; - findNotesQuantizeOld=mFindNotesQuantize; + fftFindNotesOld = fftFindNotes; + findNotesMinAOld = findNotesMinA; + findNotesNOld = numberOfMaxima; + findNotesQuantizeOld = findNotesQuantize; #endif #ifdef EXPERIMENTAL_FIND_NOTES const float #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - lmins = logf(float(minFreq) / (mFftSkipPoints + 1)), - lmaxs = logf(float(maxFreq) / (mFftSkipPoints + 1)), + lmins = logf(float(minFreq) / (fftSkipPoints + 1)), + lmaxs = logf(float(maxFreq) / (fftSkipPoints + 1)), #else //!EXPERIMENTAL_FFT_SKIP_POINTS lmins = lmin, lmaxs = lmax, @@ -2065,7 +2065,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, float maxima0[128], maxima1[128]; const float #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - f2bin = half / (rate / 2.0f / (mFftSkipPoints + 1)), + f2bin = half / (rate / 2.0f / (fftSkipPoints + 1)), #else //!EXPERIMENTAL_FFT_SKIP_POINTS f2bin = half / (rate / 2.0f), #endif //EXPERIMENTAL_FFT_SKIP_POINTS @@ -2092,7 +2092,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, else { #ifdef EXPERIMENTAL_FIND_NOTES int maximas=0; - if (!usePxCache && mFftFindNotes) { + if (!usePxCache && fftFindNotes) { for (int i = maxTableSize-1; i >= 0; i--) indexes[i]=-1; @@ -2111,7 +2111,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, int index=indexes[i]; if (index >= 0) { float freqi=freq[x0+index]; - if (freqi < mFindNotesMinA) + if (freqi < findNotesMinA) break; bool ok=true; @@ -2125,7 +2125,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, } if (ok) { maxima[maximas++] = index; - if (maximas >= mNumberOfMaxima) + if (maximas >= numberOfMaxima) break; } } @@ -2138,7 +2138,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, for (int i=0; i < maximas; i++) { int index=maxima[i]; float f = float(index)*bin2f; - if (mFindNotesQuantize) + if (findNotesQuantize) { f = expf(int(log(f/440)/log2*12-0.5)/12.0f*log2)*440; maxima[i] = f*f2bin; } @@ -2172,7 +2172,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, float value; #ifdef EXPERIMENTAL_FIND_NOTES - if (mFftFindNotes) { + if (fftFindNotes) { if (it < maximas) { float i0=maxima0[it]; if (yy >= i0) @@ -2182,7 +2182,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, float i1=maxima1[it]; if (yy+1 <= i1) { value=sumFreqValues(freq, x0, bin0, bin1); - if (value < mFindNotesMinA) + if (value < findNotesMinA) value = minColor; else value = (value + gain + range) / (double)range; @@ -2253,7 +2253,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, unsigned char rv, gv, bv; const float value = clip->mSpecPxCache->values[x * mid.height + yy]; - GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv); + GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); int px = ((mid.height - 1 - yy) * mid.width + x) * 3; data[px++] = rv; data[px++] = gv; @@ -2293,10 +2293,10 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, yy2 = yy2_base; unsigned char rv, gv, bv; - GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv); + GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); #ifdef EXPERIMENTAL_FFT_Y_GRID - if (mFftYGrid && yGrid[yy]) { + if (fftYGrid && yGrid[yy]) { rv /= 1.1f; gv /= 1.1f; bv /= 1.1f; @@ -3043,99 +3043,74 @@ void TrackArtist::UpdatePrefs() mdBrange = gPrefs->Read(wxT("/GUI/EnvdBRange"), mdBrange); mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping); - // mMaxFreq should have the same default as in SpectrumPrefs. - mMaxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L); - mMinFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1); - mLogMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1); - if( mLogMaxFreq < 0 ) - mLogMaxFreq = mMaxFreq; - mLogMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1); - if( mLogMinFreq < 0 ) - mLogMinFreq = mMinFreq; - if (mLogMinFreq < 1) - mLogMinFreq = 1; - - mWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); -#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - mZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); -#endif - mIsGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0); - -#ifdef EXPERIMENTAL_FFT_Y_GRID - mFftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0); -#endif //EXPERIMENTAL_FFT_Y_GRID - -#ifdef EXPERIMENTAL_FIND_NOTES - mFftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0); - mFindNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0); - mNumberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L); - mFindNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0); -#endif //EXPERIMENTAL_FIND_NOTES - -#ifdef EXPERIMENTAL_FFT_SKIP_POINTS - mFftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L); -#endif //EXPERIMENTAL_FFT_SKIP_POINTS - gPrefs->Flush(); } // Get various preference values int TrackArtist::GetSpectrumMinFreq(int deffreq) { - return mMinFreq < 0 ? deffreq : mMinFreq; + const int &minFreq = SpectrogramSettings::defaults().minFreq; + return minFreq < 0 ? deffreq : minFreq; } int TrackArtist::GetSpectrumMaxFreq(int deffreq) { - return mMaxFreq < 0 ? deffreq : mMaxFreq; + const int &maxFreq = SpectrogramSettings::defaults().maxFreq; + return maxFreq < 0 ? deffreq : maxFreq; } int TrackArtist::GetSpectrumLogMinFreq(int deffreq) { - return mLogMinFreq < 0 ? deffreq : mLogMinFreq; + const int &logMinFreq = SpectrogramSettings::defaults().logMinFreq; + return logMinFreq < 0 ? deffreq : logMinFreq; } int TrackArtist::GetSpectrumLogMaxFreq(int deffreq) { - return mLogMaxFreq < 0 ? deffreq : mLogMaxFreq; + const int &logMaxFreq = SpectrogramSettings::defaults().logMaxFreq; + return logMaxFreq < 0 ? deffreq : logMaxFreq; } int TrackArtist::GetSpectrumWindowSize(bool includeZeroPadding) { + includeZeroPadding; + const int &windowSize = SpectrogramSettings::defaults().windowSize; #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - if (includeZeroPadding) - return mWindowSize * mZeroPaddingFactor; + if (includeZeroPadding) { + const int &zeroPaddingFactor = SpectrogramSettings::defaults().zeroPaddingFactor; + return windowSize * zeroPaddingFactor; + } else #endif - return mWindowSize; + return windowSize; } #ifdef EXPERIMENTAL_FFT_SKIP_POINTS int TrackArtist::GetSpectrumFftSkipPoints() { - return mFftSkipPoints; + return SpectrogramSettings::defaults().fftSkipPoints; } #endif // Set various preference values void TrackArtist::SetSpectrumMinFreq(int freq) { - mMinFreq = freq; + SpectrogramSettings::defaults().minFreq = freq; } void TrackArtist::SetSpectrumMaxFreq(int freq) { - mMaxFreq = freq; + SpectrogramSettings::defaults().maxFreq = freq; } void TrackArtist::SetSpectrumLogMinFreq(int freq) { - mLogMinFreq = freq; + SpectrogramSettings::defaults().logMinFreq = freq; } void TrackArtist::SetSpectrumLogMaxFreq(int freq) { - mLogMaxFreq = freq; + SpectrogramSettings::defaults().logMaxFreq = freq; } // Draws the sync-lock bitmap, tiled; always draws stationary relative to the DC diff --git a/src/TrackArtist.h b/src/TrackArtist.h index cb78093eb..a192d0998 100644 --- a/src/TrackArtist.h +++ b/src/TrackArtist.h @@ -173,32 +173,8 @@ class AUDACITY_DLL_API TrackArtist { // Preference values float mdBrange; // "/GUI/EnvdBRange" long mShowClipping; // "/GUI/ShowClipping" - int mLogMaxFreq; // "/SpectrumLog/MaxFreq" - int mLogMinFreq; // "/SpectrumLog/MinFreq" - int mMaxFreq; // "/Spectrum/MaxFreq" - int mMinFreq; // "/Spectrum/MinFreq" - int mWindowSize; // "/Spectrum/FFTSize" -#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - int mZeroPaddingFactor; // "/Spectrum/ZeroPaddingFactor" -#endif - bool mIsGrayscale; // "/Spectrum/Grayscale" bool mbShowTrackNameInWaveform; // "/GUI/ShowTrackNameInWaveform" -#ifdef EXPERIMENTAL_FFT_SKIP_POINTS - int mFftSkipPoints; // "/Spectrum/FFTSkipPoints" -#endif //EXPERIMENTAL_FFT_SKIP_POINTS - -#ifdef EXPERIMENTAL_FFT_Y_GRID - bool mFftYGrid; // "/Spectrum/FFTYGrid" -#endif //EXPERIMENTAL_FFT_Y_GRID - -#ifdef EXPERIMENTAL_FIND_NOTES - bool mFftFindNotes; // "/Spectrum/FFTFindNotes" - float mFindNotesMinA; // "/Spectrum/FindNotesMinA" - int mNumberOfMaxima; // "/Spectrum/FindNotesN" - bool mFindNotesQuantize; // "/Spectrum/FindNotesQuantize") -#endif //EXPERIMENTAL_FIND_NOTES - int mInsetLeft; int mInsetTop; int mInsetRight; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 5b2102588..c88df224d 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -214,6 +214,8 @@ is time to refresh some aspect of the screen. #include "ondemand/ODManager.h" +#include "prefs/SpectrumPrefs.h" + #include "toolbars/ControlToolBar.h" #include "toolbars/ToolManager.h" #include "toolbars/ToolsToolBar.h" @@ -3045,8 +3047,7 @@ void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack) while(windowSize > effectiveLength) windowSize >>= 1; - int windowType; - gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3); + const int windowType = SpectrogramSettings::defaults().windowType; mFrequencySnapper->Calculate( SpectrumAnalyst::Spectrum, windowType, windowSize, rate, &frequencySnappingData[0], length); @@ -4722,7 +4723,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event ) // Always spectrogram, never pitch view, pass true windowSize = mTrackArtist->GetSpectrumWindowSize(true); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints(); + fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints; #endif //EXPERIMENTAL_FFT_SKIP_POINTS binSize = rate / windowSize; minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less @@ -4739,7 +4740,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event ) // Always spectrogram, never pitch view, pass true windowSize = mTrackArtist->GetSpectrumWindowSize(true); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints(); + fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints; #endif //EXPERIMENTAL_FFT_SKIP_POINTS binSize = rate / windowSize; minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 34a5b119a..7dc0175d3 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -39,6 +39,8 @@ drawing). Cache's the Spectrogram frequency samples. #include "Resample.h" #include "Project.h" +#include "prefs/SpectrumPrefs.h" + #include WX_DEFINE_LIST(WaveClipList); @@ -904,16 +906,21 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, double t0, double pixelsPerSecond, bool autocorrelation) { - int frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L); - int windowType; - int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); + const SpectrogramSettings &settings = SpectrogramSettings::defaults(); + #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L); - int fftSkipPoints1 = fftSkipPoints+1; + int fftSkipPoints = settings.fftSkipPoints; + int fftSkipPoints1 = fftSkipPoints + 1; #endif //EXPERIMENTAL_FFT_SKIP_POINTS - const int zeroPaddingFactor = - autocorrelation ? 1 : gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); - gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3); + + const int &frequencyGain = settings.frequencyGain; + const int &windowSize = settings.windowSize; + const int &windowType = settings.windowType; +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + const int &zeroPaddingFactor = autocorrelation ? 1 : settings.zeroPaddingFactor; +#else + const int zeroPaddingFactor = 1; +#endif // FFT length may be longer than the window of samples that affect results // because of zero padding done for increased frequency resolution diff --git a/src/prefs/SpectrumPrefs.cpp b/src/prefs/SpectrumPrefs.cpp index 344fbc2fc..a2e6c13f6 100644 --- a/src/prefs/SpectrumPrefs.cpp +++ b/src/prefs/SpectrumPrefs.cpp @@ -15,6 +15,7 @@ *//*******************************************************************/ #include "../Audacity.h" +#include "SpectrumPrefs.h" #include #include @@ -23,7 +24,6 @@ #include "../Prefs.h" #include "../Project.h" #include "../ShuttleGui.h" -#include "SpectrumPrefs.h" #include "../FFT.h" SpectrumPrefs::SpectrumPrefs(wxWindow * parent) @@ -352,10 +352,12 @@ bool SpectrumPrefs::Apply() ShuttleGui S(this, eIsSavingToPrefs); PopulateOrExchange(S); + SpectrogramSettings::defaults().UpdatePrefs(); + return true; } -void SpectrumPrefs::OnWindowSize(wxCommandEvent &event) +void SpectrumPrefs::OnWindowSize(wxCommandEvent &) { wxChoice *const pWindowSizeControl = static_cast(wxWindow::FindWindowById(ID_WINDOW_SIZE, this)); @@ -366,3 +368,61 @@ void SpectrumPrefs::OnWindowSize(wxCommandEvent &event) BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel) EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize) END_EVENT_TABLE() + +SpectrogramSettings::SpectrogramSettings() +{ + UpdatePrefs(); +} + +SpectrogramSettings& SpectrogramSettings::defaults() +{ + static SpectrogramSettings instance; + return instance; +} + +void SpectrogramSettings::UpdatePrefs() +{ + minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L); + maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L); + + // These preferences are not written anywhere in the program as of now, + // but I keep this legacy here. Who knows, someone might edit prefs files + // directly. PRL + logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1); + if (logMaxFreq < 0) + logMaxFreq = maxFreq; + logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1); + if (logMinFreq < 0) + logMinFreq = minFreq; + if (logMinFreq < 1) + logMinFreq = 1; + + range = gPrefs->Read(wxT("/Spectrum/Range"), 80L); + gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L); + frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L); + + windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); + +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + zeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); +#endif + + gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3); + + isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0); + +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L); +#endif + +#ifdef EXPERIMENTAL_FFT_Y_GRID + fftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0); +#endif //EXPERIMENTAL_FFT_Y_GRID + +#ifdef EXPERIMENTAL_FIND_NOTES + fftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0); + findNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0); + numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L); + findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0); +#endif //EXPERIMENTAL_FIND_NOTES +} diff --git a/src/prefs/SpectrumPrefs.h b/src/prefs/SpectrumPrefs.h index acb08866e..b40ef4483 100644 --- a/src/prefs/SpectrumPrefs.h +++ b/src/prefs/SpectrumPrefs.h @@ -71,4 +71,46 @@ class SpectrumPrefs:public PrefsPanel #endif }; + +struct SpectrogramSettings +{ + static SpectrogramSettings &defaults(); + SpectrogramSettings(); + + void UpdatePrefs(); + + int minFreq; + int maxFreq; + + int logMinFreq; + int logMaxFreq; + + int range; + int gain; + int frequencyGain; + + int windowType; + int windowSize; +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + int zeroPaddingFactor; +#endif + + bool isGrayscale; + +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + int fftSkipPoints; +#endif + +#ifdef EXPERIMENTAL_FFT_Y_GRID + bool fftYGrid; +#endif //EXPERIMENTAL_FFT_Y_GRID + +#ifdef EXPERIMENTAL_FIND_NOTES + bool fftFindNotes; + bool findNotesMinA; + bool numberOfMaxima; + bool findNotesQuantize; +#endif //EXPERIMENTAL_FIND_NOTES +}; + #endif From afa2fe9fb4252402d6a4279b15d51e090e496e03 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 4 Jun 2015 10:40:21 -0400 Subject: [PATCH 3/4] Keep FFT windows for Spectrograms in one place in SpectrogramSettings... ... not redundantly in each WaveClip. --- src/RealFFTf.h | 6 +- src/WaveClip.cpp | 108 ++----------------------------- src/WaveClip.h | 8 --- src/prefs/SpectrumPrefs.cpp | 124 +++++++++++++++++++++++++++++++++++- src/prefs/SpectrumPrefs.h | 13 ++++ 5 files changed, 144 insertions(+), 115 deletions(-) diff --git a/src/RealFFTf.h b/src/RealFFTf.h index b3bacab7a..6e7b44383 100644 --- a/src/RealFFTf.h +++ b/src/RealFFTf.h @@ -2,15 +2,15 @@ #define __realfftf_h #define fft_type float -typedef struct FFTParamType { +struct FFTParam { int *BitReversed; fft_type *SinTable; int Points; #ifdef EXPERIMENTAL_EQ_SSE_THREADED int pow2Bits; #endif -} FFTParam; -#define HFFT FFTParam * +}; +typedef FFTParam * HFFT; HFFT InitializeFFT(int); void EndFFT(HFFT); diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 7dc0175d3..6d42f275f 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -336,7 +336,7 @@ public: #ifdef EXPERIMENTAL_USE_REALFFTF #include "FFT.h" -static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, float *window, int len, float *out) +static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, const float *window, int len, float *out) { int i; if(len > hFFT->Points*2) @@ -371,13 +371,6 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate) mSequence = new Sequence(projDirManager, format); mEnvelope = new Envelope(); mWaveCache = new WaveCache(0); -#ifdef EXPERIMENTAL_USE_REALFFTF - mWindowType = -1; - mWindowSize = -1; - hFFT = NULL; - mWindow = NULL; -#endif - mZeroPaddingFactor = 1; mSpecCache = new SpecCache(); mSpecPxCache = new SpecPxCache(1); mAppendBuffer = NULL; @@ -400,13 +393,6 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager) mEnvelope->SetOffset(orig.GetOffset()); mEnvelope->SetTrackLen(((double)orig.mSequence->GetNumSamples()) / orig.mRate); mWaveCache = new WaveCache(0); -#ifdef EXPERIMENTAL_USE_REALFFTF - mWindowType = -1; - mWindowSize = -1; - hFFT = NULL; - mWindow = NULL; -#endif - mZeroPaddingFactor = 1; mSpecCache = new SpecCache(); mSpecPxCache = new SpecPxCache(1); @@ -429,12 +415,6 @@ WaveClip::~WaveClip() delete mWaveCache; delete mSpecCache; delete mSpecPxCache; -#ifdef EXPERIMENTAL_USE_REALFFTF - if(hFFT != NULL) - EndFFT(hFFT); - if(mWindow != NULL) - delete[] mWindow; -#endif if (mAppendBuffer) DeleteSamples(mAppendBuffer); @@ -820,67 +800,6 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, return true; } -namespace -{ -enum { WINDOW, TWINDOW, DWINDOW }; -void RecreateWindow( - float *&window, int which, int fftLen, - int padding, int windowType, int windowSize, double &scale) -{ - if (window != NULL) - delete[] window; - // Create the requested window function - window = new float[fftLen]; - int ii; - - wxASSERT(windowSize % 2 == 0); - const int endOfWindow = padding + windowSize; - // Left and right padding - for (ii = 0; ii < padding; ++ii) { - window[ii] = 0.0; - window[fftLen - ii - 1] = 0.0; - } - // Default rectangular window in the middle - for (; ii < endOfWindow; ++ii) - window[ii] = 1.0; - // Overwrite middle as needed - switch (which) { - case WINDOW: - WindowFunc(windowType, windowSize, window + padding); - // NewWindowFunc(windowType, windowSize, extra, window + padding); - break; - case TWINDOW: - wxASSERT(false); -#if 0 - // Future, reassignment - NewWindowFunc(windowType, windowSize, extra, window + padding); - for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier) - window[ii] *= multiplier; - break; -#endif - case DWINDOW: - wxASSERT(false); -#if 0 - // Future, reassignment - DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding); - break; -#endif - default: - wxASSERT(false); - } - // Scale the window function to give 0dB spectrum for 0dB sine tone - if (which == WINDOW) { - scale = 0.0; - for (ii = padding; ii < endOfWindow; ++ii) - scale += window[ii]; - if (scale > 0) - scale = 2.0 / scale; - } - for (ii = padding; ii < endOfWindow; ++ii) - window[ii] *= scale; -} -} - void WaveClip::ComputeSpectrogramGainFactors(int fftLen, int frequencyGain, std::vector &gainFactors) { if (frequencyGain > 0) { @@ -921,6 +840,11 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, #else const int zeroPaddingFactor = 1; #endif +#ifdef EXPERIMENTAL_USE_REALFFTF + settings.CacheWindows(); + const HFFT &hFFT = settings.hFFT; + const float *const &window = settings.window; +#endif // FFT length may be longer than the window of samples that affect results // because of zero padding done for increased frequency resolution @@ -928,24 +852,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, const int half = fftLen / 2; const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2; -#ifdef EXPERIMENTAL_USE_REALFFTF - // Update the FFT and window if necessary - if((mWindowType != windowType) || (mWindowSize != windowSize) - || (hFFT == NULL) || (mWindow == NULL) || (fftLen != hFFT->Points * 2) - || (mZeroPaddingFactor != zeroPaddingFactor)) { - mWindowType = windowType; - mWindowSize = windowSize; - if(hFFT != NULL) - EndFFT(hFFT); - hFFT = InitializeFFT(fftLen); - double scale; - RecreateWindow(mWindow, WINDOW, fftLen, padding, mWindowType, mWindowSize, scale); - } -#endif // EXPERIMENTAL_USE_REALFFTF - - - mZeroPaddingFactor = zeroPaddingFactor; - const bool match = mSpecCache && mSpecCache->dirty == mDirty && @@ -1119,7 +1025,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, mRate, &mSpecCache->freq[half * x], autocorrelation, windowType); } else { - ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, fftLen, &mSpecCache->freq[half * x]); + ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, window, fftLen, &mSpecCache->freq[half * x]); } #else // EXPERIMENTAL_USE_REALFFTF ComputeSpectrum(buffer, windowSize, windowSize, diff --git a/src/WaveClip.h b/src/WaveClip.h index ba0e52cb2..e9fbfeafc 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -307,14 +307,6 @@ protected: WaveCache *mWaveCache; ODLock mWaveCacheMutex; SpecCache *mSpecCache; -#ifdef EXPERIMENTAL_USE_REALFFTF - // Variables used for computing the spectrum - HFFT hFFT; - float *mWindow; - int mWindowType; - int mWindowSize; -#endif - int mZeroPaddingFactor; samplePtr mAppendBuffer; sampleCount mAppendBufferLen; diff --git a/src/prefs/SpectrumPrefs.cpp b/src/prefs/SpectrumPrefs.cpp index a2e6c13f6..cd2920ec1 100644 --- a/src/prefs/SpectrumPrefs.cpp +++ b/src/prefs/SpectrumPrefs.cpp @@ -370,6 +370,8 @@ BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel) END_EVENT_TABLE() SpectrogramSettings::SpectrogramSettings() +: hFFT(0) +, window(0) { UpdatePrefs(); } @@ -382,6 +384,8 @@ SpectrogramSettings& SpectrogramSettings::defaults() void SpectrogramSettings::UpdatePrefs() { + bool destroy = false; + minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L); maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L); @@ -401,13 +405,26 @@ void SpectrogramSettings::UpdatePrefs() gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L); frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L); - windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); + const int newWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); + if (newWindowSize != windowSize) { + destroy = true; + windowSize = newWindowSize; + } #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - zeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); + const int newZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); + if (newZeroPaddingFactor != zeroPaddingFactor) { + destroy = true; + zeroPaddingFactor = newZeroPaddingFactor; + } #endif - gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3); + int newWindowType; + gPrefs->Read(wxT("/Spectrum/WindowType"), &newWindowType, 3); + if (newWindowType != windowType) { + destroy = true; + windowType = newWindowType; + } isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0); @@ -425,4 +442,105 @@ void SpectrogramSettings::UpdatePrefs() numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L); findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0); #endif //EXPERIMENTAL_FIND_NOTES + + if (destroy) + DestroyWindows(); +} + +SpectrogramSettings::~SpectrogramSettings() +{ + DestroyWindows(); +} + +void SpectrogramSettings::DestroyWindows() +{ +#ifdef EXPERIMENTAL_USE_REALFFTF + if (hFFT != NULL) { + EndFFT(hFFT); + hFFT = NULL; + } + if (window != NULL) { + delete[] window; + window = NULL; + } +#endif +} + + +namespace +{ + enum { WINDOW, TWINDOW, DWINDOW }; + void RecreateWindow( + float *&window, int which, int fftLen, + int padding, int windowType, int windowSize, double &scale) + { + if (window != NULL) + delete[] window; + // Create the requested window function + window = new float[fftLen]; + int ii; + + wxASSERT(windowSize % 2 == 0); + const int endOfWindow = padding + windowSize; + // Left and right padding + for (ii = 0; ii < padding; ++ii) { + window[ii] = 0.0; + window[fftLen - ii - 1] = 0.0; + } + // Default rectangular window in the middle + for (; ii < endOfWindow; ++ii) + window[ii] = 1.0; + // Overwrite middle as needed + switch (which) { + case WINDOW: + WindowFunc(windowType, windowSize, window + padding); + // NewWindowFunc(windowType, windowSize, extra, window + padding); + break; + case TWINDOW: + wxASSERT(false); +#if 0 + // Future, reassignment + NewWindowFunc(windowType, windowSize, extra, window + padding); + for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier) + window[ii] *= multiplier; + break; +#endif + case DWINDOW: + wxASSERT(false); +#if 0 + // Future, reassignment + DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding); + break; +#endif + default: + wxASSERT(false); + } + // Scale the window function to give 0dB spectrum for 0dB sine tone + if (which == WINDOW) { + scale = 0.0; + for (ii = padding; ii < endOfWindow; ++ii) + scale += window[ii]; + if (scale > 0) + scale = 2.0 / scale; + } + for (ii = padding; ii < endOfWindow; ++ii) + window[ii] *= scale; + } +} + +void SpectrogramSettings::CacheWindows() const +{ +#ifdef EXPERIMENTAL_USE_REALFFTF + if (hFFT == NULL || window == NULL) { + + double scale; + const int fftLen = windowSize * zeroPaddingFactor; + const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2; + + if (hFFT != NULL) + EndFFT(hFFT); + hFFT = InitializeFFT(fftLen); + RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale); + } +#endif // EXPERIMENTAL_USE_REALFFTF } diff --git a/src/prefs/SpectrumPrefs.h b/src/prefs/SpectrumPrefs.h index b40ef4483..9a3ad1370 100644 --- a/src/prefs/SpectrumPrefs.h +++ b/src/prefs/SpectrumPrefs.h @@ -30,6 +30,8 @@ #include "PrefsPanel.h" +struct FFTParam; + class SpectrumPrefs:public PrefsPanel { public: @@ -76,8 +78,11 @@ struct SpectrogramSettings { static SpectrogramSettings &defaults(); SpectrogramSettings(); + ~SpectrogramSettings(); void UpdatePrefs(); + void DestroyWindows(); + void CacheWindows() const; int minFreq; int maxFreq; @@ -111,6 +116,14 @@ struct SpectrogramSettings bool numberOfMaxima; bool findNotesQuantize; #endif //EXPERIMENTAL_FIND_NOTES + + // Following fields are derived from preferences. + +#ifdef EXPERIMENTAL_USE_REALFFTF + // Variables used for computing the spectrum + mutable FFTParam *hFFT; + mutable float *window; +#endif }; #endif From 1916bc3142724a3d8341ad6d0e1b31b39a2da707 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 4 Jun 2015 11:26:24 -0400 Subject: [PATCH 4/4] Fix compilation of some disabled experimental branches for spectrograms ... ... Not promising that they work, just compilation. --- src/TrackArtist.cpp | 45 ++++++++++++++++++++++++--------------------- src/WaveClip.cpp | 4 ++-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 8b9d1f18a..214de0c8a 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -665,6 +665,10 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & r) void TrackArtist::UpdateVRuler(Track *t, wxRect & r) { +#ifdef EXPERIMENTAL_FFT_SKIP_POINTS + const int fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints; +#endif //EXPERIMENTAL_FFT_SKIP_POINTS + // Label tracks do not have a vruler if (t->GetKind() == Track::Label) { return; @@ -1939,6 +1943,9 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, const bool &numberOfMaxima = settings.numberOfMaxima; const bool &findNotesQuantize = settings.findNotesQuantize; #endif +#ifdef EXPERIMENTAL_FFT_Y_GRID + const bool &fftYGrid = settings.fftYGrid; +#endif dc.SetPen(*wxTRANSPARENT_PEN); @@ -2049,13 +2056,13 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, #endif #ifdef EXPERIMENTAL_FIND_NOTES - const float #ifdef EXPERIMENTAL_FFT_SKIP_POINTS + const float lmins = logf(float(minFreq) / (fftSkipPoints + 1)), - lmaxs = logf(float(maxFreq) / (fftSkipPoints + 1)), + lmaxs = logf(float(maxFreq) / (fftSkipPoints + 1)) #else //!EXPERIMENTAL_FFT_SKIP_POINTS lmins = lmin, - lmaxs = lmax, + lmaxs = lmax #endif //EXPERIMENTAL_FFT_SKIP_POINTS ; #endif //EXPERIMENTAL_FIND_NOTES @@ -2092,13 +2099,14 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, else { #ifdef EXPERIMENTAL_FIND_NOTES int maximas=0; - if (!usePxCache && fftFindNotes) { + const int x0 = half * x; + if (fftFindNotes) { for (int i = maxTableSize-1; i >= 0; i--) indexes[i]=-1; // Build a table of (most) values, put the index in it. for (int i = int(i0); i < int(i1); i++) { - float freqi=freq[x0+int(i)]; + float freqi=freq[x0 + int(i)]; int value=int((freqi+gain+range)/range*(maxTableSize-1)); if (value < 0) value=0; @@ -2107,19 +2115,19 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, indexes[value]=i; } // Build from the indices an array of maxima. - for (int i = maxTableSize-1; i >= 0; i--) { - int index=indexes[i]; + for (int i = maxTableSize - 1; i >= 0; i--) { + int index = indexes[i]; if (index >= 0) { - float freqi=freq[x0+index]; + float freqi = freq[x0 + index]; if (freqi < findNotesMinA) break; - bool ok=true; - for (int m=0; m < maximas; m++) { + bool ok = true; + for (int m = 0; m < maximas; m++) { // Avoid to store very close maxima. float maxm = maxima[m]; - if (maxm/index < minDistance && index/maxm < minDistance) { - ok=false; + if (maxm / index < minDistance && index / maxm < minDistance) { + ok = false; break; } } @@ -2127,9 +2135,9 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, maxima[maximas++] = index; if (maximas >= numberOfMaxima) break; - } - } - } + } + } + } // The f2pix helper macro converts a frequency into a pixel coordinate. #define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*mid.height @@ -2181,11 +2189,9 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, if (inMaximum) { float i1=maxima1[it]; if (yy+1 <= i1) { - value=sumFreqValues(freq, x0, bin0, bin1); + value=findValue(freq + x0, bin0, bin1, half, autocorrelation, gain, range); if (value < findNotesMinA) value = minColor; - else - value = (value + gain + range) / (double)range; } else { it++; inMaximum = false; @@ -2329,9 +2335,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache, #ifdef EXPERIMENTAL_FFT_Y_GRID delete[] yGrid; #endif //EXPERIMENTAL_FFT_Y_GRID -#ifdef EXPERIMENTAL_FIND_NOTES - delete[] indexes; -#endif //EXPERIMENTAL_FIND_NOTES } void TrackArtist::InvalidateSpectrumCache(TrackList *tracks) diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 6d42f275f..69e4799ce 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -268,7 +268,7 @@ public: , zeroPaddingFactor(-1) , frequencyGain(-1) #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - , fftSkipPoints(-1); + , fftSkipPoints(-1) #endif //EXPERIMENTAL_FFT_SKIP_POINTS , freq(NULL) @@ -295,7 +295,7 @@ public: , zeroPaddingFactor(zeroPaddingFactor_) , frequencyGain(frequencyGain_) #ifdef EXPERIMENTAL_FFT_SKIP_POINTS - , fftSkipPoints(fftSkipPoints_); + , fftSkipPoints(fftSkipPoints_) #endif //EXPERIMENTAL_FFT_SKIP_POINTS // len columns, and so many rows, column-major.