/* This version keeps common tables rather than allocating a new table every time */ HFFT GetFFT(int fftlen) { int h,n = fftlen/2; for(h=0; (h<MAX_HFFT) && (hFFTArray[h] != NULL) && (n != hFFTArray[h]->Points); h++); if(h<MAX_HFFT) { if(hFFTArray[h] == NULL) { hFFTArray[h] = InitializeFFT(fftlen); nFFTLockCount[h] = 0; } nFFTLockCount[h]++; return hFFTArray[h]; } else { // All buffers used, so fall back to allocating a new set of tables return InitializeFFT(fftlen);; } }
void EffectNoiseRemoval::Initialize() { int i; mSampleRate = mProjectRate; mFreqSmoothingBins = (int)(mFreqSmoothingHz * mWindowSize / mSampleRate); mAttackDecayBlocks = 1 + (int)(mAttackDecayTime * mSampleRate / (mWindowSize / 2)); mNoiseAttenFactor = pow(10.0, mNoiseGain/20.0); mOneBlockAttackDecay = pow(10.0, (mNoiseGain / (10.0 * mAttackDecayBlocks))); mSensitivityFactor = pow(10.0, mSensitivity/10.0); mMinSignalBlocks = (int)(mMinSignalTime * mSampleRate / (mWindowSize / 2)); if( mMinSignalBlocks < 1 ) mMinSignalBlocks = 1; mHistoryLen = (2 * mAttackDecayBlocks) - 1; if (mHistoryLen < mMinSignalBlocks) mHistoryLen = mMinSignalBlocks; mSpectrums = new float*[mHistoryLen]; mGains = new float*[mHistoryLen]; mRealFFTs = new float*[mHistoryLen]; mImagFFTs = new float*[mHistoryLen]; for(i = 0; i < mHistoryLen; i++) { mSpectrums[i] = new float[mSpectrumSize]; mGains[i] = new float[mSpectrumSize]; mRealFFTs[i] = new float[mSpectrumSize]; mImagFFTs[i] = new float[mSpectrumSize]; } // Initialize the FFT hFFT = InitializeFFT(mWindowSize); mFFTBuffer = new float[mWindowSize]; mInWaveBuffer = new float[mWindowSize]; mWindow = new float[mWindowSize]; mOutImagBuffer = new float[mWindowSize]; mOutOverlapBuffer = new float[mWindowSize]; // Create a Hanning window function for(i=0; i<mWindowSize; i++) mWindow[i] = 0.5 - 0.5 * cos((2.0*M_PI*i) / mWindowSize); if (mDoProfile) { for (i = 0; i < mSpectrumSize; i++) mNoiseThreshold[i] = float(0); } }
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 }
void SpectrogramSettings::CacheWindows() const { if (hFFT == NULL || window == NULL) { double scale; const auto fftLen = WindowSize() * ZeroPaddingFactor(); const auto padding = (windowSize * (zeroPaddingFactor - 1)) / 2; if (hFFT != NULL) EndFFT(hFFT); hFFT = InitializeFFT(fftLen); RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale); if (algorithm == algReassignment) { RecreateWindow(tWindow, TWINDOW, fftLen, padding, windowType, windowSize, scale); RecreateWindow(dWindow, DWINDOW, fftLen, padding, windowType, windowSize, scale); } } }
bool WaveClip::GetSpectrogram(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); 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); #ifdef EXPERIMENTAL_FFT_SKIP_POINTS int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L); int fftSkipPoints1 = fftSkipPoints+1; #endif //EXPERIMENTAL_FFT_SKIP_POINTS int half = windowSize/2; gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3); #ifdef EXPERIMENTAL_USE_REALFFTF // Update the FFT and window if necessary if((mWindowType != windowType) || (mWindowSize != windowSize) || (hFFT == NULL) || (mWindow == NULL) || (mWindowSize != hFFT->Points*2) ) { mWindowType = windowType; mWindowSize = windowSize; if(hFFT != NULL) EndFFT(hFFT); hFFT = InitializeFFT(mWindowSize); if(mWindow != NULL) delete[] mWindow; // Create the requested window function mWindow = new float[mWindowSize]; int i; for(i=0; i<windowSize; i++) mWindow[i]=1.0; WindowFunc(mWindowType, mWindowSize, mWindow); // Scale the window function to give 0dB spectrum for 0dB sine tone double ws=0; for(i=0; i<windowSize; i++) ws += mWindow[i]; if(ws > 0) { ws = 2.0/ws; for(i=0; i<windowSize; i++) mWindow[i] *= ws; } } #endif // EXPERIMENTAL_USE_REALFFTF if (mSpecCache && mSpecCache->minFreqOld == minFreq && mSpecCache->maxFreqOld == maxFreq && mSpecCache->rangeOld == range && mSpecCache->gainOld == gain && mSpecCache->windowTypeOld == windowType && mSpecCache->windowSizeOld == windowSize && mSpecCache->frequencyGainOld == frequencygain && #ifdef EXPERIMENTAL_FFT_SKIP_POINTS mSpecCache->fftSkipPointsOld == fftSkipPoints && #endif //EXPERIMENTAL_FFT_SKIP_POINTS mSpecCache->dirty == mDirty && mSpecCache->start == t0 && mSpecCache->ac == autocorrelation && mSpecCache->len >= numPixels && mSpecCache->pps == pixelsPerSecond) { memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float)); memcpy(where, mSpecCache->where, (numPixels+1)*sizeof(sampleCount)); return false; //hit cache completely } SpecCache *oldCache = mSpecCache; mSpecCache = new SpecCache(numPixels, half, autocorrelation); mSpecCache->pps = pixelsPerSecond; mSpecCache->start = t0; sampleCount x; bool *recalc = new bool[mSpecCache->len + 1]; for (x = 0; x < mSpecCache->len + 1; x++) { recalc[x] = true; // purposely offset the display 1/2 bin to the left (as compared // to waveform display to properly center response of the FFT mSpecCache->where[x] = (sampleCount)floor((t0*mRate) + (x*mRate/pixelsPerSecond) + 1.); } // Optimization: if the old cache is good and overlaps // with the current one, re-use as much of the cache as // possible if (oldCache->dirty == mDirty && oldCache->minFreqOld == minFreq && oldCache->maxFreqOld == maxFreq && oldCache->rangeOld == range && oldCache->gainOld == gain && oldCache->windowTypeOld == windowType && oldCache->windowSizeOld == windowSize && oldCache->frequencyGainOld == frequencygain && #ifdef EXPERIMENTAL_FFT_SKIP_POINTS oldCache->fftSkipPointsOld == fftSkipPoints && #endif //EXPERIMENTAL_FFT_SKIP_POINTS oldCache->pps == pixelsPerSecond && oldCache->ac == autocorrelation && oldCache->where[0] < mSpecCache->where[mSpecCache->len] && oldCache->where[oldCache->len] > mSpecCache->where[0]) { for (x = 0; x < mSpecCache->len; x++) if (mSpecCache->where[x] >= oldCache->where[0] && mSpecCache->where[x] <= oldCache->where[oldCache->len]) { int ox = (int) ((double (oldCache->len) * (mSpecCache->where[x] - oldCache->where[0])) / (oldCache->where[oldCache->len] - oldCache->where[0]) + 0.5); if (ox >= 0 && ox < oldCache->len && mSpecCache->where[x] == oldCache->where[ox]) { for (sampleCount i = 0; i < (sampleCount)half; i++) mSpecCache->freq[half * x + i] = oldCache->freq[half * ox + i]; recalc[x] = false; } } } #ifdef EXPERIMENTAL_FFT_SKIP_POINTS float *buffer = new float[windowSize*fftSkipPoints1]; mSpecCache->fftSkipPointsOld = fftSkipPoints; #else //!EXPERIMENTAL_FFT_SKIP_POINTS float *buffer = new float[windowSize]; #endif //EXPERIMENTAL_FFT_SKIP_POINTS mSpecCache->minFreqOld = minFreq; mSpecCache->maxFreqOld = maxFreq; mSpecCache->gainOld = gain; mSpecCache->rangeOld = range; mSpecCache->windowTypeOld = windowType; mSpecCache->windowSizeOld = windowSize; mSpecCache->frequencyGainOld = frequencygain; float *gainfactor = NULL; if(frequencygain > 0) { // Compute a frequency-dependant gain factor // scaled such that 1000 Hz gets a gain of 0dB double factor = 0.001*(double)mRate/(double)windowSize; gainfactor = new float[half]; for(x = 0; x < half; x++) { gainfactor[x] = frequencygain*log10(factor * x); } } for (x = 0; x < mSpecCache->len; x++) if (recalc[x]) { sampleCount start = mSpecCache->where[x]; sampleCount len = windowSize; sampleCount i; if (start <= 0 || start >= mSequence->GetNumSamples()) { for (i = 0; i < (sampleCount)half; i++) mSpecCache->freq[half * x + i] = 0; } else { float *adj = buffer; start -= windowSize >> 1; if (start < 0) { for (i = start; i < 0; i++) *adj++ = 0; len += start; start = 0; } #ifdef EXPERIMENTAL_FFT_SKIP_POINTS if (start + len*fftSkipPoints1 > mSequence->GetNumSamples()) { int newlen = (mSequence->GetNumSamples() - start)/fftSkipPoints1; for (i = newlen*fftSkipPoints1; i < (sampleCount)len*fftSkipPoints1; i++) #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; } 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 #ifdef EXPERIMENTAL_USE_REALFFTF if(autocorrelation) { ComputeSpectrum(buffer, windowSize, windowSize, mRate, &mSpecCache->freq[half * x], autocorrelation, windowType); } else { ComputeSpectrumUsingRealFFTf(buffer, hFFT, mWindow, mWindowSize, &mSpecCache->freq[half * x]); } #else // EXPERIMENTAL_USE_REALFFTF ComputeSpectrum(buffer, windowSize, windowSize, mRate, &mSpecCache->freq[half * x], autocorrelation, windowType); #endif // EXPERIMENTAL_USE_REALFFTF if(gainfactor) { // Apply a frequency-dependant gain factor for(i=0; i<half; i++) mSpecCache->freq[half * x + i] += gainfactor[i]; } } } if(gainfactor) delete[] gainfactor; delete[]buffer; delete[]recalc; delete oldCache; mSpecCache->dirty = mDirty; memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float)); memcpy(where, mSpecCache->where, (numPixels+1)*sizeof(sampleCount)); return true; } bool WaveClip::GetMinMax(float *min, float *max, double t0, double t1) { *min = float(0.0); *max = float(0.0); if (t0 > t1) return false; if (t0 == t1) return true; sampleCount s0, s1; TimeToSamplesClip(t0, &s0); TimeToSamplesClip(t1, &s1); return mSequence->GetMinMax(s0, s1-s0, min, max); }