Example #1
0
        public const double HIGHPASS = 7000.0; //HZ

        public static double[] DistortionMask(int maskLength, double distortionStrength, WaveFormat format)
        {
            double lowpass, highpass;
            double nyquist = SoundProcessing.NyquistRate(format);

            lowpass  = LOWPASS / (nyquist / SoundProcessing.Constants.FFT_LENGTH / 2.0);
            highpass = HIGHPASS / (nyquist / SoundProcessing.Constants.FFT_LENGTH / 2.0);

            double[] mask = new double[maskLength];
            for (int i = 0; i < maskLength; ++i)
            {
                double rampDown = 1.0;
                if (i < lowpass)
                {
                    rampDown = MathUtils.Clamp(Math.Sqrt(i), -distortionStrength, distortionStrength);
                }
                else if (i > highpass)
                {
                    rampDown = MathUtils.Clamp(Math.Sqrt(i / 2), -distortionStrength, distortionStrength);
                }
                mask[i] = rampDown;
            }
            return(mask);
        }
        public static double[] ApplyDistortion(double[] samples, double distortionStrength, WaveFormat fmt)
        {
            List <double> processedSamples = new List <double>();

            //list containing overlapping sound frames
            List <double> savedTimeDomain = new List <double>(SoundProcessing.Constants.FFT_FRAME_LENGTH);

            SoundProcessing.PadZeroes(savedTimeDomain, SoundProcessing.Constants.FFT_FRAME_LENGTH);//pad zeroes to have required container size

            //build a filter mask specified for the distortion
            double[] filterMask = FilterMasks.DistortionMask(
                SoundProcessing.Constants.FREQUENCY_DOMAIN_LENGTH,
                distortionStrength,
                fmt
                );

            for (int i = 0; i < samples.Length; i += SoundProcessing.Constants.FFT_FRAME_LENGTH)
            {
                //cut out a data frame from samples
                var data = samples.Slice(i, SoundProcessing.Constants.FFT_LENGTH);
                //prepare a buffer for FFT
                var complices = new Complex[SoundProcessing.Constants.FREQUENCY_DOMAIN_LENGTH];

                //arrays containing the input samples, the result of FFT and the result of IFFT
                PinnedArray <double>  input           = new PinnedArray <double>(data);
                PinnedArray <Complex> frequencyDomain = new PinnedArray <Complex>(complices);
                PinnedArray <double>  timeDomain      = new PinnedArray <double>(data.Length);

                //convert time domain to frequency domain
                DFT.FFT(input, frequencyDomain);

                //mask the frequencies using a mask created earlier
                for (int j = 0; j < frequencyDomain.Length; ++j)
                {
                    frequencyDomain[j] *= filterMask[j];
                }

                //mask negative frequencies
                for (int j = frequencyDomain.Length - 1; j > frequencyDomain.Length / 2; --j)
                {
                    frequencyDomain[j] *= filterMask[frequencyDomain.Length - j];
                }

                //convert back to time domain
                DFT.IFFT(frequencyDomain, timeDomain);

                //overlapping of the frames
                for (int j = 0; j < SoundProcessing.Constants.OVERLAP; ++j)
                {
                    timeDomain[j] *= (j + 0.0) / SoundProcessing.Constants.OVERLAP;
                    timeDomain[j] += savedTimeDomain[j] * (1.0 - (j + 0.00) / (double)SoundProcessing.Constants.OVERLAP); //overlap with previous samples to avoid stuttering
                }

                //add overlapping sound samples
                savedTimeDomain.Clear();
                for (int j = SoundProcessing.Constants.FFT_FRAME_LENGTH; j < timeDomain.Length; ++j)
                {
                    savedTimeDomain.Add(MathUtils.Clamp(timeDomain[j], -1.0, 1.0));
                }

                //add the actual samples
                for (int j = 0; j < SoundProcessing.Constants.FFT_FRAME_LENGTH; ++j)
                {
                    processedSamples.Add(MathUtils.Clamp(timeDomain[j], -1.0, 1.0));
                }

                //dispose of the PinnedArray objects
                input.Dispose();
                frequencyDomain.Dispose();
                timeDomain.Dispose();
            }

            return(processedSamples.ToArray());
        }