private float _vibratoPhase; // Phase through the vibrato sine wave #endregion Fields #region Constructors public Synth(SynthParams sfxParams) { GenerateAudioData(sfxParams); }
private float[] GenerateAudioData(SynthParams sfxParams) { float[] buffer = null; bool _finished = false; for (int i = 0; i < buffer.Length; i++) { if (_finished) return buffer; // Repeats every _repeatLimit times, partially resetting the sound parameters if (sfxParams.RepeatLimit > 0) { if (++_repeatTime >= sfxParams.RepeatLimit) { _repeatTime = 0; Reset(false); } } // If _changeLimit is reached, shifts the pitch if (_changeLimit != 0) { if (++_changeTime >= _changeLimit) { _changeLimit = 0; _period *= sfxParams.ChangeAmount; } } // Acccelerate and apply slide sfxParams.Slide += sfxParams.DeltaSlide; _period *= sfxParams.Slide; // Checks for frequency getting too low, and stops the sound if a minFrequency was set if (_period > _maxPeriod) { _period = _maxPeriod; if (sfxParams.MinFrequency > 0) _finished = true; } _periodTemp = _period; if (sfxParams.IsVibratoEnabled) { _vibratoPhase += sfxParams.VibratoSpeed; _periodTemp = _period * (float)(1.0f + Math.Sin(_vibratoPhase) * sfxParams.VibratoDepth); } _periodTemp = Math.Max((int)_periodTemp,8); if (sfxParams.WaveShape == SynthParams.WaveShapeEnum.Square) { sfxParams.SquareDuty += sfxParams.DutySweep; if (sfxParams.SquareDuty < 0.0) sfxParams.SquareDuty = 0.0f; if (sfxParams.SquareDuty > 0.5) sfxParams.SquareDuty = 0.5f; } // Moves through the different stages of the volume envelope if (++_envelopeTime > _envelopeLength) { _envelopeTime = 0; switch (++_envelopeStage) { case 1: _envelopeLength = _envelopeLength1; break; case 2: _envelopeLength = _envelopeLength2; break; } } // Sets the volume based on the position in the envelope switch (_envelopeStage) { case 0: _envelopeVolume = _envelopeTime * _envelopeOverLength0; break; case 1: _envelopeVolume = 1.0f + (1.0f - _envelopeTime * _envelopeOverLength1) * 2.0f * sfxParams.SustainPunch; break; case 2: _envelopeVolume = 1.0f - _envelopeTime * _envelopeOverLength2; break; case 3: _envelopeVolume = 0.0f; _finished = true; break; } if (sfxParams.IsPhaserEnabled) { _phaserOffset += _phaserDeltaOffset; _phaserInt = (int)_phaserOffset; if (_phaserInt < 0) _phaserInt = -_phaserInt; if (_phaserInt > 1023) _phaserInt = 1023; } if (sfxParams.IsFilterEnabled && Math.Abs(sfxParams.HighPassFilterCutoffSweep) > TOLERANCE) { sfxParams.HighPassFilterCutoff *= sfxParams.HighPassFilterCutoffSweep; if (sfxParams.HighPassFilterCutoff < 0.00001f) sfxParams.HighPassFilterCutoff = 0.00001f; if (sfxParams.HighPassFilterCutoff > 0.1f) sfxParams.HighPassFilterCutoff = 0.1f; } _superSample = 0; // Generates 8 samples which are averaged out to produce superSample for (int cycle = 0; cycle < 8; cycle++) { if (++_phase >= _periodTemp) _phase = _phase % (int)_periodTemp; switch (sfxParams.WaveShape) { case SynthParams.WaveShapeEnum.Square: _sample = ((_phase / _periodTemp) < sfxParams.SquareDuty) ? 0.5f : -0.5f; break; case SynthParams.WaveShapeEnum.Saw: _sample = 1.0f - (_phase / _periodTemp) * 2.0f; break; case SynthParams.WaveShapeEnum.Sine: _pos = _phase / _periodTemp; _pos = _pos > 0.5f ? (_pos - 1.0f) * 6.28318531f : _pos * 6.28318531f; _sample = _pos < 0 ? 1.27323954f * _pos + 0.405284735f * _pos * _pos : 1.27323954f * _pos - 0.405284735f * _pos * _pos; _sample = _sample < 0 ? 0.225f * (_sample * -_sample - _sample) + _sample : 0.225f * (_sample * _sample - _sample) + _sample; break; case SynthParams.WaveShapeEnum.Noise: _sample = GetRandom.Float(-1, 1); break; } // Applies the low and high pass filters if (sfxParams.IsFilterEnabled) { _lpFilterOldPos = _lpFilterPos; sfxParams.LowPassFilterCutoff *= sfxParams.LowPassFilterCutoffSweep; if (sfxParams.LowPassFilterCutoff < 0.0) sfxParams.LowPassFilterCutoff = 0.0f; if (sfxParams.LowPassFilterCutoff > 0.1) sfxParams.LowPassFilterCutoff = 0.1f; if (sfxParams.IsLowPassFilterEnabled) { _lpFilterDeltaPos += (_sample - _lpFilterPos) * sfxParams.LowPassFilterCutoff; _lpFilterDeltaPos *= _lpFilterDamping; } else { _lpFilterPos = _sample; _lpFilterDeltaPos = 0.0f; } _lpFilterPos += _lpFilterDeltaPos; _hpFilterPos += _lpFilterPos - _lpFilterOldPos; _hpFilterPos *= 1.0f - sfxParams.HighPassFilterCutoff; _sample = _hpFilterPos; } if (sfxParams.IsPhaserEnabled) { _phaserBuffer[_phaserPos & 1023] = _sample; _sample += _phaserBuffer[(_phaserPos - _phaserInt + 1024) & 1023]; _phaserPos = (_phaserPos + 1) & 1023; } _superSample += _sample; } // Averages out the super samples and applies volumes _superSample = sfxParams.MasterVolume * _envelopeVolume * _superSample * 0.125f; // Apply clipping if (_superSample < -1f) _superSample = -1f; if (_superSample > 1f) _superSample = 1f; // Writes value to list, ignoring left/right sound channels (this is applied when filtering the audio later) buffer[i] = _superSample; } return buffer; }
public static SynthParams Powerup() { var result = new SynthParams(); if (GetRandom.Bool()) { result.WaveShape = WaveShapeEnum.Saw; } else { result.SquareDuty = GetRandom.Float(0.6f); } if (GetRandom.Bool()) { result.StartFrequency = GetRandom.Float(0.2f, 0.5f); result.Slide = GetRandom.Float(0.1f, 0.5f); result.RepeatSpeed = GetRandom.Float(0.4f, 0.8f); } else { result.StartFrequency = GetRandom.Float(0.2f, 0.5f); result.Slide = GetRandom.Float(0.05f, 0.25f); if (GetRandom.Bool()) { result.VibratoDepth = GetRandom.Float(0.7f); result.VibratoSpeed = GetRandom.Float(0.6f); } } result.SustainTime = GetRandom.Float(0.4f); result.DecayTime = GetRandom.Float(0.1f, 0.5f); return result; }
public static SynthParams Random() { var result = new SynthParams { WaveShape = (WaveShapeEnum) (GetRandom.Float()*4f), AttackTime = (float) Math.Pow(GetRandom.Float(-1, 1), 4), SustainTime = (float) Math.Pow(GetRandom.Float(-1, 1), 2), SustainPunch = (float) Math.Pow(GetRandom.Float(0.8f), 2), DecayTime = GetRandom.Float(), StartFrequency = (GetRandom.Bool()) ? (float) Math.Pow(GetRandom.Float(-1, 1), 2) : ((float) Math.Pow(GetRandom.Float(0.5f), 3) + 0.5f), MinFrequency = 0.0f, Slide = (float) Math.Pow(GetRandom.Float(-1, 1), 5), DeltaSlide = (float) Math.Pow(GetRandom.Float(-1, 1), 3), VibratoDepth = (float) Math.Pow(GetRandom.Float(-1, 1), 3), VibratoSpeed = GetRandom.Float(-1, 1), ChangeAmount = GetRandom.Float(-1, 1), ChangeSpeed = GetRandom.Float(-1, 1), SquareDuty = GetRandom.Float(-1, 1), DutySweep = (float) Math.Pow(GetRandom.Float(-1, 1), 3), RepeatSpeed = GetRandom.Float(-1, 1), PhaserOffset = (float) Math.Pow(GetRandom.Float(-1, 1), 3), PhaserSweep = (float) Math.Pow(GetRandom.Float(-1, 1), 3), LowPassFilterCutoff = 1f - (float) Math.Pow(GetRandom.Float(), 3), LowPassFilterCutoffSweep = (float) Math.Pow(GetRandom.Float(-1, 1), 3), LowPassFilterResonance = GetRandom.Float(-1, 1), HighPassFilterCutoff = (float) Math.Pow(GetRandom.Float(), 5), HighPassFilterCutoffSweep = (float) Math.Pow(GetRandom.Float(-1, 1), 5), }; if (result.AttackTime + result.SustainTime + result.DecayTime < 0.2f) { result.SustainTime = GetRandom.Float(0.2f, 0.5f); result.DecayTime = GetRandom.Float(0.2f, 0.5f); } if ((result.StartFrequency > 0.7f && result.Slide > 0.2) || (result.StartFrequency < 0.2 && result.Slide < -0.05)) { result.Slide = -result.Slide; } if (result.LowPassFilterCutoff < 0.1f && result.LowPassFilterCutoffSweep < -0.05f) { result.LowPassFilterCutoffSweep = -result.LowPassFilterCutoffSweep; } return result; }
public static SynthParams MenuBlip() { var result = new SynthParams(); result.WaveShape = (WaveShapeEnum) (GetRandom.Int(2)); if (result.WaveShape == WaveShapeEnum.Square) result.SquareDuty = GetRandom.Float(0.6f); result.StartFrequency = GetRandom.Float(0.2f, 0.6f); result.SustainTime = GetRandom.Float(0.1f, 0.2f); result.DecayTime = GetRandom.Float(0.2f); result.HighPassFilterCutoff = 0.1f; return result; }
public static SynthParams PlayerHurt() { var result = new SynthParams(); result.WaveShape = (WaveShapeEnum)(GetRandom.Int(3)); if (result.WaveShape == WaveShapeEnum.Sine) result.WaveShape = WaveShapeEnum.Noise; if (result.WaveShape == WaveShapeEnum.Square) result.SquareDuty = GetRandom.Float(0.6f); result.StartFrequency = GetRandom.Float(0.2f, 0.8f); result.Slide = GetRandom.Float(-0.3f, 0.1f); result.SustainTime = GetRandom.Float(0.1f); result.DecayTime = GetRandom.Float(0.1f,0.3f); if (GetRandom.Bool()) result.HighPassFilterCutoff = GetRandom.Float(0.3f); return result; }
public static SynthParams Laser() { var result = new SynthParams(); result.WaveShape = (WaveShapeEnum)(GetRandom.Int(3)); result.StartFrequency = GetRandom.Float(0.5f,1); result.MinFrequency = result.StartFrequency - 0.2f - GetRandom.Float() * 0.6f; if (result.MinFrequency < 0.2f) result.MinFrequency = 0.2f; result.Slide = -0.15f - GetRandom.Float() * 0.2f; if (GetRandom.Float() < 0.33f) { result.StartFrequency = 0.3f + GetRandom.Float() * 0.6f; result.MinFrequency = GetRandom.Float(0.1f); result.Slide = GetRandom.Float(-0.65f,-0.35f); } if (GetRandom.Bool()) { result.SquareDuty = GetRandom.Float(0.5f); result.DutySweep = GetRandom.Float(0.2f); } else { result.SquareDuty = GetRandom.Float(0.4f,0.9f); result.DutySweep = -GetRandom.Float(0.7f); } result.SustainTime = GetRandom.Float(0.1f,0.3f); result.DecayTime = GetRandom.Float(0.4f); if (GetRandom.Bool()) result.SustainPunch = GetRandom.Float(0.3f); if (GetRandom.Bool(1/3)) { result.PhaserOffset = GetRandom.Float(0.2f); result.PhaserSweep = GetRandom.Float(-0.2f,0); } if (GetRandom.Bool()) result.HighPassFilterCutoff = GetRandom.Float(0.3f); return result; }
public static SynthParams Jump() { var result = new SynthParams(); result.WaveShape = WaveShapeEnum.Square; result.SquareDuty = GetRandom.Float(0.6f); result.StartFrequency = GetRandom.Float(0.3f, 0.6f); result.Slide = GetRandom.Float(0.1f, 0.3f); result.SustainTime = GetRandom.Float(0.1f, 0.4f); result.DecayTime = GetRandom.Float(0.1f, 0.3f); if (GetRandom.Bool()) result.HighPassFilterCutoff = GetRandom.Float(0.3f); if (GetRandom.Bool()) result.LowPassFilterCutoff = GetRandom.Float(0.4f, 1.0f); return result; }
public static SynthParams Explosion() { var result = new SynthParams(); result.WaveShape = WaveShapeEnum.Noise; if (GetRandom.Bool()) { result.StartFrequency = GetRandom.Float(0.1f,0.5f); result.Slide = -0.1f + GetRandom.Float() * 0.4f; } else { result.StartFrequency = GetRandom.Float(0.2f,0.9f); result.Slide = GetRandom.Float(-0.2f,0); } result.StartFrequency *= result.StartFrequency; if (GetRandom.Bool(1/5)) result.Slide = 0; if (GetRandom.Bool(1/3)) result.RepeatSpeed = GetRandom.Float(0.3f,0.8f); result.SustainTime = GetRandom.Float(0.1f,0.4f); result.DecayTime = GetRandom.Float(0.5f); result.SustainPunch = GetRandom.Float(0.2f,0.8f); if (GetRandom.Bool()) { result.PhaserOffset = GetRandom.Float(-0.3f, 0.6f); result.PhaserSweep = GetRandom.Float(-0.3f,0); } if (GetRandom.Bool(1/3)) { result.ChangeSpeed = GetRandom.Float(0.6f,0.9f); result.ChangeAmount = GetRandom.Float(0.8f,0.8f); } return result; }
public static SynthParams Default() { var result = new SynthParams(); result.Reset(); return result; }
public static SynthParams Coin() { var result = new SynthParams(); result.StartFrequency = GetRandom.Float(0.4f, 0.9f); result.SustainTime = GetRandom.Float(0.1f); result.DecayTime = GetRandom.Float(0.1f, 0.5f); result.SustainPunch = GetRandom.Float(0.3f, 0.6f); if (GetRandom.Bool()) { result.ChangeSpeed = GetRandom.Float(0.5f, 0.7f); result.ChangeAmount = GetRandom.Float(0.2f, 0.6f); } return result; }