Example #1
0
        /// <summary>
        /// Get the default BFXR parameters.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters Default()
        {
            var p = new BfxrParameters();

            foreach (PropertyInfo prop in typeof(BfxrParameters).GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var attr = prop.GetCustomAttribute <ParamAttribute>();
                if (attr != null)
                {
                    prop.SetValue(p, attr.Default);
                }
            }
            return(p);
        }
Example #2
0
        /// <summary>
        /// Generate parameters for a random explosion sound.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters Explosion()
        {
            var p = BfxrParameters.Default();

            p.Wave = BfxrWave.Noise;

            if (rand.NextDouble() < 0.5)
            {
                p.StartFrequency = randFloat(0.1, 0.4);
                p.Slide          = randFloat(-0.5, -0.1);
            }
            else
            {
                p.StartFrequency = randFloat(0.2, 0.7);
                p.Slide          = randFloat(-0.4, -0.2);
            }
            p.StartFrequency = p.StartFrequency * p.StartFrequency;
            if (rand.NextDouble() < 0.2)
            {
                p.Slide = 0;
            }
            if (rand.NextDouble() < 0.33)
            {
                p.RepeatSpeed = randFloat(0.3, 0.8);
            }

            p.SustainTime  = randFloat(0.1, 0.4);
            p.DecayTime    = randFloat(0, 0.5);
            p.SustainPunch = randFloat(0.2, 0.8);

            if (rand.NextDouble() < 0.5)
            {
                p.FlangerOffset = randFloat(-0.3, 0.6);
                p.FlangerSweep  = randFloat(-0.3, 0);
            }

            if (rand.NextDouble() < 0.33)
            {
                p.ChangeSpeed  = randFloat(0.6, 0.9);
                p.ChangeAmount = randFloat(-0.8, 0.8);
            }

            return(p);
        }
Example #3
0
        /// <summary>
        /// Generate parameters for a random coin pickup sound.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters PickupCoin()
        {
            var p = BfxrParameters.Default();

            p.StartFrequency = randFloat(0.4, 0.9);
            p.SustainTime    = randFloat(0, 0.1);
            p.DecayTime      = randFloat(0.1, 0.5);
            p.SustainPunch   = randFloat(0.3, 0.6);

            if (rand.NextDouble() < 0.5)
            {
                p.ChangeSpeed = randFloat(0.5, 0.7);
                int numer = rand.Next(1, 8);
                int denom = numer + rand.Next(2, 9);
                p.ChangeAmount = (double)numer / (double)denom;
            }

            return(p);
        }
Example #4
0
        /// <summary>
        /// Deserialize a set of parameters from the BFXR tool.
        /// </summary>
        /// <param name="data">The BFXR parameterss, serialized as a string.</param>
        public static BfxrParameters Deserialize(string data)
        {
            string[] fieldText = data.Split(new char[] { ',' });
            var      p         = new BfxrParameters();

            foreach (PropertyInfo prop in typeof(BfxrParameters).GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var attr = prop.GetCustomAttribute <ParamAttribute>();
                if (attr == null)
                {
                    continue;
                }
                object value = attr.Default;
                string s     = attr.Order < fieldText.Length ? fieldText[attr.Order] : null;
                if (s != null && s.Length > 0)
                {
                    double v;
                    if (!double.TryParse(s, out v))
                    {
                        Console.WriteLine("Warning: Cannot parse value for {0}: {1}", prop.Name, s);
                    }
                    else
                    {
                        var cattr = attr as ContinuousParamAttribute;
                        if (cattr != null)
                        {
                            double nv = Math.Max(cattr.Minimum, Math.Min(cattr.Maximum, v));
                            if (nv != v)
                            {
                                Console.WriteLine("Warning: Value {0} out of range for {1}, should be {2} .. {3}", v, prop.Name, cattr.Minimum, cattr.Maximum);
                            }
                            value = nv;
                        }
                        else
                        {
                            value = (BfxrWave)(Math.Max(0, Math.Min(8, (int)v)));
                        }
                    }
                }
                prop.SetValue(p, value);
            }
            return(p);
        }
Example #5
0
 /// <summary>
 /// Deserialize a set of parameters from the BFXR tool.
 /// </summary>
 /// <param name="data">The BFXR parameterss, serialized as a string.</param>
 public static BfxrParameters Deserialize(string data)
 {
     string[] fieldText = data.Split(new char[]{ ',' });
     var p = new BfxrParameters();
     foreach (PropertyInfo prop in typeof(BfxrParameters).GetProperties(BindingFlags.Instance | BindingFlags.Public))
     {
         var attr = prop.GetCustomAttribute<ParamAttribute>();
         if (attr == null)
             continue;
         object value = attr.Default;
         string s = attr.Order < fieldText.Length ? fieldText[attr.Order] : null;
         if (s != null && s.Length > 0)
         {
             double v;
             if (!double.TryParse(s, out v))
             {
                 Console.WriteLine("Warning: Cannot parse value for {0}: {1}", prop.Name, s);
             }
             else
             {
                 var cattr = attr as ContinuousParamAttribute;
                 if (cattr != null)
                 {
                     double nv = Math.Max(cattr.Minimum, Math.Min(cattr.Maximum, v));
                     if (nv != v)
                     {
                         Console.WriteLine("Warning: Value {0} out of range for {1}, should be {2} .. {3}", v, prop.Name, cattr.Minimum, cattr.Maximum);
                     }
                     value = nv;
                 }
                 else
                 {
                     value = (BfxrWave)(Math.Max(0, Math.Min(8, (int)v)));
                 }
             }
         }
         prop.SetValue(p, value);
     }
     return p;
 }
Example #6
0
 /// <summary>
 /// Get the default BFXR parameters.
 /// </summary>
 /// <returns>BFXR parameters.</returns>
 public static BfxrParameters Default()
 {
     var p = new BfxrParameters();
     foreach (PropertyInfo prop in typeof(BfxrParameters).GetProperties(BindingFlags.Instance | BindingFlags.Public))
     {
         var attr = prop.GetCustomAttribute<ParamAttribute>();
         if (attr != null)
         {
             prop.SetValue(p, attr.Default);
         }
     }
     return p;
 }
Example #7
0
        /// <summary>
        /// Generate parameters for a random laser shoot sound.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters LaserShoot()
        {
            var p = BfxrParameters.Default();

            switch (rand.Next(0, 12) / 5)
            {
            case 0:
                p.Wave = BfxrWave.Square;
                break;

            case 1:
                p.Wave = BfxrWave.Saw;
                break;

            case 2:
                p.Wave = BfxrWave.Sine;
                break;
            }

            p.StartFrequency = randFloat(0.5, 1.0);
            p.MinFrequency   = Math.Max(0.2, p.StartFrequency - randFloat(0.2, 0.8));
            p.Slide          = randFloat(-0.35, -0.15);

            if (rand.NextDouble() < 0.33)
            {
                p.StartFrequency = randFloat(0, 0.6);
                p.MinFrequency   = randFloat(0, 0.1);
                p.Slide          = randFloat(-0.65, -0.35);
            }

            if (p.Wave == BfxrWave.Square)
            {
                if (rand.NextDouble() < 0.5)
                {
                    p.SquareDuty = randFloat(0, 0.5);
                    p.DutySweep  = randFloat(0, 0.2);
                }
                else
                {
                    p.SquareDuty = randFloat(0.4, 0.9);
                    p.DutySweep  = randFloat(-0.7, 0);
                }
            }

            p.SustainTime = randFloat(0.1, 0.3);
            p.DecayTime   = randFloat(0, 0.4);
            if (rand.NextDouble() < 0.5)
            {
                p.SustainPunch = randFloat(0, 0.3);
            }

            if (rand.NextDouble() < 0.33)
            {
                p.FlangerOffset = randFloat(0, 0.2);
                p.FlangerSweep  = randFloat(-0.2, 0);
            }

            if (rand.NextDouble() < 0.5)
            {
                p.HPFilterCutoff = randFloat(0, 0.3);
            }

            return(p);
        }
Example #8
0
        /// <summary>
        /// Generate parameters for a random hit or hurt sound.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters HitHurt()
        {
            var p = BfxrParameters.Default();

            return(p);
        }
Example #9
0
        /// <summary>
        /// Generate parameters for a random powerup sound.
        /// </summary>
        /// <returns>BFXR parameters.</returns>
        public static BfxrParameters Powerup()
        {
            var p = BfxrParameters.Default();

            return(p);
        }
Example #10
0
        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;
        }
Example #11
0
        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;
        }