From afa2fe9fb4252402d6a4279b15d51e090e496e03 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 4 Jun 2015 10:40:21 -0400 Subject: [PATCH] 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