Esempio n. 1
0
        private void ProcessorFrequencySkew(SpectrumStage stage, Strengths strengths)
        {
            var scaler    = stage.FrequencySkewTransformed;
            var pinToTop  = stage.PinToHighFrequency;
            var magnitude = fftSignal.Select(x => x.Abs).ToArray();

            for (int i = strengths.FMin; i <= strengths.FMax; i++)
            {
                double k;
                if (pinToTop)
                {
                    k = strengths.FMax - (strengths.FMax - i) * scaler;
                    if (k < strengths.FMin)
                    {
                        k = strengths.FMin;
                    }
                }
                else
                {
                    k = (i - strengths.FMin) * scaler + strengths.FMin;
                    if (k > strengths.FMax)
                    {
                        k = strengths.FMax;
                    }
                }

                var interpolated = AudioLib.Interpolate.Spline(k, magnitude, false);
                fftSignal[i].Abs = interpolated;
            }
        }
Esempio n. 2
0
        private void ProcessApply(SpectrumStage stage, Strengths strengths, Dictionary <ImpulseConfig, Complex[]> stageOutputs)
        {
            if (stage.SelectedApplySource == null)
            {
                return;
            }
            if (stageOutputs == null)
            {
                return;
            }

            var idx = stage.SelectedApplySource.Index;

            if (idx < 0 || idx >= config.Index)             // can only apply things with lower index, because otherwise they haven't been computed yet!
            {
                return;
            }

            var applyFftSignal = stageOutputs.SingleOrDefault(x => x.Key.Index == idx);

            if (applyFftSignal.Value == null)
            {
                return;                 // Probably should never happen!
            }
            for (int i = 1; i < fftSignal.Length / 2; i++)
            {
                var stren = strengths.Strength[i];
                fftSignal[i] *= (1 - (Complex)stren) + ((Complex)stren * applyFftSignal.Value[i]);
                fftSignal[fftSignal.Length - i] *= (1 - (Complex)stren) + ((Complex)stren * applyFftSignal.Value[fftSignal.Length - i]);
            }
        }
Esempio n. 3
0
 private void ProcessGain(SpectrumStage stage, Strengths strengths)
 {
     for (int i = strengths.FMin; i <= strengths.FMax; i++)
     {
         var amount = AudioLib.Utils.DB2gain(stage.GainTransformed * strengths.Strength[i]);
         fftSignal[i] *= (Complex)amount;
         fftSignal[fftSignal.Length - i] *= (Complex)amount;
     }
 }
Esempio n. 4
0
        private void ProcessMinimumPhase(SpectrumStage stage, Strengths strengths)
        {
            // https://dsp.stackexchange.com/questions/7872/derive-minimum-phase-from-magnitude
            // https://ccrma.stanford.edu/~jos/sasp/Minimum_Phase_Filter_Design.html
            // https://uk.mathworks.com/matlabcentral/newsreader/view_thread/17748
            // https://stackoverflow.com/questions/11942855/matlab-hilbert-transform-in-c

            /* Matlab example that achieves what we want:
             *      t=-15:0.25:15;
             *      x = pi*t+j*1e-9;
             *      h = real(sin(x)./x); % simple linear phase FIR
             *      H = fft(h,128);
             *      reaLogH = log(abs(H));
             *      hilb = hilbert(reaLogH);
             *      H2 = exp(hilb);
             *      hMinPhase = real(fliplr(ifft(H2)));
             *      hMinPhase = hMinPhase(1:length(h));
             *
             *      figure(1)
             *      plot(t,h,t,hMinPhase)
             *      xlabel('time')
             *      ylabel('Amplitude')
             */

            // hilbert function is the only problematic one, but I've translated that over to C#
            // This is still pretty much numbers voodoo to me, could someone in the f*****g field write up a pragmatic description
            // of just what the f**k the hilbert transform does without using pages and pages of obscure math?
            // f**k I hate academics...

            if (!stage.MinimumPhase)
            {
                return;
            }

            var H       = fftSignal;
            var reaLogH = new double[H.Length];

            for (int i = 0; i < fftSignal.Length; i++)
            {
                reaLogH[i] = Math.Log(H[i].Abs);
            }

            var hilb = Hilbert(reaLogH);
            var H2   = hilb           // translate over to System.Numerics as I don't have a Complex.Exp(Complex) function in my library... fail on me
                       .Select(x => new System.Numerics.Complex(x.Real, x.Imag))
                       .Select(x => System.Numerics.Complex.Exp(x))
                       .Select(x => new Complex(x.Real, x.Imaginary))
                       .ToArray();

            for (int i = 0; i < fftSignal.Length; i++)
            {
                fftSignal[i] = H2[i];
            }
        }
Esempio n. 5
0
        private void ProcessDelay(SpectrumStage stage, Strengths strengths)
        {
            var delaySamples = stage.DelayMillisTransformed / 1000.0 * samplerate;

            for (int i = strengths.FMin; i <= strengths.FMax; i++)
            {
                var amount = delaySamples / (double)ImpulseConfig.MaxSampleLength;
                amount = amount * strengths.Strength[i];
                var newVal = fftSignal[i] * Complex.CExp(-2 * Math.PI * i * amount);
                fftSignal[i] = newVal;
                fftSignal[fftSignal.Length - i].Arg = -newVal.Arg;
            }
        }
Esempio n. 6
0
        private void ProcessRandomGain(SpectrumStage stage, Strengths strengths)
        {
            var rand = new Random(stage.RandomGainSeedTransformed);

            for (int i = 0; i < stage.RandomGainShiftTransformed; i++)
            {
                rand.NextDouble();                 // pop off x number of samples, "shifting" the sequence forward
            }
            var filterCount   = stage.RandomGainFilteringTransformed;
            var gainAmount    = stage.RandomGainAmountTransformed;
            var randCount     = strengths.Strength.Length + 2 * filterCount;
            var mode          = stage.RandomGainModeTransformed;
            var skew          = stage.RandomSkewAmountTransformed;
            var noise         = Enumerable.Range(0, randCount).Select(x => rand.NextDouble() * 2 - 1).ToArray();
            var filteredNoise = new double[strengths.Strength.Length];

            for (int i = filterCount; i < noise.Length - filterCount; i++)
            {
                var sum = 0.0;
                for (int j = -filterCount; j <= filterCount; j++)
                {
                    var idx = i + j;
                    sum += noise[idx];
                }

                filteredNoise[i - filterCount] = sum / Math.Sqrt(2 * filterCount + 1);
            }

            for (int i = strengths.FMin; i <= strengths.FMax; i++)
            {
                var skewedNoise = Math.Pow(Math.Abs(filteredNoise[i]), skew) * Math.Sign(filteredNoise[i]);
                var gf          = gainAmount * skewedNoise;

                var dbGain = gf * strengths.Strength[i];
                var scaler = AudioLib.Utils.DB2gain(dbGain);

                if (mode == ApplyMode.Amplify && scaler < 1)
                {
                    scaler = 1;
                }
                if (mode == ApplyMode.Reduce && scaler > 1)
                {
                    scaler = 1;
                }
                fftSignal[i] *= (Complex)scaler;
                fftSignal[fftSignal.Length - i] *= (Complex)scaler;
            }
        }
Esempio n. 7
0
        public void ProcessStage(SpectrumStage stage, Dictionary <ImpulseConfig, Complex[]> impulseConfigOutputs)
        {
            lock (locker)
            {
                if (!stage.IsEnabled)
                {
                    return;
                }

                var strengths = GetStrengths(stage);
                ProcessApply(stage, strengths, impulseConfigOutputs);
                ProcessGain(stage, strengths);
                ProcessGainVariation(stage, strengths);
                ProcessRandomGain(stage, strengths);
                ProcessorFrequencySkew(stage, strengths);

                ProcessMinimumPhase(stage, strengths);

                ProcessDelay(stage, strengths);
                ProcessPhaseBands(stage, strengths);
            }
        }
Esempio n. 8
0
        private void ProcessPhaseBands(SpectrumStage stage, Strengths strengths)
        {
            var bands            = stage.PhaseBandsTransformed;
            var shift            = stage.PhaseBandFreqShiftTransformed;
            var sections         = GetBands(bands, shift, samplerate, fftSignal.Length);
            var rand             = new Random(stage.PhaseBandSeedTransformed);
            int pb               = 0;
            var delaySamplesMain = stage.PhaseBandDelayMillisTransformed / 1000 * samplerate;

            foreach (var section in sections)
            {
                var delaySamples     = rand.NextDouble() * delaySamplesMain;
                var k                = pb / (double)(sections.Count - 1);
                var amountOfTracking = Math.Abs(stage.PhaseBandFreqTrackTransformed);
                if (stage.PhaseBandFreqTrackTransformed < 0)
                {
                    k = 1 - k;
                    var track = k * amountOfTracking + (1 - amountOfTracking);
                    delaySamples *= track;
                }
                else
                {
                    var track = k * amountOfTracking + (1 - amountOfTracking);
                    delaySamples *= track;
                }

                var amount = delaySamples / (double)ImpulseConfig.MaxSampleLength;
                for (int i = section[0]; i <= section[1]; i++)
                {
                    amount = amount * strengths.Strength[i];
                    var newVal = fftSignal[i] * Complex.CExp(-2 * Math.PI * i * amount);
                    fftSignal[i] = newVal;
                    fftSignal[fftSignal.Length - i].Arg = -newVal.Arg;
                }

                pb++;
            }
        }
Esempio n. 9
0
        private Strengths GetStrengths(SpectrumStage stage)
        {
            var nyquist     = samplerate / 2;
            var absMaxIndex = fftSignal.Length / 2;
            var minFreq     = stage.MinFreqTransformed;
            var maxFreq     = stage.MaxFreqTransformed;

            // slight hack, because we used a fixed frequency range, we don't pin it relative to the sampling frequency, then the absolute highest frequency
            // that can be selected is 22Khz (set in the MaxFreqTransformed getter) - IF this frequency is used, we stretch it up so that to the nyquist frequency
            // to prevent a jump at 22Khz when using high sampling frequencies
            if (Math.Abs(stage.MinFreqTransformed - ImpulseConfig.MaxFrequency) < 0.01)
            {
                minFreq = nyquist;
            }
            if (Math.Abs(stage.MaxFreqTransformed - ImpulseConfig.MaxFrequency) < 0.01)
            {
                maxFreq = nyquist;
            }

            var fMin = Math.Round(minFreq / (double)nyquist * absMaxIndex);
            var fMax = Math.Round(maxFreq / (double)nyquist * absMaxIndex);

            if (minFreq >= maxFreq)
            {
                return new Strengths {
                           FMax = 1, FMin = 1, Strength = new double[absMaxIndex + 1]
                }
            }
            ;

            if (fMin < 1)
            {
                fMin = 1;
            }
            if (fMax < 1)
            {
                fMax = 1;
            }
            if (fMin >= absMaxIndex)
            {
                fMin = absMaxIndex;
            }
            if (fMax >= absMaxIndex)
            {
                fMax = absMaxIndex;
            }

            var fBlendMin = Math.Round(Math.Pow(2, stage.LowBlendOctsTransformed) * minFreq / (double)nyquist * absMaxIndex);
            var fBlendMax = Math.Round(Math.Pow(2, -stage.HighBlendOctsTransformed) * maxFreq / (double)nyquist * absMaxIndex);

            if (fBlendMin < 1)
            {
                fBlendMin = 1;
            }
            if (fBlendMax < 1)
            {
                fBlendMax = 1;
            }
            if (fBlendMin >= absMaxIndex)
            {
                fBlendMin = absMaxIndex;
            }
            if (fBlendMax >= absMaxIndex)
            {
                fBlendMax = absMaxIndex;
            }

            var blendIn = new double[absMaxIndex + 1];

            for (int i = (int)fMin; i <= (int)fMax; i++)
            {
                var octaveDistance = (i - fMin) / (fBlendMin - fMin) * stage.LowBlendOctsTransformed;
                var value          = (Math.Log(1 + octaveDistance, 2)) / (Math.Log(1 + stage.LowBlendOctsTransformed, 2));

                if (fBlendMin == fMin)
                {
                    blendIn[i] = 1.0;
                }
                else if (i <= fBlendMin)
                {
                    blendIn[i] = value;
                }
                else
                {
                    blendIn[i] = 1.0;
                }
            }

            var blendOut = new double[absMaxIndex + 1];

            for (int i = (int)fMin; i <= (int)fMax; i++)
            {
                var octaveDistance = (i - fBlendMax) / (fMax - fBlendMax) * stage.HighBlendOctsTransformed;
                var value          = (Math.Log(1 + octaveDistance)) / (Math.Log(1 + stage.HighBlendOctsTransformed));

                if (fMax == fBlendMax)
                {
                    blendOut[i] = 0.0;
                }
                else if (i <= fBlendMax)
                {
                    blendOut[i] = 0;
                }
                else
                {
                    blendOut[i] = value;
                }
            }

            // mix the two together so that out cuts against in
            for (int i = 0; i < blendIn.Length; i++)
            {
                blendIn[i] = blendIn[i] - blendOut[i];
                if (blendIn[i] < 0)
                {
                    blendIn[i] = 0;
                }
            }

            return(new Strengths {
                FMin = (int)fMin, FMax = (int)fMax, Strength = blendIn
            });
        }
Esempio n. 10
0
        private void ProcessGainVariation(SpectrumStage stage, Strengths strengths)
        {
            var absMaxIndex     = fftSignal.Length / 2;
            var gain            = new double[strengths.Strength.Length];
            var amt             = stage.GainSmoothingAmountTransformed;
            var octavesToSmooth = stage.GainSmoothingOctavesTransformed;
            var hzPerPartial    = 1 / (double)absMaxIndex * samplerate / 2;
            var mode            = stage.GainSmoothingModeTransformed;

            for (int i = 1; i <= fftSignal.Length / 2; i++)
            {
                var freq     = i * hzPerPartial;
                var lowFreq  = freq * Math.Pow(2, -octavesToSmooth);
                var highFreq = freq * Math.Pow(2, octavesToSmooth);
                var iBelow   = (freq - lowFreq) / hzPerPartial;
                var iAbove   = (highFreq - freq) / hzPerPartial;

                var avgSum = 0.0;
                int count  = 0;
                for (int j = -(int)Math.Round(iBelow); j <= Math.Round(iAbove); j++)
                {
                    var idx = i + j;
                    if (idx <= 0)
                    {
                        continue;
                    }
                    if (idx > absMaxIndex)
                    {
                        continue;
                    }
                    count++;
                    var sample = fftSignal[idx].Abs;
                    avgSum += sample;
                }

                avgSum /= count;
                var avgDb     = AudioLib.Utils.Gain2DB(avgSum);
                var partialDb = AudioLib.Utils.Gain2DB(fftSignal[i].Abs);
                var diffDb    = partialDb - avgDb;

                var stren    = strengths.Strength[i];
                var newMagDb = avgDb + diffDb * (amt * stren + 1 * (1 - stren));
                var newGain  = AudioLib.Utils.DB2gain(newMagDb) / fftSignal[i].Abs;
                gain[i] = newGain;

                if (mode == ApplyMode.Amplify && newGain < 1)
                {
                    gain[i] = 1;
                }
                else if (mode == ApplyMode.Reduce && newGain > 1)
                {
                    gain[i] = 1;
                }
            }

            for (int i = strengths.FMin; i <= strengths.FMax; i++)
            {
                var g = gain[i];
                fftSignal[i] *= (Complex)g;
                fftSignal[fftSignal.Length - i] *= (Complex)g;
            }
        }