Пример #1
0
        public void TestReverse()
        {
            //Arrange
            var test     = _signal.Copy();
            var reversed = _signal.Copy().Samples;

            Array.Reverse(reversed);

            //Act
            test.Reverse();

            //Assert
            Assert.That(test.Samples, Is.EqualTo(reversed));
        }
Пример #2
0
        /// <summary>
        /// Decimation preceded by low-pass filtering
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="factor"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public DiscreteSignal Decimate(DiscreteSignal signal, int factor, FirFilter filter = null)
        {
            if (factor == 1)
            {
                return(signal.Copy());
            }

            var filterSize = factor > MinResamplingFilterOrder / 2 ?
                             2 * factor + 1 :
                             MinResamplingFilterOrder;

            var lpFilter = filter;

            if (filter == null)
            {
                lpFilter = DesignFilter.FirLp(filterSize, 0.5f / factor);

                signal = lpFilter.ApplyTo(signal);
            }

            var output = new float[signal.Length / factor];

            var pos = 0;

            for (var i = 0; i < output.Length; i++)
            {
                output[i] = signal[pos];
                pos      += factor;
            }

            return(new DiscreteSignal(signal.SamplingRate / factor, output));
        }
Пример #3
0
        /// <summary>
        /// Interpolation followed by low-pass filtering
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="factor"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public DiscreteSignal Interpolate(DiscreteSignal signal, int factor, FirFilter filter = null)
        {
            if (factor == 1)
            {
                return(signal.Copy());
            }

            var output = new float[signal.Length * factor];

            var pos = 0;

            for (var i = 0; i < signal.Length; i++)
            {
                output[pos] = factor * signal[i];
                pos        += factor;
            }

            var lpFilter = filter;

            if (filter == null)
            {
                var filterSize = factor > MinResamplingFilterOrder / 2 ?
                                 2 * factor + 1 :
                                 MinResamplingFilterOrder;

                lpFilter = DesignFilter.FirLp(filterSize, 0.5f / factor);
            }

            return(lpFilter.ApplyTo(new DiscreteSignal(signal.SamplingRate * factor, output)));
        }
Пример #4
0
        /// <summary>
        /// Time stretching with auto-derived parameters
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="stretch">Stretch factor (ratio)</param>
        /// <param name="algorithm">Algorithm for TSM (optional)</param>
        /// <returns>Time stretched signal</returns>
        public static DiscreteSignal TimeStretch(DiscreteSignal signal,
                                                 double stretch,
                                                 TsmAlgorithm algorithm = TsmAlgorithm.PhaseVocoderPhaseLocking)
        {
            if (Math.Abs(stretch - 1.0) < 1e-10)
            {
                return(signal.Copy());
            }

            IFilter stretchFilter;

            var frameSize = MathUtils.NextPowerOfTwo(1024 * signal.SamplingRate / 16000);

            switch (algorithm)
            {
            case TsmAlgorithm.PhaseVocoder:
                stretchFilter = new PhaseVocoder(stretch, frameSize / 10, frameSize);
                break;

            case TsmAlgorithm.PhaseVocoderPhaseLocking:
                stretchFilter = new PhaseLockingVocoder(stretch, frameSize / 8, frameSize);
                break;

            case TsmAlgorithm.PaulStetch:
                stretchFilter = new PaulStretch(stretch, frameSize / 10, frameSize * 4);
                break;

            default:
                stretchFilter = new Wsola(stretch);
                break;
            }

            return(stretchFilter.ApplyTo(signal, FilteringMethod.Auto));
        }
Пример #5
0
        /// <summary>
        /// Time stretching
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="stretch">Stretch factor (scale)</param>
        /// <param name="fftSize">Size of FFT</param>
        /// <param name="hopSize">Hop size</param>
        /// <param name="algorithm">Algorithm for TSM</param>
        /// <returns></returns>
        public static DiscreteSignal TimeStretch(DiscreteSignal signal,
                                                 double stretch,
                                                 int fftSize            = 1024,
                                                 int hopSize            = -1,
                                                 TsmAlgorithm algorithm = TsmAlgorithm.Wsola)
        {
            if (Math.Abs(stretch - 1.0) < 1e-10)
            {
                return(signal.Copy());
            }

            var hopAnalysis = hopSize > 0 ? hopSize : fftSize / 4;

            IFilter stretchFilter;

            switch (algorithm)
            {
            case TsmAlgorithm.PhaseVocoder:
                stretchFilter = new PhaseVocoder(stretch, hopAnalysis, fftSize);
                break;

            default:
                stretchFilter = new Wsola(stretch, fftSize);
                break;
            }

            return(stretchFilter.ApplyTo(signal, FilteringOptions.Auto));
        }
Пример #6
0
        /// <summary>
        /// Time stretching with parameters set by user
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="stretch">Stretch factor (ratio)</param>
        /// <param name="windowSize">Window size (for vocoders - FFT size)</param>
        /// <param name="hopSize">Hop size</param>
        /// <param name="algorithm">Algorithm for TSM (optional)</param>
        /// <returns>Time stretched signal</returns>
        public static DiscreteSignal TimeStretch(DiscreteSignal signal,
                                                 double stretch,
                                                 int windowSize,
                                                 int hopSize,
                                                 TsmAlgorithm algorithm = TsmAlgorithm.PhaseVocoderPhaseLocking)
        {
            if (Math.Abs(stretch - 1.0) < 1e-10)
            {
                return(signal.Copy());
            }

            IFilter stretchFilter;

            switch (algorithm)
            {
            case TsmAlgorithm.PhaseVocoder:
                stretchFilter = new PhaseVocoder(stretch, hopSize, windowSize);
                break;

            case TsmAlgorithm.PhaseVocoderPhaseLocking:
                stretchFilter = new PhaseLockingVocoder(stretch, hopSize, windowSize);
                break;

            case TsmAlgorithm.PaulStetch:
                stretchFilter = new PaulStretch(stretch, hopSize, windowSize);
                break;

            default:
                stretchFilter = new Wsola(stretch, windowSize, hopSize);
                break;
            }

            return(stretchFilter.ApplyTo(signal, FilteringMethod.Auto));
        }
Пример #7
0
        /// <summary>
        /// Changes RMS relatively to input <paramref name="signal"/>.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="rmsDb">RMS change in decibels, e.g. -6dB - decrease RMS twice</param>
        public static DiscreteSignal ChangeRms(DiscreteSignal signal, double rmsDb)
        {
            var modified = signal.Copy();

            ChangeRms(modified.Samples, rmsDb);
            return(modified);
        }
Пример #8
0
        /// <summary>
        /// Normalizes RMS.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="rmsDb">RMS in decibels (dBFS), e.g. -6dB, -18dB, -26dB, etc.</param>
        public static DiscreteSignal NormalizeRms(DiscreteSignal signal, double rmsDb)
        {
            var normalized = signal.Copy();

            NormalizeRms(normalized.Samples, rmsDb);
            return(normalized);
        }
Пример #9
0
        /// <summary>
        /// Normalizes peak level.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="peakDb">Peak level in decibels (dBFS), e.g. -1dB, -3dB, etc.</param>
        public static DiscreteSignal NormalizePeak(DiscreteSignal signal, double peakDb)
        {
            var normalized = signal.Copy();

            NormalizePeak(normalized.Samples, peakDb);
            return(normalized);
        }
Пример #10
0
        /// <summary>
        /// Time stretching
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="stretch"></param>
        /// <param name="fftSize"></param>
        /// <param name="hopSize"></param>
        /// <returns></returns>
        public static DiscreteSignal TimeStretch(DiscreteSignal signal, double stretch, int fftSize = 1024, int hopSize = -1)
        {
            if (Math.Abs(stretch - 1.0) < 1e-10)
            {
                return(signal.Copy());
            }

            var hopAnalysis  = hopSize > 0 ? hopSize : fftSize / 4;
            var hopSynthesis = (int)(hopAnalysis * stretch);

            var vocoder = new PhaseVocoder(hopAnalysis, hopSynthesis, fftSize);

            return(vocoder.ApplyTo(signal));
        }
Пример #11
0
        /// <summary>
        /// Simple resampling as the combination of interpolation and decimation.
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="up"></param>
        /// <param name="down"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down, FirFilter filter = null)
        {
            if (up == down)
            {
                return(signal.Copy());
            }

            var newSamplingRate = signal.SamplingRate * up / down;

            if (up > 20 && down > 20)
            {
                return(Resample(signal, newSamplingRate, filter));
            }

            var output = new float[signal.Length * up];

            var pos = 0;

            for (var i = 0; i < signal.Length; i++)
            {
                output[pos] = up * signal[i];
                pos        += up;
            }

            var lpFilter = filter;

            if (filter == null)
            {
                var factor     = Math.Max(up, down);
                var filterSize = factor > MinResamplingFilterOrder / 2 ?
                                 8 * factor + 1 :
                                 MinResamplingFilterOrder;

                lpFilter = DesignFilter.FirLp(filterSize, 0.5f / factor);
            }

            var upsampled = lpFilter.ApplyTo(new DiscreteSignal(signal.SamplingRate * up, output));

            output = new float[upsampled.Length / down];

            pos = 0;
            for (var i = 0; i < output.Length; i++)
            {
                output[i] = upsampled[pos];
                pos      += down;
            }

            return(new DiscreteSignal(newSamplingRate, output));
        }
Пример #12
0
        /// <summary>
        /// Simple resampling (as the combination of interpolation and decimation).
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="newSamplingRate"></param>
        /// <returns></returns>
        public static DiscreteSignal Resample(DiscreteSignal signal, int newSamplingRate)
        {
            if (newSamplingRate == signal.SamplingRate)
            {
                return(signal.Copy());
            }

            var gcd = MathUtils.Gcd(signal.SamplingRate, newSamplingRate);

            var up   = newSamplingRate / gcd;
            var down = signal.SamplingRate / gcd;

            if (up > 20 && down > 20)
            {
                return(ResampleUpDown(signal, up, down));
            }

            var output = new float[signal.Length * up];

            var pos = 0;

            for (var i = 0; i < signal.Length; i++)
            {
                output[pos] = up * signal[i];
                pos        += up;
            }

            var factor     = Math.Max(up, down);
            var filterSize = factor > MinResamplingFilterOrder / 2 ?
                             8 * factor + 1 :
                             MinResamplingFilterOrder;

            var lpFilter = DesignFilter.FirLp(filterSize, 0.5f / factor);

            var upsampled = lpFilter.ApplyTo(new DiscreteSignal(signal.SamplingRate * up, output));

            output = new float[upsampled.Length / down];

            pos = 0;
            for (var i = 0; i < output.Length; i++)
            {
                output[i] = upsampled[pos];
                pos      += down;
            }

            return(new DiscreteSignal(newSamplingRate, output));
        }
Пример #13
0
        /// <summary>
        /// Band-limited resampling
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="newSamplingRate"></param>
        /// <param name="filter"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public DiscreteSignal Resample(DiscreteSignal signal,
                                       int newSamplingRate,
                                       FirFilter filter = null,
                                       int order        = 15)
        {
            if (signal.SamplingRate == newSamplingRate)
            {
                return(signal.Copy());
            }

            var g = (float)newSamplingRate / signal.SamplingRate;

            var input  = signal.Samples;
            var output = new float[(int)(input.Length * g)];

            if (g < 1 && filter == null)
            {
                filter = new FirFilter(DesignFilter.FirWinLp(MinResamplingFilterOrder, g / 2));

                input = filter.ApplyTo(signal).Samples;
            }

            var step = 1 / g;

            for (var n = 0; n < output.Length; n++)
            {
                var x = n * step;

                for (var i = -order; i < order; i++)
                {
                    var j = (int)Math.Floor(x) - i;

                    if (j < 0 || j >= input.Length)
                    {
                        continue;
                    }

                    var   t    = x - j;
                    float w    = (float)(0.5 * (1.0 + Math.Cos(t / order * Math.PI)));  // Hann window
                    float sinc = (float)MathUtils.Sinc(t);                              // Sinc function
                    output[n] += w * sinc * input[j];
                }
            }

            return(new DiscreteSignal(newSamplingRate, output));
        }
Пример #14
0
        /// <summary>
        /// Method implements tube distortion effect
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="filteringOptions"></param>
        /// <returns></returns>
        public DiscreteSignal ApplyTo(DiscreteSignal signal,
                                      FilteringOptions filteringOptions = FilteringOptions.Auto)
        {
            var maxAmp = signal.Samples.Max(s => Math.Abs(s));

            if (Math.Abs(maxAmp) < 1e-10)
            {
                return(signal.Copy());
            }

            IEnumerable <float> tempZ;

            if (Math.Abs(Q) < 1e-10)
            {
                tempZ = signal.Samples.Select(s =>
                {
                    var q = Gain * s / maxAmp;
                    return(Math.Abs(q - Q) < 1e-10 ?
                           1.0f / Dist :
                           (float)(q / (1 - Math.Exp(-Dist * q))));
                });
            }
            else
            {
                tempZ = signal.Samples.Select(s =>
                {
                    var q = Gain * s / maxAmp;
                    return(Math.Abs(q - Q) < 1e-10 ?
                           (float)(1.0 / Dist + Q / (1 - Math.Exp(Dist * Q))) :
                           (float)((q - Q) / (1 - Math.Exp(-Dist * (q - Q))) + Q / (1 - Math.Exp(Dist * Q))));
                });
            }

            var maxZ  = tempZ.Max(z => Math.Abs(z));
            var tempY = tempZ.Zip(signal.Samples, (z, x) => Mix * z * maxAmp / maxZ + (1 - Mix) * x);

            var maxY   = tempY.Max(y => Math.Abs(y));
            var output = tempY.Select(y => y * maxAmp / maxY);

            return(_outputFilter.ApplyTo(new DiscreteSignal(signal.SamplingRate, output)));
        }
Пример #15
0
        /// <summary>
        /// Method implements simple distortion effect
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="filteringOptions"></param>
        /// <returns></returns>
        public DiscreteSignal ApplyTo(DiscreteSignal signal,
                                      FilteringOptions filteringOptions = FilteringOptions.Auto)
        {
            var maxAmp = signal.Samples.Max(s => Math.Abs(s));

            if (Math.Abs(maxAmp) < 1e-8)
            {
                return(signal.Copy());
            }

            var tempZ = signal.Samples.Select(s =>
            {
                var q = Gain * s / maxAmp;
                return(Math.Sign(q) * (1 - Math.Exp(-Math.Abs(q))));
            });

            var maxZ  = tempZ.Max(z => Math.Abs(z));
            var tempY = tempZ.Zip(signal.Samples, (z, x) => Mix * z * maxAmp / maxZ + (1 - Mix) * x);

            var maxY   = tempY.Max(y => Math.Abs(y));
            var output = tempY.Select(y => (float)(y * maxAmp / maxY));

            return(new DiscreteSignal(signal.SamplingRate, output));
        }