Example #1
0
        /// <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);
        }
Example #2
0
        /// <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;
        }
Example #3
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;
        }
Example #4
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));
        }
Example #5
0
 public void FFT(bool forward)
 {
     if (forward)
     {
         fft.Direct(data, re, im);
     }
     else
     {
         fft.Inverse(re, im, data);
     }
 }
Example #6
0
        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));
        }
Example #7
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 = 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));
        }
Example #8
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);

                // 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));
        }
Example #9
0
        /// <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;
        }
Example #10
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;
        }
Example #11
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);
        }
Example #12
0
        /// <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;
        }
Example #13
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;
        }
Example #15
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)
            {
                ;
            }
        }
Example #16
0
        /// <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));
        }