public BfxrGenerator(BfxrParameters p)
        {
            this.rand = new Random();

            this.state.period    = 100.0 / (p.StartFrequency * p.StartFrequency + 0.001);
            this.state.maxPeriod = 100.0 / (p.MinFrequency * p.MinFrequency + 0.001);

            this.state.slide      = 1.0 - 0.01 * p.Slide * p.Slide * p.Slide;
            this.state.deltaSlide = -0.000001 * p.DeltaSlide * p.DeltaSlide * p.DeltaSlide;

            this.state.squareDuty = 0;
            this.state.dutySweep  = 0;
            if (p.Wave == BfxrWave.Square)
            {
                this.state.squareDuty = 0.5 - 0.5 * p.SquareDuty;
                this.state.dutySweep  = -0.00005 * p.DutySweep;
            }

            this.state.changePeriod     = (int)((1.1 - p.ChangeRepeat) * (20000 / 1.1) + 32);
            this.state.changePeriodTime = 0;

            this.state.changeAmount = p.ChangeAmount > 0
                                ? 1.0 - 0.9 * p.ChangeAmount * p.ChangeAmount
                                : 1.0 + 10.0 * p.ChangeAmount * p.ChangeAmount;
            this.state.changeAmount2 = p.ChangeAmount2 > 0
                                ? 1.0 - 0.9 * p.ChangeAmount2 * p.ChangeAmount2
                                : 1.0 + 10.0 * p.ChangeAmount2 * p.ChangeAmount2;
            this.state.changeTime  = 0;
            this.state.changeTime2 = 0;
            this.state.changeLimit = p.ChangeSpeed == 1.0
                                ? 0
                                : (int)(((1.0 - p.ChangeSpeed) * (1.0 - p.ChangeSpeed) * 20000 + 32) *
                                        (1.0 - p.ChangeRepeat + 0.1) / 1.1);
            this.state.changeLimit2 = p.ChangeSpeed2 == 1.0
                                ? 0
                                : (int)(((1.0 - p.ChangeSpeed2) * (1.0 - p.ChangeSpeed2) * 20000 + 32) *
                                        (1.0 - p.ChangeRepeat + 0.1) / 1.1);

            this.initState     = this.state;
            this.pinkGenerator = new PinkGenerator(this.rand);

            this.masterVolume = p.MasterVolume * p.MasterVolume;
            this.wave         = p.Wave;

            double attackTime  = Math.Max(0, p.AttackTime);
            double sustainTime = Math.Max(0.01, p.SustainTime);
            double decayTime   = Math.Max(0, p.DecayTime);
            double totalTime   = attackTime + sustainTime + decayTime;

            if (totalTime < MinLength)
            {
                double fac = MinLength / totalTime;
                attackTime  *= fac;
                sustainTime *= fac;
                decayTime   *= fac;
            }
            this.sustainPunch = p.SustainPunch;
            this.phase        = 0;

            this.minFrequency      = p.MinFrequency;
            this.muted             = false;
            this.overtones         = (int)(p.Overtones * 10);
            this.overtoneFalloff   = p.OvertoneFalloff;
            this.bitcrushFreq      = 1 - Math.Pow(p.BitCrush, 1.0 / 3.0);
            this.bitcrushFreqSweep = -0.000015 * p.BitCrushSweep;
            this.bitcrushPhase     = 0;
            this.bitcrushLast      = 0;

            this.compressionFactor = 1 / (1 + 4 * p.CompressionAmount);
            this.filters           = p.LPFilterCutoff != 1.0 || p.HPFilterCutoff != 0.0;

            this.lpFilterOn          = p.LPFilterCutoff != 1.0;
            this.lpFilterPos         = 0.0;
            this.lpFilterDeltaPos    = 0.0;
            this.lpFilterCutoff      = 0.1 * p.LPFilterCutoff * p.LPFilterCutoff * p.LPFilterCutoff;
            this.lpFilterDeltaCutoff = 1.0 + 0.0001 * p.LPFilterCutoffSweep;
            this.lpFilterDamping     = 1.0 - 5.0 / (1.0 + 20 * p.LPFilterResonance * p.LPFilterResonance) * (0.01 + this.lpFilterCutoff);

            this.hpFilterPos         = 0.0;
            this.hpFilterCutoff      = 0.1 * p.HPFilterCutoff * p.HPFilterCutoff;
            this.hpFilterDeltaCutoff = 1.0 + 0.0003 * p.HPFilterCutoffSweep;

            this.vibratoPhase     = 0;
            this.vibratoSpeed     = 0.01 * p.VibratoSpeed * p.VibratoSpeed;
            this.vibratoAmplitude = 0.5 * p.VibratoDepth;

            this.envelopeVolume     = 0;
            this.envelopeStage      = 0;
            this.envelopeTime       = 0;
            this.envelopeLength0    = (int)(100000 * attackTime * attackTime);
            this.envelopeLength1    = (int)(100000 * sustainTime * sustainTime);
            this.envelopeLength2    = (int)(100000 * decayTime * decayTime + 10);
            this.envelopeLength     = this.envelopeLength0;
            this.envelopeFullLength = this.envelopeLength0 + this.envelopeLength1 + this.envelopeLength2;

            this.envelopeInvLength0 = 1.0 / this.envelopeLength0;
            this.envelopeInvLength1 = 1.0 / this.envelopeLength1;
            this.envelopeInvLength2 = 1.0 / this.envelopeLength2;

            this.flanger            = p.FlangerOffset != 0.0 || p.FlangerSweep != 0.0;
            this.flangerOffset      = 1020.0 * p.FlangerOffset * p.FlangerOffset * (p.FlangerOffset > 0 ? 1 : -1);
            this.flangerDeltaOffset = 0.2 * p.FlangerSweep * p.FlangerSweep * p.FlangerSweep;
            this.flangerPos         = 0;

            this.flangerBuffer    = new float[1024];
            this.noiseBuffer      = new float[32];
            this.pinkNoiseBuffer  = new float[32];
            this.loResNoiseBuffer = new float[32];

            for (int i = 0; i < this.noiseBuffer.Length; i++)
            {
                this.noiseBuffer[i] = 2.0f * (float)this.rand.NextDouble() - 1.0f;
            }
            for (int i = 0; i < this.pinkNoiseBuffer.Length; i++)
            {
                this.pinkNoiseBuffer[i] = this.pinkGenerator.Next();
            }
            float val = 0.0f;

            for (int i = 0; i < this.loResNoiseBuffer.Length; i++)
            {
                if ((i % LoResNoisePeriod) == 0)
                {
                    val = 2.0f * (float)this.rand.NextDouble() - 1.0f;
                }
                this.loResNoiseBuffer[i] = val;
            }

            this.repeatTime  = 0;
            this.repeatLimit = p.RepeatSpeed == 0.0
                                ? 0
                                : (int)((1.0 - p.RepeatSpeed) * (1.0 - p.RepeatSpeed) * 20000) + 32;
        }
        public BfxrGenerator(BfxrParameters p)
        {
            this.rand = new Random();

            this.state.period = 100.0 / (p.StartFrequency * p.StartFrequency + 0.001);
            this.state.maxPeriod = 100.0 / (p.MinFrequency * p.MinFrequency + 0.001);

            this.state.slide = 1.0 - 0.01 * p.Slide * p.Slide * p.Slide;
            this.state.deltaSlide = -0.000001 * p.DeltaSlide * p.DeltaSlide * p.DeltaSlide;

            this.state.squareDuty = 0;
            this.state.dutySweep = 0;
            if (p.Wave == BfxrWave.Square)
            {
                this.state.squareDuty = 0.5 - 0.5 * p.SquareDuty;
                this.state.dutySweep = -0.00005 * p.DutySweep;
            }

            this.state.changePeriod = (int)((1.1 - p.ChangeRepeat) * (20000 / 1.1) + 32);
            this.state.changePeriodTime = 0;

            this.state.changeAmount = p.ChangeAmount > 0
                ? 1.0 - 0.9 * p.ChangeAmount * p.ChangeAmount
                : 1.0 + 10.0 * p.ChangeAmount * p.ChangeAmount;
            this.state.changeAmount2 = p.ChangeAmount2 > 0
                ? 1.0 - 0.9 * p.ChangeAmount2 * p.ChangeAmount2
                : 1.0 + 10.0 * p.ChangeAmount2 * p.ChangeAmount2;
            this.state.changeTime = 0;
            this.state.changeTime2 = 0;
            this.state.changeLimit = p.ChangeSpeed == 1.0
                ? 0
                : (int)(((1.0 - p.ChangeSpeed) * (1.0 - p.ChangeSpeed) * 20000 + 32) *
                    (1.0 - p.ChangeRepeat + 0.1) / 1.1);
            this.state.changeLimit2 = p.ChangeSpeed2 == 1.0
                ? 0
                : (int)(((1.0 - p.ChangeSpeed2) * (1.0 - p.ChangeSpeed2) * 20000 + 32) *
                    (1.0 - p.ChangeRepeat + 0.1) / 1.1);

            this.initState = this.state;
            this.pinkGenerator = new PinkGenerator(this.rand);

            this.masterVolume = p.MasterVolume * p.MasterVolume;
            this.wave = p.Wave;

            double attackTime = Math.Max(0, p.AttackTime);
            double sustainTime = Math.Max(0.01, p.SustainTime);
            double decayTime = Math.Max(0, p.DecayTime);
            double totalTime = attackTime + sustainTime + decayTime;
            if (totalTime < MinLength)
            {
                double fac = MinLength / totalTime;
                attackTime *= fac;
                sustainTime *= fac;
                decayTime *= fac;
            }
            this.sustainPunch = p.SustainPunch;
            this.phase = 0;

            this.minFrequency = p.MinFrequency;
            this.muted = false;
            this.overtones = (int)(p.Overtones * 10);
            this.overtoneFalloff = p.OvertoneFalloff;
            this.bitcrushFreq = 1 - Math.Pow(p.BitCrush, 1.0 / 3.0);
            this.bitcrushFreqSweep = -0.000015 * p.BitCrushSweep;
            this.bitcrushPhase = 0;
            this.bitcrushLast = 0;

            this.compressionFactor = 1 / (1 + 4 * p.CompressionAmount);
            this.filters = p.LPFilterCutoff != 1.0 || p.HPFilterCutoff != 0.0;

            this.lpFilterOn = p.LPFilterCutoff != 1.0;
            this.lpFilterPos = 0.0;
            this.lpFilterDeltaPos = 0.0;
            this.lpFilterCutoff = 0.1 * p.LPFilterCutoff * p.LPFilterCutoff * p.LPFilterCutoff;
            this.lpFilterDeltaCutoff = 1.0 + 0.0001 * p.LPFilterCutoffSweep;
            this.lpFilterDamping = 1.0 - 5.0 / (1.0 + 20 * p.LPFilterResonance * p.LPFilterResonance) * (0.01 + this.lpFilterCutoff);

            this.hpFilterPos = 0.0;
            this.hpFilterCutoff = 0.1 * p.HPFilterCutoff * p.HPFilterCutoff;
            this.hpFilterDeltaCutoff = 1.0 + 0.0003 * p.HPFilterCutoffSweep;

            this.vibratoPhase = 0;
            this.vibratoSpeed = 0.01 * p.VibratoSpeed * p.VibratoSpeed;
            this.vibratoAmplitude = 0.5 * p.VibratoDepth;

            this.envelopeVolume = 0;
            this.envelopeStage = 0;
            this.envelopeTime = 0;
            this.envelopeLength0 = (int)(100000 * attackTime * attackTime);
            this.envelopeLength1 = (int)(100000 * sustainTime * sustainTime);
            this.envelopeLength2 = (int)(100000 * decayTime * decayTime + 10);
            this.envelopeLength = this.envelopeLength0;
            this.envelopeFullLength = this.envelopeLength0 + this.envelopeLength1 + this.envelopeLength2;

            this.envelopeInvLength0 = 1.0 / this.envelopeLength0;
            this.envelopeInvLength1 = 1.0 / this.envelopeLength1;
            this.envelopeInvLength2 = 1.0 / this.envelopeLength2;

            this.flanger = p.FlangerOffset != 0.0 || p.FlangerSweep != 0.0;
            this.flangerOffset = 1020.0 * p.FlangerOffset * p.FlangerOffset * (p.FlangerOffset > 0 ? 1 : -1);
            this.flangerDeltaOffset = 0.2 * p.FlangerSweep * p.FlangerSweep * p.FlangerSweep;
            this.flangerPos = 0;

            this.flangerBuffer = new float[1024];
            this.noiseBuffer = new float[32];
            this.pinkNoiseBuffer = new float[32];
            this.loResNoiseBuffer = new float[32];

            for (int i = 0; i < this.noiseBuffer.Length; i++)
            {
                this.noiseBuffer[i] = 2.0f * (float)this.rand.NextDouble() - 1.0f;
            }
            for (int i = 0; i < this.pinkNoiseBuffer.Length; i++)
            {
                this.pinkNoiseBuffer[i] = this.pinkGenerator.Next();
            }
            float val = 0.0f;
            for (int i = 0; i < this.loResNoiseBuffer.Length; i++)
            {
                if ((i % LoResNoisePeriod) == 0)
                {
                    val = 2.0f * (float)this.rand.NextDouble() - 1.0f;
                }
                this.loResNoiseBuffer[i] = val;
            }

            this.repeatTime = 0;
            this.repeatLimit = p.RepeatSpeed == 0.0
                ? 0
                : (int)((1.0 - p.RepeatSpeed) * (1.0 - p.RepeatSpeed) * 20000) + 32;
        }