/// <summary> /// Offline filtering /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (method != FilteringMethod.Auto) { return(base.ApplyTo(signal, method)); } var input = signal.Samples; var output = new float[input.Length + 1]; var b0 = _b[0]; var b1 = _b[1]; _prevSample = 0; int i = 0; for (; i < input.Length; i++) { var sample = input[i]; output[i] = b0 * sample + b1 * _prevSample; _prevSample = sample; } output[i] = b1 * _prevSample; return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Apply filter by fast recursive strategy /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (method != FilteringMethod.Auto) { return(base.ApplyTo(signal, method)); } var input = signal.Samples; var size = Size; var output = new float[input.Length]; var b0 = _b32[0]; var bs = _b32[Size]; output[0] = input[0] * b0; for (var n = 1; n < size; n++) { output[n] = input[n] * b0 + output[n - 1]; } for (var n = size; n < input.Length; n++) { output[n] = input[n - size] * bs + input[n] * b0 + output[n - 1]; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Algorithm is essentially: 1) TSM; 2) linear interpolation /// </summary> /// <param name="signal">Input signal</param> /// <param name="method">Filtering method</param> /// <returns>Pitch shifted signal</returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { // 1) just stretch var stretched = Operation.TimeStretch(signal, _shift, _fftSize, _hopSize, algorithm: _tsm); // 2) and interpolate var x = Enumerable.Range(0, stretched.Length) // [0.0, 1.0, 2.0, 3.0, ...] .Select(s => (float)s) .ToArray(); var xresampled = Enumerable.Range(0, signal.Length) .Select(s => (float)(_shift * s)) // [0.0, _shift, 2*_shift, ...] .ToArray(); var resampled = new float[xresampled.Length]; MathUtils.InterpolateLinear(x, stretched.Samples, xresampled, resampled); for (var i = 0; i < resampled.Length; i++) { resampled[i] = signal[i] * Dry + resampled[i] * Wet; } return(new DiscreteSignal(signal.SamplingRate, resampled)); }
/// <summary> /// Method implements median filtering 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[input.Length]; int i = 0, j = 0; for (i = 0; i < Size / 2; i++) // then feed first samples { Process(input[i]); } for (; j < input.Length - Size / 2; j++, i++) // and begin populating output signal { output[j] = Process(input[i]); } for (i = 0; i < Size / 2; i++, j++) // don't forget last samples { output[j] = Process(0); } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Apply filter /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (method != FilteringMethod.Auto) { return(base.ApplyTo(signal, method)); } var input = signal.Samples; var output = new float[input.Length]; var b0 = _b[0]; var am = _a[_delay]; for (var i = 0; i < _delay; i++) { output[i] = b0 * input[i]; } for (var i = _delay; i < signal.Length; i++) { output[i] = b0 * input[i] - am * output[i - _delay]; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Applies filter to entire <paramref name="signal"/> and returns new filtered signal. /// </summary> /// <param name="signal">Signal</param> /// <param name="method">Filtering method</param> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (method != FilteringMethod.Auto) { return(base.ApplyTo(signal, method)); } var input = signal.Samples; var output = new float[input.Length + _kernelSize - 1]; var b0 = _b[0]; var bm = _b[_delay]; int i = 0, j = 0; for (; i < _delay; i++) { output[i] = b0 * input[i]; } for (; i < signal.Length; i++, j++) { output[i] = b0 * input[i] + bm * input[j]; } for (; i < output.Length; i++, j++) { output[i] = bm * input[j]; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Apply filter by fast recursive strategy /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (method != FilteringMethod.Auto) { return(base.ApplyTo(signal, method)); } var input = signal.Samples; var size = Size; var output = new float[input.Length]; var b0 = _b[0]; var bs = _b[Size]; output[0] = input[0] * b0; for (int n = 1, k = 0; n < size; n++, k++) { output[n] = input[n] * b0 + output[k]; } for (int n = size, k = size - 1, delay = 0; n < input.Length; n++, k++, delay++) { output[n] = input[delay] * bs + input[n] * b0 + output[k]; } return(new DiscreteSignal(signal.SamplingRate, output)); }
/// <summary> /// Apply filter to entire signal /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { if (_kernel.Length >= FilterSizeForOptimizedProcessing && method == FilteringMethod.Auto) { method = FilteringMethod.OverlapAdd; } switch (method) { case FilteringMethod.OverlapAdd: { var fftSize = MathUtils.NextPowerOfTwo(4 * Kernel.Length); var blockConvolver = OlaBlockConvolver.FromFilter(this, fftSize); return(blockConvolver.ApplyTo(signal)); } case FilteringMethod.OverlapSave: { var fftSize = MathUtils.NextPowerOfTwo(4 * Kernel.Length); var blockConvolver = OlsBlockConvolver.FromFilter(this, fftSize); return(blockConvolver.ApplyTo(signal)); } case FilteringMethod.Custom: { return(this.ProcessChunks(signal)); } default: { return(ApplyFilterDirectly(signal)); } } }
/// <summary> /// Offline OLS filtering /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var firstCount = Math.Min(HopSize - 1, signal.Length); int i = 0, j = 0; for (; i < firstCount; i++) // first HopSize-1 samples are just placed in the delay line { Process(signal[i]); } var filtered = new float[signal.Length + _kernel.Length - 1]; for (; i < signal.Length; i++, j++) // process { filtered[j] = Process(signal[i]); } var lastCount = firstCount + _kernel.Length - 1; for (i = 0; i < lastCount; i++, j++) // get last 'late' samples { filtered[j] = Process(0.0f); } return(new DiscreteSignal(signal.SamplingRate, filtered)); }
/// <summary> /// /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { switch (method) { case FilteringMethod.Custom: { return(this.ProcessChunks(signal)); } case FilteringMethod.OverlapAdd: // are you sure you wanna do this? It's IIR filter! case FilteringMethod.OverlapSave: { var length = Math.Max(DefaultImpulseResponseLength, _a.Length + _b.Length); var fftSize = MathUtils.NextPowerOfTwo(4 * length); var ir = new DiscreteSignal(signal.SamplingRate, ImpulseResponse(length).ToFloats()); return(Operation.BlockConvolve(signal, ir, fftSize, method)); } default: { return(ApplyFilterDirectly(signal)); } } }
/// <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 override DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[input.Length]; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input.Length; posAnalysis += _hopSize) { input.FastCopyTo(_re, _fftSize, posAnalysis); _zeroblock.FastCopyTo(_im, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _im); for (var j = 0; j < _fftSize / 2 + 1; j++) { var mag = Math.Sqrt(_re[j] * _re[j] + _im[j] * _im[j]); var phase = Math.Atan2(_im[j], _re[j]); _re[j] = (float)mag; _im[j] = 0; } for (var j = _fftSize / 2 + 1; j < _fftSize; j++) { _re[j] = _im[j] = 0.0f; } _fft.Inverse(_re, _im); for (var j = 0; j < _re.Length; j++) { output[posSynthesis + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSize; j++) { output[posSynthesis + j] *= _gain; output[j] = Wet * output[j] + Dry * input[j]; } posSynthesis += _hopSize; } for (; posSynthesis < output.Length; posSynthesis++) { output[posSynthesis] *= _gain; output[posSynthesis] = Wet * output[posSynthesis] + Dry * input[posSynthesis]; } 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); _zeroblock.FastCopyTo(_im, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _im); for (var j = 0; j < _fftSize / 2 + 1; 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)); } for (var j = _fftSize / 2 + 1; j < _fftSize; j++) { _re[j] = _im[j] = 0.0f; } _fft.Inverse(_re, _im); 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> /// Does block convolution of <paramref name="signal"/> with <paramref name="kernel"/> /// (using either Overlap-Add or Overlap-Save algorithm). /// </summary> /// <param name="signal">Signal</param> /// <param name="kernel">Convolution kernel</param> /// <param name="fftSize">FFT size</param> /// <param name="method">Block convolution method (OverlapAdd / OverlapSave)</param> public static DiscreteSignal BlockConvolve(DiscreteSignal signal, DiscreteSignal kernel, int fftSize, FilteringMethod method = FilteringMethod.OverlapSave) { IFilter blockConvolver; if (method == FilteringMethod.OverlapAdd) { blockConvolver = new OlaBlockConvolver(kernel.Samples, fftSize); } else { blockConvolver = new OlsBlockConvolver(kernel.Samples, fftSize); } return(blockConvolver.ApplyTo(signal)); }
/// <summary> /// Method implements block convolution of signals (using either OLA or OLS algorithm) /// </summary> /// <param name="signal"></param> /// <param name="kernel"></param> /// <param name="fftSize"></param> /// <param name="method"></param> /// <returns></returns> public static DiscreteSignal BlockConvolve(DiscreteSignal signal, DiscreteSignal kernel, int fftSize, FilteringMethod method = FilteringMethod.OverlapSave) { if (kernel.Length > fftSize) { throw new ArgumentException("Kernel length must not exceed the size of FFT!"); } IFilter blockConvolver; if (method == FilteringMethod.OverlapAdd) { blockConvolver = new OlaBlockConvolver(kernel.Samples, fftSize); } else { blockConvolver = new OlsBlockConvolver(kernel.Samples, fftSize); } return(blockConvolver.ApplyTo(signal)); }
/// <summary> /// Offline filtering /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public double[] ApplyTo(double[] signal, FilteringMethod method = FilteringMethod.Auto) { return(signal.Select(s => Process(s)).ToArray()); }
} // end of FilterNxN /// <summary> /// 十字型滤波 /// </summary> /// <param name="b">位图流</param> /// <param name="N">十字架大小,N为奇数</param> /// <param name="filteringMethod">滤波方法</param> /// <returns></returns> public Bitmap FilterCross(Bitmap b, int N, FilteringMethod filteringMethod) { // 如果 N 为偶数,则变 N 为奇数 if (N % 2 == 0) { N++; } // 十字架数字序列 int[] sequence = new int[N * 2 - 1]; // 十字架半径 int radius = N / 2; int width = b.Width; int height = b.Height; Bitmap dstImage = (Bitmap)b.Clone(); BitmapData srcData = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData dstData = dstImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); // 图像实际处理区域 int rectTop = radius; int rectBottom = height - radius; int rectLeft = radius; int rectRight = width - radius; unsafe { byte *src = (byte *)srcData.Scan0; byte *dst = (byte *)dstData.Scan0; int stride = srcData.Stride; int offset = stride - width * BPP; // 移向最顶行,即第 radius 行 src += stride * rectTop; dst += stride * rectTop; for (int y = rectTop; y < rectBottom; y++) { // 移向最左列,即每行第 radius 列 src += BPP * rectLeft; dst += BPP * rectLeft; for (int x = rectLeft; x < rectRight; x++) { // Alpha dst[3] = src[3]; // 处理 B, G, R 三分量 for (int i = 0; i < 3; i++) { int k = 0; // 收集十字架的数字序列 for (int n = -radius; n <= radius; n++) { // 收集横行 sequence[k++] = src[i + n * BPP]; // 收集竖行 if (n == 0) { continue; // 不收集中心点 } sequence[k++] = src[i + n * stride]; } // n // 根据用户指定的统计方法计算数字序列 dst[i] = (byte)Count(sequence, filteringMethod); } // i // 向后移一像素 src += BPP; dst += BPP; } // x // 移向下一行 // 这里得注意要多移 radius 列,因最右边还有 radius 列不必处理 src += (offset + BPP * radius); dst += (offset + BPP * radius); } // y } b.UnlockBits(srcData); dstImage.UnlockBits(dstData); b.Dispose(); return(dstImage); } // end of FilterCross
/// <summary> /// Applies filter to entire <paramref name="signal"/> and returns new filtered signal. /// </summary> /// <param name="signal">Signal</param> /// <param name="method">Filtering method</param> public abstract double[] ApplyTo(double[] signal, FilteringMethod method = FilteringMethod.Auto);
} // FilteringMethod /// <summary> /// 统计一个数字序列并返回一个特殊值 /// </summary> /// <param name="sequence">数字序列</param> /// <param name="filteringMethod">滤波方法</param> /// <returns></returns> public int Count(int[] sequence, FilteringMethod filteringMethod) { int count = 0; int len = sequence.Length; switch (filteringMethod) { case FilteringMethod.Mean: int sum = 0; for (int i = 0; i < len; i++) { sum += sequence[i]; } // i count = sum / len; break; case FilteringMethod.Median: bool isMovable = true; int t = 0; while (isMovable) { isMovable = false; for (int i = 1; i < len; i++) { if (sequence[i - 1] > sequence[i]) { // 交换 sequence[i-1], sequence[i] t = sequence[i - 1]; sequence[i - 1] = sequence[i]; sequence[i] = t; isMovable = true; } } // i } // isMovable // 取中值 count = sequence[len / 2]; break; case FilteringMethod.Maximum: int max = sequence[0]; for (int i = 1; i < len; i++) { if (sequence[i] > max) { max = sequence[i]; } } // i count = max; break; case FilteringMethod.Minimum: int min = sequence[0]; for (int i = 1; i < len; i++) { if (sequence[i] < min) { min = sequence[i]; } } // i count = min; break; } // switch return(count); } // end of Count
/// <summary> /// Processes entire <paramref name="signal"/> and returns new wave-shaped signal. /// </summary> /// <param name="signal">Input signal</param> /// <param name="method">Filtering method</param> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) => this.FilterOnline(signal);
/// <summary> /// Applies filter to entire <paramref name="signal"/> and returns new filtered signal. /// </summary> /// <param name="signal">Signal</param> /// <param name="method">Filtering method</param> public double[] ApplyTo(double[] signal, FilteringMethod method = FilteringMethod.Auto) => this.FilterOnline(signal);
/// <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); _zeroblock.FastCopyTo(_im, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_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 = 0; 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; } for (var j = _fftSize / 2 + 1; j < _fftSize; j++) { _re[j] = _im[j] = 0.0f; } _fft.Inverse(_re, _im); 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> /// WSOLA algorithm /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { // adjust default parameters for a new sampling rate if (signal.SamplingRate != 22050 && !_userParameters) { var factor = (float)signal.SamplingRate / 22050; _windowSize = (int)(_windowSize * factor); _hopAnalysis = (int)(_hopAnalysis * factor); _hopSynthesis = (int)(_hopAnalysis * _stretch); _maxDelta = (int)(_maxDelta * factor); PrepareConvolver(); } var window = Window.OfType(WindowTypes.Hann, _windowSize); var gain = _hopSynthesis / window.Select(w => w * w).Sum() * 0.75f; // and now WSOLA: var input = signal.Samples; var output = new float[(int)(_stretch * (input.Length + _windowSize))]; var current = new float[_windowSize + _maxDelta]; var prev = new float[_windowSize]; int posSynthesis = 0; for (int posAnalysis = 0; posAnalysis + _windowSize + _maxDelta + _hopSynthesis < input.Length; posAnalysis += _hopAnalysis, posSynthesis += _hopSynthesis) { int delta = 0; if (posAnalysis > _maxDelta / 2) { input.FastCopyTo(current, _windowSize + _maxDelta, posAnalysis - _maxDelta / 2); delta = WaveformSimilarityPos(current, prev, _maxDelta); } else { input.FastCopyTo(current, _windowSize + _maxDelta, posAnalysis); } int size = Math.Min(_windowSize, output.Length - posSynthesis); for (var j = 0; j < size; j++) { output[posSynthesis + j] += current[delta + j] * window[j]; } for (var j = 0; j < _hopSynthesis; j++) { output[posSynthesis + j] *= gain; } input.FastCopyTo(prev, _windowSize, posAnalysis + delta - _maxDelta / 2 + _hopSynthesis); } return(new DiscreteSignal(signal.SamplingRate, output)); }
public DiscreteSignal ApplyTo(DiscreteSignal signal1, DiscreteSignal signal2, FilteringMethod method = FilteringMethod.Auto) { Guard.AgainstInequality(signal1.SamplingRate, signal2.SamplingRate, "1st signal sampling rate", "2nd signal sampling rate"); var input1 = signal1.Samples; var input2 = signal2.Samples; var output = new float[input1.Length]; var windowSum = new float[output.Length]; var posMorph = 0; var endMorph = signal2.Length - _fftSize; var posSynthesis = 0; for (var posAnalysis = 0; posAnalysis + _fftSize < input1.Length; posAnalysis += _hopSize, posMorph += _hopSize) { input1.FastCopyTo(_re1, _fftSize, posAnalysis); _zeroblock.FastCopyTo(_im1, _fftSize); if (posMorph > endMorph) { posMorph = 0; } input2.FastCopyTo(_re2, _fftSize, posMorph); _zeroblock.FastCopyTo(_im2, _fftSize); _re1.ApplyWindow(_window); _re2.ApplyWindow(_window); _fft.Direct(_re1, _im1); _fft.Direct(_re2, _im2); for (var j = 0; j < _fftSize / 2 + 1; j++) { var mag1 = Math.Sqrt(_re1[j] * _re1[j] + _im1[j] * _im1[j]); var phase1 = Math.Atan2(_im1[j], _re1[j]); var mag2 = Math.Sqrt(_re2[j] * _re2[j] + _im2[j] * _im2[j]); var phase2 = Math.Atan2(_im2[j], _re2[j]); _re1[j] = (float)(mag1 * Math.Cos(phase2)); _im1[j] = (float)(mag1 * Math.Sin(phase2)); } for (var j = _fftSize / 2 + 1; j < _fftSize; j++) { _re1[j] = _im1[j] = 0.0f; } _fft.Inverse(_re1, _im1); for (var j = 0; j < _re1.Length; j++) { output[posSynthesis + j] += _re1[j] * _window[j]; } posSynthesis += _hopSize; } posMorph = 0; for (var j = 0; j < output.Length; j++, posMorph++) { output[j] /= _fftSize; if (posMorph > endMorph) { posMorph = 0; } output[j] = Wet * output[j] + Dry * signal2[posMorph]; } return(new DiscreteSignal(signal1.SamplingRate, output)); }
/// <summary> /// Offline processing /// </summary> /// <param name="signal"></param> /// <param name="method"></param> /// <returns></returns> public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { return(new DiscreteSignal(signal.SamplingRate, signal.Samples.Select(s => Process(s)))); }
/// <summary> /// The offline filtering algorithm that should be implemented by particular subclass /// </summary> /// <param name="signal">Signal for filtering</param> /// <param name="method">General filtering strategy</param> /// <returns>Filtered signal</returns> public abstract DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto);
/// <summary> /// Spectral subtraction /// </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[input.Length]; const float beta = 0.009f; const float alphaMin = 2f; const float alphaMax = 5f; const float snrMin = -5f; const float snrMax = 20f; const float k = (alphaMin - alphaMax) / (snrMax - snrMin); const float b = alphaMax - k * snrMin; var pos = 0; for (; pos + _fftSize < input.Length; pos += _hopSize) { input.FastCopyTo(_re, _fftSize, pos); _zeroblock.FastCopyTo(_im, _fftSize); _re.ApplyWindow(_window); _fft.Direct(_re, _im); for (var j = 0; 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)); _re[j] = (float)(mag * Math.Cos(phase)); _im[j] = (float)(mag * Math.Sin(phase)); } for (var j = _fftSize / 2 + 1; j < _fftSize; j++) { _re[j] = _im[j] = 0.0f; } _fft.Inverse(_re, _im); for (var j = 0; j < _re.Length; j++) { output[pos + j] += _re[j] * _window[j]; } for (var j = 0; j < _hopSize; j++) { output[pos + j] *= _gain; } } for (; pos < output.Length; pos++) { output[pos] *= _gain; } return(new DiscreteSignal(signal.SamplingRate, output)); }