void fft::inversePowerSpectrum(int start, int half, int windowSize, float *finalOut,float *magnitude,float *phase) { int i; int windowFunc = 3; /* processing variables*/ float *in_real = new float[windowSize]; float *in_img = new float[windowSize]; float *out_real = new float[windowSize]; float *out_img = new float[windowSize]; /* get real and imag part */ for (i = 0; i < half; i++) { in_real[i] = magnitude[i]*cos(phase[i]); in_img[i] = magnitude[i]*sin(phase[i]); } /* zero negative frequencies */ for (i = half; i < windowSize; i++) { in_real[i] = 0.0; in_img[i] = 0.0; } FFT(windowSize, 1, in_real, in_img, out_real, out_img); // second parameter indicates inverse transform WindowFunc(windowFunc, windowSize, out_real); for (i = 0; i < windowSize; i++) { finalOut[start + i] += out_real[i]; } delete[]in_real; delete[]in_img; delete[]out_real; delete[]out_img; }
void EffectNoiseRemoval::GetProfile(sampleCount len, sampleType *buffer) { float *in = new float[len]; float *out = new float[len]; int i; for(i=0; i<len; i++) in[i] = buffer[i]/32767.; // Apply window and FFT WindowFunc(3, len, in); // Hanning window PowerSpectrum(len, in, out); for(i=0; i<=len/2; i++) { float value = log(out[i]); if (finite(value)) { sum[i] += value; sumsq[i] += value*value; profileCount[i]++; } } delete[] in; delete[] out; }
/* Calculate the power spectrum */ void fft::powerSpectrum(int start, int half, float *data, int windowSize,float *magnitude,float *phase, float *power, float *avg_power) { int i; int windowFunc = 3; float total_power = 0.0f; /* processing variables*/ float *in_real = new float[windowSize]; float *in_img = new float[windowSize]; float *out_real = new float[windowSize]; float *out_img = new float[windowSize]; for (i = 0; i < windowSize; i++) { in_real[i] = data[start + i]; } WindowFunc(windowFunc, windowSize, in_real); RealFFT(windowSize, in_real, out_real, out_img); for (i = 0; i < half; i++) { /* compute power */ power[i] = out_real[i]*out_real[i] + out_img[i]*out_img[i]; total_power += power[i]; /* compute magnitude and phase */ magnitude[i] = 2.0*sqrt(power[i]); phase[i] = atan2(out_img[i],out_real[i]); } /* calculate average power */ *(avg_power) = total_power / (float) half; delete[]in_real; delete[]in_img; delete[]out_real; delete[]out_img; }
void EffectWaveletDenoise::RemoveNoise(sampleCount len, float *buffer, bool first) { PQMF H(d20soqf, 0, 19); // Daubechies filters PQMF G(d20doqf, 0, 19); // Multiply by Hanning window float *window = new float[len]; for (int i=0; i<len; i++) { window[i] = buffer[i]; } WindowFunc(3, len, window); // Construct wave++ interval from buffer Interval signal(0,len-1); for (int i=0; i<len; i++) { signal[i] = window[i]; } delete[] window; // Wavelet transform Interval coeff(0, len-1); WaveTrans(signal, coeff, H, G, ConvDecPer); // Thresholding Interval delta(0, len-1); // initialized to 0 for(int i=0; i<len; i++) { // Hard thresholding // if (abs(coeff[i]) > threshold) // delta[i] = 1; // Ramaraphu/Maher soft thresholding // delta[i] = exp( (abs(coeff[i])/threshold - 1)/0.2 ); // Soft thresholding if (coeff[i]*coeff[i] > threshold) delta[i] = 1.0 - threshold/(coeff[i]*coeff[i]); } for(int i=0; i<len; i++) coeff[i] *= delta[i]; // Inverse transform Interval output(0, len-1); InvWaveTrans(coeff, output, H, G, AdjConvDecPer); // Write interval data back to buffer for (int i=0; i<len; i++) buffer[i] = output[i]; }
void EffectFilter::Filter(sampleCount len, sampleType *buffer) { float *inr = new float[len]; float *ini = new float[len]; float *outr = new float[len]; float *outi = new float[len]; unsigned int i; for(i=0; i<len; i++) inr[i] = buffer[i]/32767.; // Apply window and FFT WindowFunc(3, len, inr); // Hanning window FFT(len, false, inr, NULL, outr, outi); // Apply filter unsigned int half = len/2; for(i=0; i<=half; i++) { int j = len - i; outr[i] = outr[i]*filterFunc[i]; outi[i] = outi[i]*filterFunc[i]; if (i!=0 && i!=len/2) { outr[j] = outr[j]*filterFunc[i]; outi[j] = outi[j]*filterFunc[i]; } } // Inverse FFT and normalization FFT(len, true, outr, outi, inr, ini); for(i=0; i<len; i++) buffer[i] = sampleType(inr[i]*32767); delete[] inr; delete[] ini; delete[] outr; delete[] outi; }
/* Calculate the power spectrum */ void fft::powerSpectrum (float *data, int windowSize, float *magnitude) { int windowFunc = 3; float total_power = 0.0f; /* processing variables*/ float *out_real = new float[windowSize]; float *out_img = new float[windowSize]; WindowFunc(windowFunc, windowSize, data); RealFFT(windowSize, data, out_real, out_img); for (int i=0; i<windowSize/2; i++) { /* compute magnitude and phase */ magnitude[i] = 1000.0*sqrt(out_real[i]*out_real[i] + out_img[i]*out_img[i])/windowSize; //phase[i] = atan2(out_img[i],out_real[i]); } delete[]out_real; delete[]out_img; }
bool SpectrumAnalyst::Calculate(Algorithm alg, int windowFunc, size_t windowSize, double rate, const float *data, size_t dataLen, float *pYMin, float *pYMax, FreqGauge *progress) { // Wipe old data mProcessed.resize(0); mRate = 0.0; mWindowSize = 0; // Validate inputs int f = NumWindowFuncs(); if (!(windowSize >= 32 && windowSize <= 65536 && alg >= SpectrumAnalyst::Spectrum && alg < SpectrumAnalyst::NumAlgorithms && windowFunc >= 0 && windowFunc < f)) { return false; } if (dataLen < windowSize) { return false; } // Now repopulate mRate = rate; mWindowSize = windowSize; mAlg = alg; auto half = mWindowSize / 2; mProcessed.resize(mWindowSize); Floats in{ mWindowSize }; Floats out{ mWindowSize }; Floats out2{ mWindowSize }; Floats win{ mWindowSize }; for (size_t i = 0; i < mWindowSize; i++) { mProcessed[i] = 0.0f; win[i] = 1.0f; } WindowFunc(windowFunc, mWindowSize, win.get()); // Scale window such that an amplitude of 1.0 in the time domain // shows an amplitude of 0dB in the frequency domain double wss = 0; for (size_t i = 0; i<mWindowSize; i++) wss += win[i]; if(wss > 0) wss = 4.0 / (wss*wss); else wss = 1.0; if (progress) { progress->SetRange(dataLen); } size_t start = 0; int windows = 0; while (start + mWindowSize <= dataLen) { for (size_t i = 0; i < mWindowSize; i++) in[i] = win[i] * data[start + i]; switch (alg) { case Spectrum: PowerSpectrum(mWindowSize, in.get(), out.get()); for (size_t i = 0; i < half; i++) mProcessed[i] += out[i]; break; case Autocorrelation: case CubeRootAutocorrelation: case EnhancedAutocorrelation: // Take FFT RealFFT(mWindowSize, in.get(), out.get(), out2.get()); // Compute power for (size_t i = 0; i < mWindowSize; i++) in[i] = (out[i] * out[i]) + (out2[i] * out2[i]); if (alg == Autocorrelation) { for (size_t i = 0; i < mWindowSize; i++) in[i] = sqrt(in[i]); } if (alg == CubeRootAutocorrelation || alg == EnhancedAutocorrelation) { // Tolonen and Karjalainen recommend taking the cube root // of the power, instead of the square root for (size_t i = 0; i < mWindowSize; i++) in[i] = pow(in[i], 1.0f / 3.0f); } // Take FFT RealFFT(mWindowSize, in.get(), out.get(), out2.get()); // Take real part of result for (size_t i = 0; i < half; i++) mProcessed[i] += out[i]; break; case Cepstrum: RealFFT(mWindowSize, in.get(), out.get(), out2.get()); // Compute log power // Set a sane lower limit assuming maximum time amplitude of 1.0 { float power; float minpower = 1e-20*mWindowSize*mWindowSize; for (size_t i = 0; i < mWindowSize; i++) { power = (out[i] * out[i]) + (out2[i] * out2[i]); if(power < minpower) in[i] = log(minpower); else in[i] = log(power); } // Take IFFT InverseRealFFT(mWindowSize, in.get(), NULL, out.get()); // Take real part of result for (size_t i = 0; i < half; i++) mProcessed[i] += out[i]; } break; default: wxASSERT(false); break; } //switch // Update the progress bar if (progress) { progress->SetValue(start); } start += half; windows++; } if (progress) { // Reset for next time progress->Reset(); } float mYMin = 1000000, mYMax = -1000000; double scale; switch (alg) { case Spectrum: // Convert to decibels mYMin = 1000000.; mYMax = -1000000.; scale = wss / (double)windows; for (size_t i = 0; i < half; i++) { mProcessed[i] = 10 * log10(mProcessed[i] * scale); if(mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if(mProcessed[i] < mYMin) mYMin = mProcessed[i]; } break; case Autocorrelation: case CubeRootAutocorrelation: for (size_t i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (size_t i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; break; case EnhancedAutocorrelation: for (size_t i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Peak Pruning as described by Tolonen and Karjalainen, 2000 // Clip at zero, copy to temp array for (size_t i = 0; i < half; i++) { if (mProcessed[i] < 0.0) mProcessed[i] = float(0.0); out[i] = mProcessed[i]; } // Subtract a time-doubled signal (linearly interp.) from the original // (clipped) signal for (size_t i = 0; i < half; i++) if ((i % 2) == 0) mProcessed[i] -= out[i / 2]; else mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2); // Clip at zero again for (size_t i = 0; i < half; i++) if (mProcessed[i] < 0.0) mProcessed[i] = float(0.0); // Find NEW min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (size_t i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; break; case Cepstrum: for (size_t i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max, ignoring first and last few values { size_t ignore = 4; mYMin = mProcessed[ignore]; mYMax = mProcessed[ignore]; for (size_t i = ignore + 1; i + ignore < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; } break; default: wxASSERT(false); break; } if (pYMin) *pYMin = mYMin; if (pYMax) *pYMax = mYMax; return true; }
void PaulStretch::process(float *smps, size_t nsmps) { //add NEW samples to the pool if ((smps != NULL) && (nsmps != 0)) { if (nsmps > poolsize) { nsmps = poolsize; } int nleft = poolsize - nsmps; //move left the samples from the pool to make room for NEW samples for (int i = 0; i < nleft; i++) in_pool[i] = in_pool[i + nsmps]; //add NEW samples to the pool for (size_t i = 0; i < nsmps; i++) in_pool[i + nleft] = smps[i]; } //get the samples from the pool for (size_t i = 0; i < poolsize; i++) fft_smps[i] = in_pool[i]; WindowFunc(eWinFuncHanning, poolsize, fft_smps.get()); RealFFT(poolsize, fft_smps.get(), fft_c.get(), fft_s.get()); for (size_t i = 0; i < poolsize / 2; i++) fft_freq[i] = sqrt(fft_c[i] * fft_c[i] + fft_s[i] * fft_s[i]); process_spectrum(fft_freq.get()); //put randomize phases to frequencies and do a IFFT float inv_2p15_2pi = 1.0 / 16384.0 * (float)M_PI; for (size_t i = 1; i < poolsize / 2; i++) { unsigned int random = (rand()) & 0x7fff; float phase = random * inv_2p15_2pi; float s = fft_freq[i] * sin(phase); float c = fft_freq[i] * cos(phase); fft_c[i] = fft_c[poolsize - i] = c; fft_s[i] = s; fft_s[poolsize - i] = -s; } fft_c[0] = fft_s[0] = 0.0; fft_c[poolsize / 2] = fft_s[poolsize / 2] = 0.0; FFT(poolsize, true, fft_c.get(), fft_s.get(), fft_smps.get(), fft_tmp.get()); float max = 0.0, max2 = 0.0; for (size_t i = 0; i < poolsize; i++) { max = std::max(max, fabsf(fft_tmp[i])); max2 = std::max(max2, fabsf(fft_smps[i])); } //make the output buffer float tmp = 1.0 / (float) out_bufsize * M_PI; float hinv_sqrt2 = 0.853553390593f;//(1.0+1.0/sqrt(2))*0.5; float ampfactor = 1.0; if (rap < 1.0) ampfactor = rap * 0.707; else ampfactor = (out_bufsize / (float)poolsize) * 4.0; for (size_t i = 0; i < out_bufsize; i++) { float a = (0.5 + 0.5 * cos(i * tmp)); float out = fft_smps[i + out_bufsize] * (1.0 - a) + old_out_smp_buf[i] * a; out_buf[i] = out * (hinv_sqrt2 - (1.0 - hinv_sqrt2) * cos(i * 2.0 * tmp)) * ampfactor; } //copy the current output buffer to old buffer for (size_t i = 0; i < out_bufsize * 2; i++) old_out_smp_buf[i] = fft_smps[i]; }
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); }
/* Mangle a single window. Each output sample (except the first and last * half-window) is the result of two distinct calls to this function, * due to overlapping windows. */ static void reduce_noise(chandata_t* chan, float* window, float level) { float *inr = (float*)calloc(WINDOWSIZE, sizeof(float)); float *ini = (float*)calloc(WINDOWSIZE, sizeof(float)); float *outr = (float*)calloc(WINDOWSIZE, sizeof(float)); float *outi = (float*)calloc(WINDOWSIZE, sizeof(float)); float *power = (float*)calloc(WINDOWSIZE, sizeof(float)); float *smoothing = chan->smoothing; static int callnum = 0; int i; callnum ++; for (i = 0; i < FREQCOUNT; i ++) { assert(smoothing[i] >= 0 && smoothing[i] <= 1); } memcpy(inr, window, WINDOWSIZE*sizeof(float)); FFT(WINDOWSIZE, 0, inr, NULL, outr, outi); memcpy(inr, window, WINDOWSIZE*sizeof(float)); WindowFunc(HANNING, WINDOWSIZE, inr); PowerSpectrum(WINDOWSIZE, inr, power); for(i = 0; i < FREQCOUNT; i ++) { float smooth; float plog; plog = log(power[i]); if (power[i] != 0 && plog < chan->noisegate[i] + level*8.0) smooth = 0.0; else smooth = 1.0; smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5; } /* Audacity says this code will eliminate tinkle bells. * I have no idea what that means. */ for (i = 2; i < FREQCOUNT - 2; i ++) { if (smoothing[i]>=0.5 && smoothing[i]<=0.55 && smoothing[i-1]<0.1 && smoothing[i-2]<0.1 && smoothing[i+1]<0.1 && smoothing[i+2]<0.1) smoothing[i] = 0.0; } outr[0] *= smoothing[0]; outi[0] *= smoothing[0]; outr[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; outi[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; for (i = 1; i < FREQCOUNT-1; i ++) { int j = WINDOWSIZE - i; float smooth = smoothing[i]; outr[i] *= smooth; outi[i] *= smooth; outr[j] *= smooth; outi[j] *= smooth; } FFT(WINDOWSIZE, 1, outr, outi, inr, ini); WindowFunc(HANNING, WINDOWSIZE, inr); memcpy(window, inr, WINDOWSIZE*sizeof(float)); free(inr); free(ini); free(outr); free(outi); free(power); for (i = 0; i < FREQCOUNT; i ++) { assert(smoothing[i] >= 0 && smoothing[i] <= 1); } }
void EffectNoiseRemoval::RemoveNoise(sampleCount len, sampleType *buffer) { float *inr = new float[len]; float *ini = new float[len]; float *outr = new float[len]; float *outi = new float[len]; float *power = new float[len]; float *plog = new float[len]; int i; for(i=0; i<len; i++) inr[i] = buffer[i]/32767.; // Apply window and FFT WindowFunc(3, len, inr); // Hanning window FFT(len, false, inr, NULL, outr, outi); for(i=0; i<len; i++) inr[i] = buffer[i]/32767.; WindowFunc(3, len, inr); // Hanning window PowerSpectrum(len, inr, power); for(i=0; i<=len/2; i++) plog[i] = log(power[i]); int half = len/2; for(i=0; i<=half; i++) { float smooth; if (plog[i] < noiseGate[i] + (level/2.0)) smooth = 0.0; else smooth = 1.0; smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5; } /* try to eliminate tinkle bells */ for(i=2; i<=half-2; i++) { if (smoothing[i]>=0.5 && smoothing[i]<=0.55 && smoothing[i-1]<0.1 && smoothing[i-2]<0.1 && smoothing[i+1]<0.1 && smoothing[i+2]<0.1) smoothing[i] = 0.0; } outr[0] *= smoothing[0]; outi[0] *= smoothing[0]; outr[half] *= smoothing[half]; outi[half] *= smoothing[half]; for(i=1; i<half; i++) { int j = len - i; float smooth = smoothing[i]; outr[i] *= smooth; outi[i] *= smooth; outr[j] *= smooth; outi[j] *= smooth; } // Inverse FFT and normalization FFT(len, true, outr, outi, inr, ini); for(i=0; i<len; i++) buffer[i] = sampleType(inr[i]*32767); delete[] inr; delete[] ini; delete[] outr; delete[] outi; delete[] power; delete[] plog; }
void EffectNoiseRemoval::RemoveNoise() { int center = mHistoryLen / 2; int start = center - mMinSignalBlocks/2; int finish = start + mMinSignalBlocks; int i, j; // Raise the gain for elements in the center of the sliding history for (j = 0; j < mSpectrumSize; j++) { float min = mSpectrums[start][j]; for (i = start+1; i < finish; i++) { if (mSpectrums[i][j] < min) min = mSpectrums[i][j]; } if (min > mNoiseThreshold[j] && mGains[center][j] < 0.0) mGains[center][j] = 0.0; } // Decay the gain in both directions; // note that mOneBlockAttackDecay is a negative number, like -1.0 // dB of attenuation per block for (j = 0; j < mSpectrumSize; j++) { for (i = center + 1; i < mHistoryLen; i++) { if (mGains[i][j] < mGains[i - 1][j] + mOneBlockAttackDecay) mGains[i][j] = mGains[i - 1][j] + mOneBlockAttackDecay; if (mGains[i][j] < mNoiseGain) mGains[i][j] = mNoiseGain; } for (i = center - 1; i >= 0; i--) { if (mGains[i][j] < mGains[i + 1][j] + mOneBlockAttackDecay) mGains[i][j] = mGains[i + 1][j] + mOneBlockAttackDecay; if (mGains[i][j] < mNoiseGain) mGains[i][j] = mNoiseGain; } } // Apply frequency smoothing to output gain int out = mHistoryLen - 1; // end of the queue ApplyFreqSmoothing(mGains[out]); // Apply gain to FFT for (j = 0; j < mSpectrumSize; j++) { float mult = pow(10.0, mGains[out][j] / 20.0); mRealFFTs[out][j] *= mult; mImagFFTs[out][j] *= mult; if (j > 0 && j < mSpectrumSize - 1) { mRealFFTs[out][mWindowSize - j] *= mult; mImagFFTs[out][mWindowSize - j] *= mult; } } // Invert the FFT into the output buffer FFT(mWindowSize, true, mRealFFTs[out], mImagFFTs[out], mOutWaveBuffer, mOutImagBuffer); // Hanning window WindowFunc(3, mWindowSize, mOutWaveBuffer); // Overlap-add for(j = 0; j < mWindowSize; j++) mOutOverlapBuffer[j] += mOutWaveBuffer[j]; // Output the first half of the overlap buffer, they're done - // and then shift the next half over. if (mOutSampleCount >= 0) { // ...but not if it's the first half-window mOutputTrack->Append((samplePtr)mOutOverlapBuffer, floatSample, mWindowSize / 2); } mOutSampleCount += mWindowSize / 2; for(j = 0; j < mWindowSize / 2; j++) { mOutOverlapBuffer[j] = mOutOverlapBuffer[j + (mWindowSize / 2)]; mOutOverlapBuffer[j + (mWindowSize / 2)] = 0.0; } }
bool ComputeSpectrum(float * data, int width, int height, int maxFreq, int windowSize, double rate, float *grayscaleOut, bool autocorrelation) { int windowFunc = 3; if (width < windowSize) return false; if (!data || !grayscaleOut) return true; float *processed = new float[windowSize]; int i; for (i = 0; i < windowSize; i++) processed[i] = float(0.0); int half = windowSize / 2; float *in = new float[windowSize]; float *out = new float[windowSize]; float *out2 = new float[windowSize]; int start = 0; int windows = 0; while (start + windowSize <= width) { for (i = 0; i < windowSize; i++) in[i] = data[start + i]; WindowFunc(windowFunc, windowSize, in); if (autocorrelation) { // Take FFT FFT(windowSize, false, in, NULL, out, out2); // Compute power for (i = 0; i < windowSize; i++) in[i] = (out[i] * out[i]) + (out2[i] * out2[i]); // Tolonen and Karjalainen recommend taking the cube root // of the power, instead of the square root for (i = 0; i < windowSize; i++) in[i] = pow(in[i], 1.0f / 3.0f); // Take FFT FFT(windowSize, false, in, NULL, out, out2); // Take real part of result for (i = 0; i < half; i++) processed[i] += out[i]; } else { PowerSpectrum(windowSize, in, out); for (i = 0; i < half; i++) processed[i] += out[i]; } start += half; windows++; } int maxSamples = int (maxFreq * windowSize / rate + 0.5); if (maxSamples > half) maxSamples = half; if (autocorrelation) { maxSamples = half; // Peak Pruning as described by Tolonen and Karjalainen, 2000 // Clip at zero, copy to temp array for (i = 0; i < maxSamples; i++) { if (processed[i] < 0.0) processed[i] = float(0.0); out[i] = processed[i]; } // Subtract a time-doubled signal (linearly interp.) from the original // (clipped) signal for (i = 0; i < maxSamples; i++) if ((i % 2) == 0) processed[i] -= out[i / 2]; else processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2); // Clip at zero again for (i = 0; i < maxSamples; i++) if (processed[i] < 0.0) processed[i] = float(0.0); // Find new max float max = 0; for (i = 1; i < maxSamples; i++) if (processed[i] > max) max = processed[i]; // Reverse and scale for (i = 0; i < maxSamples; i++) in[i] = processed[i] / (windowSize / 4); for (i = 0; i < maxSamples; i++) processed[maxSamples - 1 - i] = in[i]; } else { // Convert to decibels for (i = 0; i < maxSamples; i++) processed[i] = 10 * log10(processed[i] / windowSize / windows); } // Finally, put it into bins in grayscaleOut[], normalized to a 0.0-1.0 scale for (i = 0; i < height; i++) { float bin0 = float (i) * maxSamples / height; float bin1 = float (i + 1) * maxSamples / height; float binwidth = bin1 - bin0; float value = float(0.0); if (int (bin1) == int (bin0)) value = processed[int (bin0)]; else { value += processed[int (bin0)] * (int (bin0) + 1 - bin0); bin0 = 1 + int (bin0); while (bin0 < int (bin1)) { value += processed[int (bin0)]; bin0 += 1.0; } value += processed[int (bin1)] * (bin1 - int (bin1)); value /= binwidth; } if (!autocorrelation) { // Last step converts dB to a 0.0-1.0 range value = (value + 80.0) / 80.0; } if (value > 1.0) value = float(1.0); if (value < 0.0) value = float(0.0); grayscaleOut[i] = value; } delete[]in; delete[]out; delete[]out2; delete[]processed; return true; }
void FreqWindow::Recalc() { if (mProcessed) delete mProcessed; mProcessed = NULL; if (!mData) { mFreqPlot->Refresh(false); return; } int alg = mAlgChoice->GetSelection(); int windowFunc = mFuncChoice->GetSelection(); long windowSize = 0; (mSizeChoice->GetStringSelection()).ToLong(&windowSize); if (!(windowSize >= 32 && windowSize <= 65536 && alg >= 0 && alg <= 3 && windowFunc >= 0 && windowFunc <= 3)) { mFreqPlot->Refresh(false); return; } mWindowSize = windowSize; if (mDataLen < mWindowSize) { mFreqPlot->Refresh(false); return; } mProcessed = new float[mWindowSize]; int i; for (i = 0; i < mWindowSize; i++) mProcessed[i] = 0.0; int half = mWindowSize / 2; float *in = new float[mWindowSize]; float *in2 = new float[mWindowSize]; float *out = new float[mWindowSize]; float *out2 = new float[mWindowSize]; int start = 0; int windows = 0; while (start + mWindowSize <= mDataLen) { for (i = 0; i < mWindowSize; i++) in[i] = mData[start + i]; WindowFunc(windowFunc, mWindowSize, in); switch (alg) { case 0: // Spectrum PowerSpectrum(mWindowSize, in, out); for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; case 1: case 2: case 3: // Autocorrelation, Cuberoot AC or Enhanced AC // Take FFT FFT(mWindowSize, false, in, NULL, out, out2); // Compute power for (i = 0; i < mWindowSize; i++) in[i] = (out[i] * out[i]) + (out2[i] * out2[i]); if (alg == 1) { for (i = 0; i < mWindowSize; i++) in[i] = sqrt(in[i]); } if (alg == 2 || alg == 3) { // Tolonen and Karjalainen recommend taking the cube root // of the power, instead of the square root for (i = 0; i < mWindowSize; i++) in[i] = pow(in[i], 1.0 / 3.0); } // Take FFT FFT(mWindowSize, false, in, NULL, out, out2); // Take real part of result for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; case 4: // Cepstrum FFT(mWindowSize, false, in, NULL, out, out2); // Compute log power for (i = 0; i < mWindowSize; i++) in[i] = log((out[i] * out[i]) + (out2[i] * out2[i])); // Take IFFT FFT(mWindowSize, true, in, NULL, out, out2); // Take real part of result for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; } //switch start += half; windows++; } switch (alg) { case 0: // Spectrum // Convert to decibels for (i = 0; i < half; i++) mProcessed[i] = 10 * log10(mProcessed[i] / mWindowSize / windows); mProcessedSize = half; mYMin = -90; mYMax = 10; mYStep = 10; break; case 1: // Standard Autocorrelation case 2: // Cuberoot Autocorrelation for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; case 3: // Enhanced Autocorrelation for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Peak Pruning as described by Tolonen and Karjalainen, 2000 // Clip at zero, copy to temp array for (i = 0; i < half; i++) { if (mProcessed[i] < 0.0) mProcessed[i] = 0.0; out[i] = mProcessed[i]; } // Subtract a time-doubled signal (linearly interp.) from the original // (clipped) signal for (i = 0; i < half; i++) if ((i % 2) == 0) mProcessed[i] -= out[i / 2]; else mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2); // Clip at zero again for (i = 0; i < half; i++) if (mProcessed[i] < 0.0) mProcessed[i] = 0.0; // Find new min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; case 4: // Cepstrum for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max, ignoring first and last few values int ignore = 4; mYMin = mProcessed[ignore]; mYMax = mProcessed[ignore]; for (i = ignore + 1; i < half - ignore; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; } delete[]in; delete[]in2; delete[]out; delete[]out2; mFreqPlot->Refresh(false); }
void FreqWindow::Recalc() { wxLogMessage(wxT("Starting FreqWindow::Recalc()")); if (mProcessed) delete[] mProcessed; mProcessed = NULL; if (!mData) { mFreqPlot->Refresh(true); return; } int alg = mAlgChoice->GetSelection(); int windowFunc = mFuncChoice->GetSelection(); long windowSize = 0; (mSizeChoice->GetStringSelection()).ToLong(&windowSize); int f = NumWindowFuncs(); if (!(windowSize >= 32 && windowSize <= 65536 && alg >= 0 && alg <= 4 && windowFunc >= 0 && windowFunc < f)) { mFreqPlot->Refresh(true); return; } mWindowSize = windowSize; if (mDataLen < mWindowSize) { mFreqPlot->Refresh(true); return; } mProcessed = new float[mWindowSize]; int i; for (i = 0; i < mWindowSize; i++) mProcessed[i] = float(0.0); int half = mWindowSize / 2; float *in = new float[mWindowSize]; float *in2 = new float[mWindowSize]; float *out = new float[mWindowSize]; float *out2 = new float[mWindowSize]; float *win = new float[mWindowSize]; // initialize the window for(int i=0; i<mWindowSize; i++) win[i] = 1.0; WindowFunc(windowFunc, mWindowSize, win); // Scale window such that an amplitude of 1.0 in the time domain // shows an amplitude of 0dB in the frequency domain double wss = 0; for(int i=0; i<mWindowSize; i++) wss += win[i]; if(wss > 0) wss = 4.0 / (wss*wss); else wss = 1.0; //Progress dialog over FFT operation wxLogMessage(wxT("Starting progress dialogue in FreqWindow::Recalc()")); ProgressDialog *mProgress = new ProgressDialog(_("FreqWindow"),_("Drawing Spectrum")); int start = 0; int windows = 0; while (start + mWindowSize <= mDataLen) { for (i = 0; i < mWindowSize; i++) in[i] = win[i] * mData[start + i]; switch (alg) { case 0: // Spectrum PowerSpectrum(mWindowSize, in, out); for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; case 1: case 2: case 3: // Autocorrelation, Cuberoot AC or Enhanced AC // Take FFT #ifdef EXPERIMENTAL_USE_REALFFTF RealFFT(mWindowSize, in, out, out2); #else FFT(mWindowSize, false, in, NULL, out, out2); #endif // Compute power for (i = 0; i < mWindowSize; i++) in[i] = (out[i] * out[i]) + (out2[i] * out2[i]); if (alg == 1) { for (i = 0; i < mWindowSize; i++) in[i] = sqrt(in[i]); } if (alg == 2 || alg == 3) { // Tolonen and Karjalainen recommend taking the cube root // of the power, instead of the square root for (i = 0; i < mWindowSize; i++) in[i] = pow(in[i], 1.0f / 3.0f); } // Take FFT #ifdef EXPERIMENTAL_USE_REALFFTF RealFFT(mWindowSize, in, out, out2); #else FFT(mWindowSize, false, in, NULL, out, out2); #endif // Take real part of result for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; case 4: // Cepstrum #ifdef EXPERIMENTAL_USE_REALFFTF RealFFT(mWindowSize, in, out, out2); #else FFT(mWindowSize, false, in, NULL, out, out2); #endif // Compute log power // Set a sane lower limit assuming maximum time amplitude of 1.0 float power; float minpower = 1e-20*mWindowSize*mWindowSize; for (i = 0; i < mWindowSize; i++) { power = (out[i] * out[i]) + (out2[i] * out2[i]); if(power < minpower) in[i] = log(minpower); else in[i] = log(power); } // Take IFFT #ifdef EXPERIMENTAL_USE_REALFFTF InverseRealFFT(mWindowSize, in, NULL, out); #else FFT(mWindowSize, true, in, NULL, out, out2); #endif // Take real part of result for (i = 0; i < half; i++) mProcessed[i] += out[i]; break; } //switch start += half; windows++; // only update the progress dialogue infrequently to reduce it's overhead // If we do it every time, it spends as much time updating X11 as doing // the calculations. 10 seems a reasonable compromise on Linux that // doesn't make it unresponsive, but avoids the slowdown. if ((windows % 10) == 0) mProgress->Update(1 - static_cast<float>(mDataLen - start) / mDataLen); } wxLogMessage(wxT("Finished updating progress dialogue in FreqWindow::Recalc()")); switch (alg) { double scale; case 0: // Spectrum // Convert to decibels mYMin = 1000000.; mYMax = -1000000.; scale = wss / (double)windows; for (i = 0; i < half; i++) { mProcessed[i] = 10 * log10(mProcessed[i] * scale); if(mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if(mProcessed[i] < mYMin) mYMin = mProcessed[i]; } if(mYMin < -dBRange) mYMin = -dBRange; if(mYMax <= -dBRange) mYMax = -dBRange + 10.; // it's all out of range, but show a scale. else mYMax += .5; mProcessedSize = half; mYStep = 10; break; case 1: // Standard Autocorrelation case 2: // Cuberoot Autocorrelation for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; case 3: // Enhanced Autocorrelation for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Peak Pruning as described by Tolonen and Karjalainen, 2000 // Clip at zero, copy to temp array for (i = 0; i < half; i++) { if (mProcessed[i] < 0.0) mProcessed[i] = float(0.0); out[i] = mProcessed[i]; } // Subtract a time-doubled signal (linearly interp.) from the original // (clipped) signal for (i = 0; i < half; i++) if ((i % 2) == 0) mProcessed[i] -= out[i / 2]; else mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2); // Clip at zero again for (i = 0; i < half; i++) if (mProcessed[i] < 0.0) mProcessed[i] = float(0.0); // Find new min/max mYMin = mProcessed[0]; mYMax = mProcessed[0]; for (i = 1; i < half; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; case 4: // Cepstrum for (i = 0; i < half; i++) mProcessed[i] = mProcessed[i] / windows; // Find min/max, ignoring first and last few values int ignore = 4; mYMin = mProcessed[ignore]; mYMax = mProcessed[ignore]; for (i = ignore + 1; i < half - ignore; i++) if (mProcessed[i] > mYMax) mYMax = mProcessed[i]; else if (mProcessed[i] < mYMin) mYMin = mProcessed[i]; mYStep = 1; mProcessedSize = half; break; } delete[]in; delete[]in2; delete[]out; delete[]out2; delete[]win; wxLogMessage(wxT("About to draw plot in FreqWindow::Recalc()")); DrawPlot(); mFreqPlot->Refresh(true); delete mProgress; }
void EffectNoiseRemoval::RemoveNoise(sampleCount len, float *buffer) { float *inr = new float[len]; float *ini = new float[len]; float *outr = new float[len]; float *outi = new float[len]; float *power = new float[len]; float *plog = new float[len]; int i; for(i=0; i<len; i++) inr[i] = buffer[i]; // Apply window and FFT /* WindowFunc(3, len, inr); // Hanning window */ FFT(len, false, inr, NULL, outr, outi); for(i=0; i<len; i++) inr[i] = buffer[i]; WindowFunc(3, len, inr); // Hanning window PowerSpectrum(len, inr, power); for(i=0; i<=len/2; i++) plog[i] = log(power[i]); int half = len/2; for(i=0; i<=half; i++) { float smooth; //Factor of 4 here replaces previous 2, giving a //finer gradation of noise removal choice. if (plog[i] < mNoiseGate[i] + (mLevel / 4.0)) smooth = float(0.0); else smooth = float(1.0); smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5; } /* try to eliminate tinkle bells */ for(i=2; i<=half-2; i++) { if (smoothing[i]>=0.5 && smoothing[i]<=0.55 && smoothing[i-1]<0.1 && smoothing[i-2]<0.1 && smoothing[i+1]<0.1 && smoothing[i+2]<0.1) smoothing[i] = float(0.0); } outr[0] *= smoothing[0]; outi[0] *= smoothing[0]; outr[half] *= smoothing[half]; outi[half] *= smoothing[half]; for(i=1; i<half; i++) { int j = len - i; float smooth = smoothing[i]; outr[i] *= smooth; outi[i] *= smooth; outr[j] *= smooth; outi[j] *= smooth; } // Inverse FFT and normalization FFT(len, true, outr, outi, inr, ini); WindowFunc(3, len, inr); // Hanning window */ for(i=0; i<len; i++) buffer[i] = inr[i]; delete[] inr; delete[] ini; delete[] outr; delete[] outi; delete[] power; delete[] plog; }
bool ComputeSpectrum(const float * data, int width, int windowSize, double WXUNUSED(rate), float *output, bool autocorrelation, int windowFunc) { if (width < windowSize) return false; if (!data || !output) return true; float *processed = new float[windowSize]; int i; for (i = 0; i < windowSize; i++) processed[i] = float(0.0); int half = windowSize / 2; float *in = new float[windowSize]; float *out = new float[windowSize]; float *out2 = new float[windowSize]; int start = 0; int windows = 0; while (start + windowSize <= width) { for (i = 0; i < windowSize; i++) in[i] = data[start + i]; WindowFunc(windowFunc, windowSize, in); if (autocorrelation) { // Take FFT RealFFT(windowSize, in, out, out2); // Compute power for (i = 0; i < windowSize; i++) in[i] = (out[i] * out[i]) + (out2[i] * out2[i]); // Tolonen and Karjalainen recommend taking the cube root // of the power, instead of the square root for (i = 0; i < windowSize; i++) in[i] = powf(in[i], 1.0f / 3.0f); // Take FFT RealFFT(windowSize, in, out, out2); } else PowerSpectrum(windowSize, in, out); // Take real part of result for (i = 0; i < half; i++) processed[i] += out[i]; start += half; windows++; } if (autocorrelation) { // Peak Pruning as described by Tolonen and Karjalainen, 2000 /* Combine most of the calculations in a single for loop. It should be safe, as indexes refer only to current and previous elements, that have already been clipped, etc... */ for (i = 0; i < half; i++) { // Clip at zero, copy to temp array if (processed[i] < 0.0) processed[i] = float(0.0); out[i] = processed[i]; // Subtract a time-doubled signal (linearly interp.) from the original // (clipped) signal if ((i % 2) == 0) processed[i] -= out[i / 2]; else processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2); // Clip at zero again if (processed[i] < 0.0) processed[i] = float(0.0); } // Reverse and scale for (i = 0; i < half; i++) in[i] = processed[i] / (windowSize / 4); for (i = 0; i < half; i++) processed[half - 1 - i] = in[i]; } else { // Convert to decibels // But do it safely; -Inf is nobody's friend for (i = 0; i < half; i++){ float temp=(processed[i] / windowSize / windows); if (temp > 0.0) processed[i] = 10*log10(temp); else processed[i] = 0; } } for(i=0;i<half;i++) output[i] = processed[i]; delete[]in; delete[]out; delete[]out2; delete[]processed; return true; }