Exemple #1
0
        /// <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));
        }
Exemple #2
0
        /// <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));
        }
Exemple #3
0
        /// <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));
            }
            }
        }
Exemple #9
0
        /// <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));
            }
            }
        }
Exemple #11
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));
        }
Exemple #12
0
        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));
        }
Exemple #14
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));
        }
Exemple #15
0
        /// <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));
        }
Exemple #16
0
        /// <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));
        }
Exemple #17
0
 /// <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());
 }
Exemple #18
0
        } // 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
Exemple #19
0
 /// <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);
Exemple #20
0
        } // 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
Exemple #21
0
 /// <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);
Exemple #22
0
 /// <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);
Exemple #23
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);
                _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));
        }
Exemple #24
0
        /// <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));
        }
Exemple #26
0
 /// <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))));
 }
Exemple #27
0
 /// <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));
        }