/// <summary> /// Fast convolution via FFT for arrays of samples (maximally in-place). /// This version is best suited for block processing when memory needs to be reused. /// Input arrays must have size equal to the size of FFT. /// FFT size MUST be set properly in constructor! /// </summary> /// <param name="input">Real parts of the 1st signal (zero-padded)</param> /// <param name="kernel">Real parts of the 2nd signal (zero-padded)</param> /// <param name="output">Real parts of resulting convolution (zero-padded)</param> public void Convolve(float[] input, float[] kernel, float[] output) { Array.Clear(_real1, 0, _fftSize); Array.Clear(_real2, 0, _fftSize); Array.Clear(_imag1, 0, _fftSize); Array.Clear(_imag2, 0, _fftSize); input.FastCopyTo(_real1, input.Length); kernel.FastCopyTo(_real2, kernel.Length); // 1) do FFT of both signals _fft.Direct(_real1, _real1, _imag1); _fft.Direct(_real2, _real2, _imag2); // 2) do complex multiplication of spectra and normalize for (var i = 0; i <= _fftSize / 2; i++) { var re = _real1[i] * _real2[i] - _imag1[i] * _imag2[i]; var im = _real1[i] * _imag2[i] + _imag1[i] * _real2[i]; _real1[i] = 2 * re / _fftSize; _imag1[i] = 2 * im / _fftSize; } // 3) do inverse FFT of resulting spectrum _fft.Inverse(_real1, _imag1, output); }
/// <summary> /// Process one frame (FFT block) /// </summary> public virtual void ProcessFrame() { // analysis ========================================================= _dl.FastCopyTo(_re, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); // processing ======================================================= ProcessSpectrum(_re, _im, _filteredRe, _filteredIm); // synthesis ======================================================== _fft.Inverse(_filteredRe, _filteredIm, _filteredRe); _filteredRe.ApplyWindow(_window); for (var j = 0; j < _overlapSize; j++) { _filteredRe[j] += _lastSaved[j]; } _filteredRe.FastCopyTo(_lastSaved, _overlapSize, _hopSize); for (var i = 0; i < _filteredRe.Length; i++) // Wet/Dry mix { _filteredRe[i] *= Wet * _gain; _filteredRe[i] += _dl[i] * Dry; } _dl.FastCopyTo(_dl, _overlapSize, _hopSize); _inOffset = _overlapSize; _outOffset = 0; }
/// <summary> /// Process one frame (block) /// </summary> public void ProcessFrame() { var M = _kernel.Length; var halfSize = _fftSize / 2; Array.Clear(_blockRe, HopSize, M - 1); _fft.Direct(_blockRe, _blockRe, _blockIm); for (var j = 0; j <= halfSize; j++) { _convRe[j] = (_blockRe[j] * _kernelSpectrumRe[j] - _blockIm[j] * _kernelSpectrumIm[j]) / _fftSize; _convIm[j] = (_blockRe[j] * _kernelSpectrumIm[j] + _blockIm[j] * _kernelSpectrumRe[j]) / _fftSize; } _fft.Inverse(_convRe, _convIm, _convRe); for (var j = 0; j < M - 1; j++) { _convRe[j] += _lastSaved[j]; } _convRe.FastCopyTo(_lastSaved, M - 1, HopSize); _outputBufferOffset = 0; _bufferOffset = 0; }
/// <summary> /// Phase Vocoder algorithm /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[(int)(input.Length * _stretch) + _fftSize]; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input.Length; posAnalysis += _hopAnalysis) { input.FastCopyTo(_re, _fftSize, posAnalysis); Array.Clear(_im, 0, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); for (var j = 1; j <= _fftSize / 2; j++) { var mag = Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); var phase = Math.Atan2(_im[j], _re[j]); var delta = phase - _prevPhase[j]; var deltaUnwrapped = delta - _hopAnalysis * _omega[j]; var deltaWrapped = MathUtils.Mod(deltaUnwrapped + Math.PI, 2 * Math.PI) - Math.PI; var freq = _omega[j] + deltaWrapped / _hopAnalysis; _phaseTotal[j] += _hopSynthesis * freq; _prevPhase[j] = phase; _re[j] = (float)(mag * Math.Cos(_phaseTotal[j])); _im[j] = (float)(mag * Math.Sin(_phaseTotal[j])); } _fft.Inverse(_re, _im, _re); for (var j = 0; j < _re.Length; j++) { output[posSynthesis + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSynthesis; j++) { output[posSynthesis + j] *= _gain; } posSynthesis += _hopSynthesis; } for (; posSynthesis < output.Length; posSynthesis++) { output[posSynthesis] *= _gain; } return(new DiscreteSignal(signal.SamplingRate, output)); }
public void FFT(bool forward) { if (forward) { fft.Direct(data, re, im); } else { fft.Inverse(re, im, data); } }
public void TestInverseRealFft() { float[] array = { 1, 5, 3, 7, 2, 3, 0, 7 }; float[] output = new float[array.Length]; float[] re = new float[5]; float[] im = new float[5]; var realFft = new RealFft(8); realFft.Direct(array, re, im); realFft.Inverse(re, im, output); Assert.That(output, Is.EqualTo(array.Select(a => a * 4)).Within(1e-5)); }
/// <summary> /// Phase Vocoder algorithm /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[(int)(input.Length * _stretch) + _fftSize]; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input.Length; posAnalysis += _hopAnalysis) { input.FastCopyTo(_re, _fftSize, posAnalysis); Array.Clear(_im, 0, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); for (var j = 1; j <= _fftSize / 2; j++) { var mag = Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); var phase = 2 * Math.PI * _rand.NextDouble(); _re[j] = (float)(mag * Math.Cos(phase)); _im[j] = (float)(mag * Math.Sin(phase)); } _fft.Inverse(_re, _im, _re); for (var j = 0; j < _re.Length; j++) { output[posSynthesis + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSynthesis; j++) { output[posSynthesis + j] *= _gain; } posSynthesis += _hopSynthesis; } for (; posSynthesis < output.Length; posSynthesis++) { output[posSynthesis] *= _gain; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Phase Vocoder algorithm /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[(int)(input.Length * _stretch) + _fftSize]; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input.Length; posAnalysis += _hopAnalysis) { input.FastCopyTo(_re, _fftSize, posAnalysis); // analysis ================================================== _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); // processing ================================================ ProcessSpectrum(); // synthesis ================================================= _fft.Inverse(_re, _im, _re); for (var j = 0; j < _re.Length; j++) { output[posSynthesis + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSynthesis; j++) { output[posSynthesis + j] *= _gain; } posSynthesis += _hopSynthesis; } for (; posSynthesis < output.Length; posSynthesis++) { output[posSynthesis] *= _gain; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Process one frame (block) /// </summary> public void ProcessFrame() { Array.Clear(_im1, 0, _fftSize); Array.Clear(_im2, 0, _fftSize); _dl1.FastCopyTo(_re1, _fftSize); _dl2.FastCopyTo(_re2, _fftSize); _re1.ApplyWindow(_window); _re2.ApplyWindow(_window); _fft.Direct(_re1, _re1, _im1); _fft.Direct(_re2, _re2, _im2); for (var j = 1; j <= _fftSize / 2; j++) { var mag1 = Math.Sqrt(_re1[j] * _re1[j] + _im1[j] * _im1[j]); var phase2 = Math.Atan2(_im2[j], _re2[j]); _filteredRe[j] = (float)(mag1 * Math.Cos(phase2)); _filteredIm[j] = (float)(mag1 * Math.Sin(phase2)); } _fft.Inverse(_filteredRe, _filteredIm, _filteredRe); _filteredRe.ApplyWindow(_window); for (var j = 0; j < _overlapSize; j++) { _filteredRe[j] += _lastSaved[j]; } _filteredRe.FastCopyTo(_lastSaved, _overlapSize, _hopSize); for (var i = 0; i < _filteredRe.Length; i++) // Wet / Dry mix { _filteredRe[i] *= Wet / _fftSize; _filteredRe[i] += _dl2[i] * Dry; } _dl1.FastCopyTo(_dl1, _overlapSize, _hopSize); _dl2.FastCopyTo(_dl2, _overlapSize, _hopSize); _inOffset = _overlapSize; _outOffset = 0; }
/// <summary> /// Process one frame (block) /// </summary> public void ProcessFrame() { float k = (AlphaMin - AlphaMax) / (SnrMax - SnrMin); float b = AlphaMax - k * SnrMin; Array.Clear(_im, 0, _fftSize); _dl.FastCopyTo(_re, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); for (var j = 1; j <= _fftSize / 2; j++) { var power = _re[j] * _re[j] + _im[j] * _im[j]; var phase = Math.Atan2(_im[j], _re[j]); var noisePower = _noiseEstimate[j]; var snr = 10 * Math.Log10(power / noisePower); var alpha = Math.Max(Math.Min(k * snr + b, AlphaMax), AlphaMin); var diff = power - alpha * noisePower; var mag = Math.Sqrt(Math.Max(diff, Beta * noisePower)); _filteredRe[j] = (float)(mag * Math.Cos(phase)); _filteredIm[j] = (float)(mag * Math.Sin(phase)); } _fft.Inverse(_filteredRe, _filteredIm, _filteredRe); _filteredRe.ApplyWindow(_window); for (var j = 0; j < _overlapSize; j++) { _filteredRe[j] += _lastSaved[j]; } _filteredRe.FastCopyTo(_lastSaved, _overlapSize, _hopSize); _dl.FastCopyTo(_dl, _overlapSize, _hopSize); _inOffset = _overlapSize; _outOffset = 0; }
public double[] Spectrum(double[] input, bool scale) { int length = input.Length; var data = Helper.ConvertToFloat(input); var re = new float[length]; var im = new float[length]; var fft = new RealFft(length); fft.Direct(data, re, im); var spectrum = Helper.ComputeSpectrum(length / 2, re, im); fft.Inverse(re, im, data); return(spectrum); }
/// <summary> /// Process one frame (block) /// </summary> public void ProcessFrame() { Array.Clear(_im, 0, _fftSize); _dl.FastCopyTo(_re, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); for (var j = 1; j <= _fftSize / 2; j++) { var mag = Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); var phase = 2 * Math.PI * _rand.NextDouble(); _filteredRe[j] = (float)(mag * Math.Cos(phase)); _filteredIm[j] = (float)(mag * Math.Sin(phase)); } _fft.Inverse(_filteredRe, _filteredIm, _filteredRe); _filteredRe.ApplyWindow(_window); for (var j = 0; j < _overlapSize; j++) { _filteredRe[j] += _lastSaved[j]; } _filteredRe.FastCopyTo(_lastSaved, _overlapSize, _hopSize); for (var i = 0; i < _filteredRe.Length; i++) // Wet / Dry mix { _filteredRe[i] *= Wet * _gain; _filteredRe[i] += _dl[i] * Dry; } _dl.FastCopyTo(_dl, _overlapSize, _hopSize); _inOffset = _overlapSize; _outOffset = 0; }
public void process(float[] x, int length) { int i; for (i = 0; i < length; i++) { real[i] = x[i]; imag[i] = 0; } for (; i < rfft.Size; i++) { real[i] = imag[i] = 0; } rfft.Direct(real, real, imag); stretcher.stretch(real, real); stretcher.stretch(imag, imag); rfft.Inverse(real, imag, real); for (i = 0; i < length; i++) { x[i] = real[i] / rfft.Size; } }
/// <summary> /// Process one frame (block) /// </summary> public void ProcessFrame() { Array.Clear(_im, 0, _fftSize); _dl.FastCopyTo(_re, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); var nextPhase = (float)(2 * Math.PI * _hopSize / _fftSize); for (var j = 1; j <= _fftSize / 2; j++) { _mag[j] = (float)Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); _phase[j] = (float)Math.Atan2(_im[j], _re[j]); var delta = _phase[j] - _prevPhase[j]; _prevPhase[j] = _phase[j]; delta -= j * nextPhase; var deltaWrapped = MathUtils.Mod(delta + Math.PI, 2 * Math.PI) - Math.PI; _phase[j] = _freqResolution * (j + (float)deltaWrapped / nextPhase); } Array.Clear(_re, 0, _fftSize); Array.Clear(_im, 0, _fftSize); // "stretch" spectrum: var stretchPos = 0; for (var j = 0; j <= _fftSize / 2 && stretchPos <= _fftSize / 2; j++) { _re[stretchPos] += _mag[j]; _im[stretchPos] = _phase[j] * _shift; stretchPos = (int)(j * _shift); } for (var j = 1; j <= _fftSize / 2; j++) { var mag = _re[j]; var freqIndex = (_im[j] - j * _freqResolution) / _freqResolution; _phaseTotal[j] += nextPhase * (freqIndex + j); _filteredRe[j] = (float)(mag * Math.Cos(_phaseTotal[j])); _filteredIm[j] = (float)(mag * Math.Sin(_phaseTotal[j])); } _fft.Inverse(_filteredRe, _filteredIm, _filteredRe); _filteredRe.ApplyWindow(_window); for (var j = 0; j < _overlapSize; j++) { _filteredRe[j] += _lastSaved[j]; } _filteredRe.FastCopyTo(_lastSaved, _overlapSize, _hopSize); for (var i = 0; i < _filteredRe.Length; i++) // Wet / Dry mix { _filteredRe[i] *= Wet * _gain; _filteredRe[i] += _dl[i] * Dry; } _dl.FastCopyTo(_dl, _overlapSize, _hopSize); _inOffset = _overlapSize; _outOffset = 0; }
protected void GenerateWavetable() { if (_fft == null || _amplitudes == null || _frequency == 0) { return; } Array.Clear(_re, 0, _re.Length); Array.Clear(_im, 0, _im.Length); var fftHalfSize = _fftSize / 2; // synthesize spectrum: for (var i = 1; i <= _amplitudes.Length; i++) { if (_amplitudes[i - 1] == 0) { continue; } var bwHz = (Math.Pow(2, _bw / 1200) - 1.0) * _frequency * Math.Pow(i, _bwScale); var fi = _frequency * i / SamplingRate; var bwi = bwHz / (2.0 * SamplingRate); var s = (int)(fi * fftHalfSize); if (s >= fftHalfSize) { continue; } var h = 1.0; var j = s; while (h > 1e-10) { h = Profile(1.0 * j / fftHalfSize - fi, bwi); _re[j--] += (float)h * _amplitudes[i - 1]; } h = 1.0; j = s + 1; while (h > 1e-10) { h = Profile(1.0 * j / fftHalfSize - fi, bwi); _re[j++] += (float)h * _amplitudes[i - 1]; } } // generate samples from synthesized spectrum: for (var i = 0; i < _re.Length; i++) { var mag = _re[i]; var phase = _rand.NextDouble() * 2 * Math.PI; _re[i] = (float)(mag * Math.Cos(phase)); _im[i] = (float)(mag * Math.Sin(phase)); } _fft.Inverse(_re, _im, _samples); var norm = 1 / _samples.Max(); for (var i = 0; i < _samples.Length; _samples[i++] *= norm) { ; } }
/// <summary> /// Phase locking procedure /// </summary> /// <param name="signal"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[(int)(input.Length * _stretch) + _fftSize]; var peakCount = 0; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input.Length; posAnalysis += _hopAnalysis) { input.FastCopyTo(_re, _fftSize, posAnalysis); Array.Clear(_im, 0, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _re, _im); for (var j = 0; j < _mag.Length; j++) { _mag[j] = Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); _phase[j] = Math.Atan2(_im[j], _re[j]); } // spectral peaks in magnitude spectrum peakCount = 0; for (var j = 2; j < _mag.Length - 3; j++) { if (_mag[j] <= _mag[j - 1] || _mag[j] <= _mag[j - 2] || _mag[j] <= _mag[j + 1] || _mag[j] <= _mag[j + 2]) { continue; // if not a peak } _peaks[peakCount++] = j; } _peaks[peakCount++] = _mag.Length - 1; // assign phases at peaks to all neighboring frequency bins var leftPos = 1; for (var j = 0; j < peakCount - 1; j++) { var peakPos = _peaks[j]; var peakPhase = _phase[peakPos]; _delta[peakPos] = peakPhase - _prevPhase[peakPos]; var deltaUnwrapped = _delta[peakPos] - _hopAnalysis * _omega[peakPos]; var deltaWrapped = MathUtils.Mod(deltaUnwrapped + Math.PI, 2 * Math.PI) - Math.PI; var freq = _omega[peakPos] + deltaWrapped / _hopAnalysis; _phaseTotal[peakPos] = _phaseTotal[peakPos] + _hopSynthesis * freq; var rightPos = (_peaks[j] + _peaks[j + 1]) / 2; for (var k = leftPos; k < rightPos; k++) { _phaseTotal[k] = _phaseTotal[peakPos] + _phase[k] - _phase[peakPos]; _prevPhase[k] = _phase[k]; _re[k] = (float)(_mag[k] * Math.Cos(_phaseTotal[k])); _im[k] = (float)(_mag[k] * Math.Sin(_phaseTotal[k])); } leftPos = rightPos; } _fft.Inverse(_re, _im, _re); for (var j = 0; j < _re.Length; j++) { output[posSynthesis + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSynthesis; j++) { output[posSynthesis + j] *= _gain; } posSynthesis += _hopSynthesis; } for (; posSynthesis < output.Length; posSynthesis++) { output[posSynthesis] *= _gain; } return(new DiscreteSignal(signal.SamplingRate, output)); }