void Update() { if(Input.GetKeyUp(KeyCode.Space)) { SfxrParams coinParams = new SfxrParams("0,,0.08,0.25,0.2193,0.5168,,,,,,0.3126,0.5738,,,,,,1,,,,,0.5"); //SfxrParams coinParams = new SfxrParams("0,,0.0736,0.4591,0.3858,0.5416,,,,,,0.5273,0.5732,,,,,,1,,,,,0.5"); coinParams.Mutate(0.1); _synth.CreateSound(coinParams, _blockSize); _synth.Play(); } else if(Input.GetKeyUp(KeyCode.Backspace)) { SfxrParams laserParams = new SfxrParams("0,,0.0359,,0.4491,0.2968,,0.2727,,,,,,0.0191,,0.5249,,,1,,,,,0.5"); laserParams.Mutate(0.15); _synth.CreateSound(laserParams, _blockSize); _synth.Play(); } else if(Input.GetKeyUp(KeyCode.Return)) { SfxrParams explosionParams = new SfxrParams("3,,0.3113,0.6514,0.0025,0.1876,,-0.363,,,,,,,,,,,1,,,,,0.5"); //explosionParams.Mutate(0.1); _synth.CreateSound(explosionParams, _blockSize); _synth.Play(); } }
protected static SfxrItem FindParameters( Component gameComponent, FieldInfo synthFieldInfo, bool autoInitParams) { SfxrParams parameters = null; var synth = (synthFieldInfo.GetValue(gameComponent) as SfxrSynth); if ((synth == null) && autoInitParams) { synth = new SfxrSynth(); synthFieldInfo.SetValue(gameComponent, synth); } if (synth != null) { parameters = synth.parameters; if ((parameters == null) && autoInitParams) { parameters = new SfxrParams(); synth.parameters = parameters; } } SfxrItem item = null; if (parameters != null) { item = new SfxrItem(parameters, gameComponent, synthFieldInfo); } return(item); }
/// <summary> /// Sets the parameters to generate a hit/hurt sound /// </summary> public static SfxrParams HitHurt() { var p = new SfxrParams(); p.Reset(); p.waveType = (WaveType)(uint)(GetRandom() * 3f); if (p.waveType == WaveType.Sine) { p.waveType = WaveType.Noise; } else if (p.waveType == 0) { p.squareDuty = GetRandom() * 0.6f; } p.startFrequency = 0.2f + GetRandom() * 0.6f; p.slide = -0.3f - GetRandom() * 0.4f; p.sustainTime = GetRandom() * 0.1f; p.decayTime = 0.1f + GetRandom() * 0.2f; if (GetRandomBool()) { p.hpFilterCutoff = GetRandom() * 0.3f; } return(p); }
/** * Copies parameters from another instance * @param params Instance to copy parameters from */ public void CopyFrom(SfxrParams __params, bool __makeDirty = false) { bool wasDirty = paramsDirty; SetSettingsString(GetSettingsString()); paramsDirty = wasDirty || __makeDirty; }
void Update() { if (Input.GetKeyUp(KeyCode.Space)) { SfxrParams coinParams = new SfxrParams("0,,0.08,0.25,0.2193,0.5168,,,,,,0.3126,0.5738,,,,,,1,,,,,0.5"); //SfxrParams coinParams = new SfxrParams("0,,0.0736,0.4591,0.3858,0.5416,,,,,,0.5273,0.5732,,,,,,1,,,,,0.5"); coinParams.Mutate(0.1); _synth.CreateSound(coinParams, _blockSize); _synth.Play(); } else if (Input.GetKeyUp(KeyCode.Backspace)) { SfxrParams laserParams = new SfxrParams("0,,0.0359,,0.4491,0.2968,,0.2727,,,,,,0.0191,,0.5249,,,1,,,,,0.5"); laserParams.Mutate(0.15); _synth.CreateSound(laserParams, _blockSize); _synth.Play(); } else if (Input.GetKeyUp(KeyCode.Return)) { SfxrParams explosionParams = new SfxrParams("3,,0.3113,0.6514,0.0025,0.1876,,-0.363,,,,,,,,,,,1,,,,,0.5"); //explosionParams.Mutate(0.1); _synth.CreateSound(explosionParams, _blockSize); _synth.Play(); } }
/// <summary> /// Sets the parameters to generate a jump sound /// </summary> public static SfxrParams Jump() { var p = new SfxrParams(); p.Reset(); p.waveType = 0; p.squareDuty = GetRandom() * 0.6f; p.startFrequency = 0.3f + GetRandom() * 0.3f; p.slide = 0.1f + GetRandom() * 0.2f; p.sustainTime = 0.1f + GetRandom() * 0.3f; p.decayTime = 0.1f + GetRandom() * 0.2f; if (GetRandomBool()) { p.hpFilterCutoff = GetRandom() * 0.3f; } if (GetRandomBool()) { p.lpFilterCutoff = 1.0f - GetRandom() * 0.6f; } return(p); }
/** * Copies parameters from another instance * @param params Instance to copy parameters from */ public void CopyFrom(SfxrParams __params, bool __makeDirty = false) { _waveType = __params.waveType; _attackTime = __params.attackTime; _sustainTime = __params.sustainTime; _sustainPunch = __params.sustainPunch; _decayTime = __params.decayTime; _startFrequency = __params.startFrequency; _minFrequency = __params.minFrequency; _slide = __params.slide; _deltaSlide = __params.deltaSlide; _vibratoDepth = __params.vibratoDepth; _vibratoSpeed = __params.vibratoSpeed; _changeAmount = __params.changeAmount; _changeSpeed = __params.changeSpeed; _squareDuty = __params.squareDuty; _dutySweep = __params.dutySweep; _repeatSpeed = __params.repeatSpeed; _phaserOffset = __params.phaserOffset; _phaserSweep = __params.phaserSweep; _lpFilterCutoff = __params.lpFilterCutoff; _lpFilterCutoffSweep = __params.lpFilterCutoffSweep; _lpFilterResonance = __params.lpFilterResonance; _hpFilterCutoff = __params.hpFilterCutoff; _hpFilterCutoffSweep = __params.hpFilterCutoffSweep; _masterVolume = __params.masterVolume; if (__makeDirty) { paramsDirty = true; } }
/// <summary> /// Sets the parameters to generate a laser/shoot sound /// </summary> public static SfxrParams LaserShoot() { var p = new SfxrParams(); p.Reset(); p.waveType = (WaveType)(uint)(GetRandom() * 3); if (p.waveType == WaveType.Sine && GetRandomBool()) { p.waveType = (WaveType)(uint)(GetRandom() * 2f); } p.startFrequency = 0.5f + GetRandom() * 0.5f; p.minFrequency = p.startFrequency - 0.2f - GetRandom() * 0.6f; if (p.minFrequency < 0.2f) { p.minFrequency = 0.2f; } p.slide = -0.15f - GetRandom() * 0.2f; if (GetRandom() < 0.33f) { p.startFrequency = 0.3f + GetRandom() * 0.6f; p.minFrequency = GetRandom() * 0.1f; p.slide = -0.35f - GetRandom() * 0.3f; } if (GetRandomBool()) { p.squareDuty = GetRandom() * 0.5f; p.dutySweep = GetRandom() * 0.2f; } else { p.squareDuty = 0.4f + GetRandom() * 0.5f; p.dutySweep = -GetRandom() * 0.7f; } p.sustainTime = 0.1f + GetRandom() * 0.2f; p.decayTime = GetRandom() * 0.4f; if (GetRandomBool()) { p.sustainPunch = GetRandom() * 0.3f; } if (GetRandom() < 0.33f) { p.phaserOffset = GetRandom() * 0.2f; p.phaserSweep = -GetRandom() * 0.2f; } if (GetRandomBool()) { p.hpFilterCutoff = GetRandom() * 0.3f; } return(p); }
// Copying methods /** * Returns a copy of this SfxrParams with all settings duplicated * @return A copy of this SfxrParams */ public SfxrParams Clone() { SfxrParams outp = new SfxrParams(); outp.CopyFrom(this); return(outp); }
public SfxrItem( SfxrParams parameters, Component gameComponent, MemberInfo memberInfo) { this.parameters = parameters; this.gameComponent = gameComponent; this.memberInfo = memberInfo; }
/** * Stops the currently playing sound */ public void Stop() { if (_audioPlayer != null) { _audioPlayer.Destroy(); _audioPlayer = null; } if (_original != null) { _params.CopyFrom(_original); _original = null; } }
protected static IEnumerable <SfxrItem> FindParameters( UnityEngine.Object @object, bool autoInitParams) { var gameObject = (@object as GameObject); if (!gameObject) { yield break; } foreach (var gameComponent in gameObject.GetComponents <Component>()) { if (!gameComponent) { continue; } // Search through all the fields of the game-component // and identify all fields that contain SFXR parameters FieldInfo[] fieldInfos = gameComponent.GetType().GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var fieldInfo in fieldInfos) { if (typeof(SfxrSynth).IsAssignableFrom(fieldInfo.FieldType)) { SfxrItem item = FindParameters(gameComponent, fieldInfo, autoInitParams); if (item != null) { yield return(item); } } else if (typeof(SfxrParams).IsAssignableFrom(fieldInfo.FieldType)) { SfxrParams parameters = (fieldInfo.GetValue(gameComponent) as SfxrParams); if ((parameters == null) && autoInitParams) { parameters = new SfxrParams(); fieldInfo.SetValue(gameComponent, parameters); } if (parameters != null) { yield return(new SfxrItem(parameters, gameComponent, fieldInfo)); } } } } }
/// <summary> /// Sets the parameters to generate an explosion sound /// </summary> public static SfxrParams Explosion() { var p = new SfxrParams(); p.Reset(); p.waveType = WaveType.Noise; if (GetRandomBool()) { p.startFrequency = 0.1f + GetRandom() * 0.4f; p.slide = -0.1f + GetRandom() * 0.4f; } else { p.startFrequency = 0.2f + GetRandom() * 0.7f; p.slide = -0.2f - GetRandom() * 0.2f; } p.startFrequency *= p.startFrequency; if (GetRandom() < 0.2f) { p.slide = 0.0f; } if (GetRandom() < 0.33f) { p.repeatSpeed = 0.3f + GetRandom() * 0.5f; } p.sustainTime = 0.1f + GetRandom() * 0.3f; p.decayTime = GetRandom() * 0.5f; p.sustainPunch = 0.2f + GetRandom() * 0.6f; if (GetRandomBool()) { p.phaserOffset = -0.3f + GetRandom() * 0.9f; p.phaserSweep = -GetRandom() * 0.3f; } if (GetRandom() < 0.33f) { p.changeSpeed = 0.6f + GetRandom() * 0.3f; p.changeAmount = 0.8f - GetRandom() * 1.6f; } return(p); }
/// <summary> /// Plays the sound for the specified parameters. /// </summary> /// <param name="parameters">The parameters that details the sound to be generated.</param> /// <param name="skipIfUnvailable">When set to <c>true</c> and the sound cannot presently be played, simply skip this request.</param> /// <returns><c>true</c> if playing was initiated; otherwise, <c>false</c> when no sound was played.</returns> public static bool PlaySound( SfxrParams parameters, bool skipIfUnvailable = true) { if (skipIfUnvailable && (!CanPlaySound())) { return(false); // Nothing was played } var synth = new SfxrSynth(); synth.parameters.SetSettingsString( parameters.GetSettingsString()); synth.Play(); return(true); // Play was initiated }
/** * Plays a mutation of the sound. If the parameters are dirty, synthesises sound as it plays, caching it for later. * If they're not, plays from the cached sound. * Won't play if caching asynchronously. * @param mutationAmount Amount of mutation * @param mutationsNum The number of mutations to cache before picking from them */ public void PlayMutated(float __mutationAmount = 0.05f, uint __mutationsNum = 15) { Stop(); if (_cachingAsync) { return; } _mutation = true; _cachedMutationsNum = __mutationsNum; if (_params.paramsDirty || _cachedMutations == null) { // New set of mutations _cachedMutations = new float[_cachedMutationsNum][]; _cachingMutation = 0; } if (_cachingMutation != -1) { // Continuing caching new mutations Reset(true); // To get _envelopeFullLength _cachedMutation = new float[_envelopeFullLength]; _cachedMutationPos = 0; _cachedMutations[_cachingMutation] = _cachedMutation; _waveData = null; _original = _params.Clone(); _params.Mutate(__mutationAmount); Reset(true); } else { // Play from random cached mutation _waveData = _cachedMutations[(uint)(_cachedMutations.Length * getRandom())]; _waveDataPos = 0; } createGameObject(); }
public bool RenderSettingsColumn(SfxrParams parameters) { bool soundChanged = false; // Begin manual settings column GUILayout.BeginVertical("box"); GUILayout.Label("MANUAL SETTINGS", EditorStyles.boldLabel); GUILayout.Space(8); scrollPosition = GUILayout.BeginScrollView(scrollPosition); soundChanged = RenderParameters(soundParameters) || soundChanged; GUILayout.EndScrollView(); // End manual settings column GUILayout.FlexibleSpace(); GUILayout.EndVertical(); return(soundChanged); }
/// <summary> /// Sets the parameters to generate a blip/select sound /// </summary> public static SfxrParams BlipSelect() { var p = new SfxrParams(); p.Reset(); p.waveType = (WaveType)(uint)(GetRandom() * 2f); if (p.waveType == 0) { p.squareDuty = GetRandom() * 0.6f; } p.startFrequency = 0.2f + GetRandom() * 0.4f; p.sustainTime = 0.1f + GetRandom() * 0.1f; p.decayTime = GetRandom() * 0.2f; p.hpFilterCutoff = 0.1f; return(p); }
/** * Caches a series of mutations on the source sound. * If a callback is passed in, the caching will be done asynchronously, taking maxTimePerFrame milliseconds * per frame to cache, them calling the callback when it's done. * If not, the whole sound is cached immediately - can freeze the player for a few seconds, especially in debug mode. * @param mutationsNum Number of mutations to cache * @param mutationAmount Amount of mutation * @param callback Function to call when the caching is complete * @param maxTimePerFrame Maximum time in milliseconds the caching will use per frame */ public void CacheMutations(uint __mutationsNum = 15, float __mutationAmount = 0.05f, Action __callback = null, bool __isFromCoroutine = false) { Stop(); if (_cachingAsync && !__isFromCoroutine) { return; } _cachedMutationsNum = __mutationsNum; _cachedMutations = new float[_cachedMutationsNum][]; if (__callback != null) { _mutation = true; _cachingAsync = true; GameObject _surrogateObj = new GameObject("SfxrGameObjectSurrogate-" + (Time.realtimeSinceStartup)); SfxrCacheSurrogate _surrogate = _surrogateObj.AddComponent <SfxrCacheSurrogate>(); _surrogate.CacheMutations(this, __mutationsNum, __mutationAmount, __callback); } else { Reset(true); SfxrParams original = _params.Clone(); for (uint i = 0; i < _cachedMutationsNum; i++) { _params.Mutate(__mutationAmount); CacheSound(); _cachedMutations[i] = _cachedWave; _params.CopyFrom(original); } _cachingAsync = false; _cachingMutation = -1; } }
/// <summary> /// Sets the parameters to generate a pickup/coin sound /// </summary> public static SfxrParams PickupCoin() { var p = new SfxrParams(); p.Reset(); p.startFrequency = 0.4f + GetRandom() * 0.5f; p.sustainTime = GetRandom() * 0.1f; p.decayTime = 0.1f + GetRandom() * 0.4f; p.sustainPunch = 0.3f + GetRandom() * 0.3f; if (!GetRandomBool()) { return(p); } p.changeSpeed = 0.5f + GetRandom() * 0.2f; var cnum = (int)(GetRandom() * 7f) + 1; var cden = cnum + (int)(GetRandom() * 7f) + 2; p.changeAmount = cnum / (float)cden; return(p); }
protected virtual void OnGUI() { // Initializations if (soundParameters == null) { soundParameters = new SfxrParams(); soundParameters.Randomize(); } if (synth == null) { synth = new SfxrSynth(); } bool soundChanged = false; // Begin UI scrollPositionRoot = GUILayout.BeginScrollView(scrollPositionRoot); GUILayout.BeginHorizontal(); // Left column (generator buttons, copy & paste) soundChanged = RenderLeftColumn(soundParameters) || soundChanged; // Main settings column soundChanged = RenderSettingsColumn(soundParameters) || soundChanged; // Ends the UI GUILayout.EndHorizontal(); GUILayout.EndScrollView(); // Play sound if necessary if (soundChanged) { synth.parameters.SetSettingsString(soundParameters.GetSettingsString()); PlaySound(); CreateWavePreview(); } }
protected virtual void OnGUI() { // Initializations if (soundParameters == null) { soundParameters = new SfxrParams(); soundParameters.Randomize(); } if (synth == null) { synth = new SfxrSynth(); } bool soundChanged = false; // Begin UI scrollPositionRoot = GUILayout.BeginScrollView(scrollPositionRoot); GUILayout.BeginHorizontal(); // Left column (generator buttons, copy & paste) soundChanged = RenderLeftColumn(soundParameters) || soundChanged; // Main settings column soundChanged = RenderSettingsColumn(soundParameters) || soundChanged; // Ends the UI GUILayout.EndHorizontal(); GUILayout.EndScrollView(); // Play sound if necessary if (soundChanged) { // ADDED by hsandt for debouncing and avoiding Fatal Error on Play spam isWaitingForPreviewDebounce = true; lastSoundChangeTimeStamp = Time.realtimeSinceStartup; } }
/// <summary> /// Sets the parameters to generate a powerup sound /// </summary> public static SfxrParams PowerUp() { var p = new SfxrParams(); p.Reset(); if (GetRandomBool()) { p.waveType = WaveType.Sawtooth; } else { p.squareDuty = GetRandom() * 0.6f; } if (GetRandomBool()) { p.startFrequency = 0.2f + GetRandom() * 0.3f; p.slide = 0.1f + GetRandom() * 0.4f; p.repeatSpeed = 0.4f + GetRandom() * 0.4f; } else { p.startFrequency = 0.2f + GetRandom() * 0.3f; p.slide = 0.05f + GetRandom() * 0.2f; if (GetRandomBool()) { p.vibratoDepth = GetRandom() * 0.7f; p.vibratoSpeed = GetRandom() * 0.6f; } } p.sustainTime = GetRandom() * 0.4f; p.decayTime = 0.1f + GetRandom() * 0.4f; return(p); }
/** * If there is a cached sound to play, reads out of the data. * If there isn't, synthesises new chunch of data, caching it as it goes. * @param data Float[] to write data to * @param channels Number of channels used * @return Whether it needs to continue (there are samples left) or not */ public bool GenerateAudioFilterData(float[] __data, int __channels) { bool endOfSamples = false; if (_waveData != null) { int samplesWritten = WriteSamples(_waveData, (int)_waveDataPos, __data, __channels); _waveDataPos += (uint)samplesWritten; if (samplesWritten == 0) endOfSamples = true; } else { if (_mutation) { if (_original != null) { _waveDataPos = _cachedMutationPos; int samplesNeeded = (int)Mathf.Min((__data.Length / __channels), _cachedMutation.Length - _cachedMutationPos); if (SynthWave(_cachedMutation, (int)_cachedMutationPos, (uint)samplesNeeded) || samplesNeeded == 0) { // Finished _params.CopyFrom(_original); _original = null; _cachingMutation++; endOfSamples = true; if (_cachingMutation >= _cachedMutationsNum) _cachingMutation = -1; } else { _cachedMutationPos += (uint)samplesNeeded; } WriteSamples(_cachedMutation, (int)_waveDataPos, __data, __channels); } } else { if (_cachingNormal) { _waveDataPos = _cachedWavePos; int samplesNeeded = (int)Mathf.Min((__data.Length / __channels), _cachedWave.Length - _cachedWavePos); if (SynthWave(_cachedWave, (int)_cachedWavePos, (uint)samplesNeeded) || samplesNeeded == 0) { _cachingNormal = false; endOfSamples = true; } else { _cachedWavePos += (uint)samplesNeeded; } WriteSamples(_cachedWave, (int)_waveDataPos, __data, __channels); } } } return !endOfSamples; }
/// <summary> /// Renders the specified SFXR parameters in the editor. /// </summary> /// <param name="parameters">The current parameters to be rendered.</param> /// <remarks> /// This method is called automatically for the standalone editor window /// when a game-object with parameters is selected. However, this public /// method can also be called by CustomEditor implementations for specific /// game-components to render the editor in the Inspector window /// (see UnityEditor.Editor for details). Also, this method can be used /// from PropertyDrawer implementations; future releases of the code may /// include such a default drawer (once SfxrSynth and SfxrParams supports /// native serialization for Unity). /// </remarks> public bool RenderParameters(SfxrParams parameters) { bool soundChanged = false; GUIStyle waveTypeStyle = EditorStyles.popup; waveTypeStyle.fontSize = 12; waveTypeStyle.fixedHeight = 22; EditorGUI.BeginChangeCheck(); try { WaveType waveTypeAsEnum = (WaveType)parameters.waveType; waveTypeAsEnum = (WaveType)EditorGUILayout.EnumPopup(new GUIContent("Wave Type", "Shape of the wave"), waveTypeAsEnum, waveTypeStyle); parameters.waveType = (uint)waveTypeAsEnum; GUILayout.Space(12); //RenderPopup(waveTypeOptions, ((int)(parameters.waveType)), (value => parameters.waveType = ((uint)(value))), new GUIContent("Wave Type", "Shape of the wave")); bool isSquareWaveType = (parameters.waveType == 0); RenderSlider(+0, +1, parameters.masterVolume, (value => parameters.masterVolume = value), new GUIContent("Volume", "Overall volume of the sound (0 to 1)")); RenderHeading("Wave Envelope"); RenderSlider(+0, +1, parameters.attackTime, (value => parameters.attackTime = value), new GUIContent("Attack Time", "Length of the volume envelope attack (0 to 1)")); RenderSlider(+0, +1, parameters.sustainTime, (value => parameters.sustainTime = value), new GUIContent("Sustain Time", "Length of the volume envelope sustain (0 to 1)")); RenderSlider(+0, +1, parameters.sustainPunch, (value => parameters.sustainPunch = value), new GUIContent("Sustain Punch", "Tilts the sustain envelope for more 'pop' (0 to 1)")); RenderSlider(+0, +1, parameters.decayTime, (value => parameters.decayTime = value), new GUIContent("Decay Time", "Length of the volume envelope decay (yes, I know it's called release) (0 to 1)")); // BFXR RenderSlider(+0, +1, parameters.compressionAmount, (value => parameters.compressionAmount = value), new GUIContent("Compression", "Pushes amplitudes together into a narrower range to make them stand out more. Very good for sound effects, where you want them to stick out against background music (0 to 1)")); RenderHeading("Frequency"); RenderSlider(+0, +1, parameters.startFrequency, (value => parameters.startFrequency = value), new GUIContent("Start Frequency", "Base note of the sound (0 to 1)")); RenderSlider(+0, +1, parameters.minFrequency, (value => parameters.minFrequency = value), new GUIContent("Minimum Frequency", "If sliding, the sound will stop at this frequency, to prevent really low notes (0 to 1)")); RenderSlider(-1, +1, parameters.slide, (value => parameters.slide = value), new GUIContent("Slide", "Slides the note up or down (-1 to 1)")); RenderSlider(-1, +1, parameters.deltaSlide, (value => parameters.deltaSlide = value), new GUIContent("Delta Slide", "Accelerates the slide (-1 to 1)")); RenderSlider(+0, +1, parameters.vibratoDepth, (value => parameters.vibratoDepth = value), new GUIContent("Vibrato Depth", "Strength of the vibrato effect (0 to 1)")); RenderSlider(+0, +1, parameters.vibratoSpeed, (value => parameters.vibratoSpeed = value), new GUIContent("Vibrato Speed", "Speed of the vibrato effect (i.e. frequency) (0 to 1)")); // BFXR RenderSlider(+0, +1, parameters.overtones, (value => parameters.overtones = value), new GUIContent("Harmonics", "Overlays copies of the waveform with copies and multiples of its frequency. Good for bulking out or otherwise enriching the texture of the sounds (warning: this is the number 1 cause of usfxr slowdown!) (0 to 1)")); RenderSlider(+0, +1, parameters.overtoneFalloff, (value => parameters.overtoneFalloff = value), new GUIContent("Harmonics falloff", "The rate at which higher overtones should decay (0 to 1)")); RenderHeading("Tone Change/Pitch Jump"); // BFXR RenderSlider(+0, +1, parameters.changeRepeat, (value => parameters.changeRepeat = value), new GUIContent("Change Repeat Speed", "Larger Values means more pitch jumps, which can be useful for arpeggiation (0 to 1)")); RenderSlider(-1, +1, parameters.changeAmount, (value => parameters.changeAmount = value), new GUIContent("Change Amount 1", "Shift in note, either up or down (-1 to 1)")); RenderSlider(+0, +1, parameters.changeSpeed, (value => parameters.changeSpeed = value), new GUIContent("Change Speed 1", "How fast the note shift happens (only happens once) (0 to 1)")); // BFXR RenderSlider(-1, +1, parameters.changeAmount2, (value => parameters.changeAmount2 = value), new GUIContent("Change Amount 2", "Shift in note, either up or down (-1 to 1)")); RenderSlider(+0, +1, parameters.changeSpeed2, (value => parameters.changeSpeed2 = value), new GUIContent("Change Speed 2", "How fast the note shift happens (only happens once) (0 to 1)")); RenderHeading("Square Waves"); RenderSlider(+0, +1, parameters.squareDuty, (value => parameters.squareDuty = value), new GUIContent("Square Duty", "Controls the ratio between the up and down states of the square wave, changing the tibre (0 to 1)"), isSquareWaveType); RenderSlider(-1, +1, parameters.dutySweep, (value => parameters.dutySweep = value), new GUIContent("Duty Sweep", "Sweeps the duty up or down (-1 to 1)"), isSquareWaveType); RenderHeading("Repeats"); RenderSlider(+0, +1, parameters.repeatSpeed, (value => parameters.repeatSpeed = value), new GUIContent("Repeat Speed", "Speed of the note repeating - certain variables are reset each time (0 to 1)")); RenderHeading("Phaser"); RenderSlider(-1, +1, parameters.phaserOffset, (value => parameters.phaserOffset = value), new GUIContent("Phaser Offset", "Offsets a second copy of the wave by a small phase, changing the tibre (-1 to 1)")); RenderSlider(-1, +1, parameters.phaserSweep, (value => parameters.phaserSweep = value), new GUIContent("Phaser Sweep", "Sweeps the phase up or down (-1 to 1)")); RenderHeading("Filters"); RenderSlider(+0, +1, parameters.lpFilterCutoff, (value => parameters.lpFilterCutoff = value), new GUIContent("Low-Pass Cutoff", "Frequency at which the low-pass filter starts attenuating higher frequencies (0 to 1)")); RenderSlider(-1, +1, parameters.lpFilterCutoffSweep, (value => parameters.lpFilterCutoffSweep = value), new GUIContent("Low-Pass Cutoff Sweep", "Sweeps the low-pass cutoff up or down (-1 to 1)")); RenderSlider(+0, +1, parameters.lpFilterResonance, (value => parameters.lpFilterResonance = value), new GUIContent("Low-Pass Resonance", "Changes the attenuation rate for the low-pass filter, changing the timbre (0 to 1)")); RenderSlider(+0, +1, parameters.hpFilterCutoff, (value => parameters.hpFilterCutoff = value), new GUIContent("High-Pass Cutoff", "Frequency at which the high-pass filter starts attenuating lower frequencies (0 to 1)")); RenderSlider(-1, +1, parameters.hpFilterCutoffSweep, (value => parameters.hpFilterCutoffSweep = value), new GUIContent("High-Pass Cutoff Sweep", "Sweeps the high-pass cutoff up or down (-1 to 1)")); RenderHeading("Bit Crushing"); // BFXR RenderSlider(+0, +1, parameters.bitCrush, (value => parameters.bitCrush = value), new GUIContent("Bit Crush", "Resamples the audio at a lower frequency (0 to 1)")); RenderSlider(-1, +1, parameters.bitCrushSweep, (value => parameters.bitCrushSweep = value), new GUIContent("Bit Crush Sweep", "Sweeps the Bit Crush filter up or down (-1 to 1)")); } finally { if (EditorGUI.EndChangeCheck()) { parameters.paramsDirty = true; soundChanged = true; } } return(soundChanged); }
public bool RenderLeftColumn(SfxrParams parameters) { bool soundChanged = false; // Begin generator column GUILayout.BeginVertical("box", GUILayout.Width(110)); GUILayout.Label("GENERATOR", EditorStyles.boldLabel); GUILayout.Space(8); if (GUILayout.Button("PICKUP/COIN")) { suggestedName = "PickupCoin"; parameters.GeneratePickupCoin(); soundChanged = true; } if (GUILayout.Button("LASER/SHOOT")) { suggestedName = "LaserShoot"; parameters.GenerateLaserShoot(); soundChanged = true; } if (GUILayout.Button("EXPLOSION")) { suggestedName = "Explosion"; parameters.GenerateExplosion(); soundChanged = true; } if (GUILayout.Button("POWERUP")) { suggestedName = "Powerup"; parameters.GeneratePowerup(); soundChanged = true; } if (GUILayout.Button("HIT/HURT")) { suggestedName = "HitHurt"; parameters.GenerateHitHurt(); soundChanged = true; } if (GUILayout.Button("JUMP")) { suggestedName = "Jump"; parameters.GenerateJump(); soundChanged = true; } if (GUILayout.Button("BLIP/SELECT")) { suggestedName = "BlipSelect"; parameters.GenerateBlipSelect(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("MUTATE")) { parameters.Mutate(); soundChanged = true; } if (GUILayout.Button("RANDOMIZE")) { suggestedName = "Random"; parameters.Randomize(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("COPY (OLD)")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsStringLegacy(); } if (GUILayout.Button("COPY")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsString(); } if (GUILayout.Button("PASTE")) { suggestedName = null; parameters.SetSettingsString(EditorGUIUtility.systemCopyBuffer); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("PLAY SOUND")) { PlaySound(); } GUILayout.Space(30); if (GUILayout.Button("EXPORT WAV")) { var path = EditorUtility.SaveFilePanel("Export as WAV", "", getSuggestedName() + ".wav", "wav"); if (path.Length != 0) { SfxrSynth synth = new SfxrSynth(); synth.parameters.SetSettingsString(parameters.GetSettingsString()); File.WriteAllBytes(path, synth.GetWavFile()); } } GUILayout.Space(30); soundTitle = GUILayout.TextField(soundTitle); bool canSave = !string.IsNullOrEmpty(soundTitle) && !soundTitle.Contains(";") && !soundTitle.Contains(":"); bool mustReplace = canSave && SoundContainer.Contains(soundTitle); string buttonName = "SAVE"; if (!canSave) { buttonName = "INVALID NAME"; } else if (mustReplace) { buttonName = "REPLACE"; } else { buttonName = "SAVE"; } if (!canSave) { bool prevVal = GUI.enabled; GUI.enabled = false; GUILayout.Button(buttonName); GUI.enabled = prevVal; } else { if (GUILayout.Button(buttonName)) { string soundParams = parameters.GetSettingsString(); if (mustReplace) { SoundContainer.ReplaceSound(soundTitle, soundParams); } else { SoundContainer.AddSound(soundTitle, soundParams); } } } if (canSave && mustReplace) { if (GUILayout.Button("LOAD")) { string soundParams = SoundContainer.GetSound(soundTitle); parameters.SetSettingsString(soundParams); soundChanged = true; } } else { bool prevVal = GUI.enabled; GUI.enabled = false; GUILayout.Button("LOAD"); GUI.enabled = prevVal; } if (canSave && mustReplace) { if (GUILayout.Button("DELETE")) { SoundContainer.DeleteSound(soundTitle); } } else { bool prevVal = GUI.enabled; GUI.enabled = false; GUILayout.Button("DELETE"); GUI.enabled = prevVal; } // End generator column GUILayout.FlexibleSpace(); GUILayout.EndVertical(); return(soundChanged); }
public bool RenderLeftColumn(SfxrParams parameters) { bool soundChanged = false; // Begin generator column GUILayout.BeginVertical("box", GUILayout.Width(110)); GUILayout.Label("GENERATOR", EditorStyles.boldLabel); GUILayout.Space(8); if (GUILayout.Button("PICKUP/COIN")) { suggestedName = "PickupCoin"; parameters.GeneratePickupCoin(); soundChanged = true; } if (GUILayout.Button("LASER/SHOOT")) { suggestedName = "LaserShoot"; parameters.GenerateLaserShoot(); soundChanged = true; } if (GUILayout.Button("EXPLOSION")) { suggestedName = "Explosion"; parameters.GenerateExplosion(); soundChanged = true; } if (GUILayout.Button("POWERUP")) { suggestedName = "Powerup"; parameters.GeneratePowerup(); soundChanged = true; } if (GUILayout.Button("HIT/HURT")) { suggestedName = "HitHurt"; parameters.GenerateHitHurt(); soundChanged = true; } if (GUILayout.Button("JUMP")) { suggestedName = "Jump"; parameters.GenerateJump(); soundChanged = true; } if (GUILayout.Button("BLIP/SELECT")) { suggestedName = "BlipSelect"; parameters.GenerateBlipSelect(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("MUTATE")) { parameters.Mutate(); soundChanged = true; } if (GUILayout.Button("RANDOMIZE")) { suggestedName = "Random"; parameters.Randomize(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("COPY (OLD)")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsStringLegacy(); } if (GUILayout.Button("COPY")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsString(); } if (GUILayout.Button("PASTE")) { suggestedName = null; parameters.SetSettingsString(EditorGUIUtility.systemCopyBuffer); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("PLAY SOUND")) { PlaySound(); } GUILayout.Space(30); if (GUILayout.Button("EXPORT WAV")) { var path = EditorUtility.SaveFilePanel("Export as WAV", "", getSuggestedName() + ".wav", "wav"); if (path.Length != 0) { SfxrSynth synth = new SfxrSynth(); synth.parameters.SetSettingsString(parameters.GetSettingsString()); File.WriteAllBytes(path, synth.GetWavFile()); } } // End generator column GUILayout.FlexibleSpace(); GUILayout.EndVertical(); return(soundChanged); }
/** * Copies parameters from another instance * @param params Instance to copy parameters from */ public void CopyFrom(SfxrParams __params, bool __makeDirty = false) { _waveType = __params.waveType; _attackTime = __params.attackTime; _sustainTime = __params.sustainTime; _sustainPunch = __params.sustainPunch; _decayTime = __params.decayTime; _startFrequency = __params.startFrequency; _minFrequency = __params.minFrequency; _slide = __params.slide; _deltaSlide = __params.deltaSlide; _vibratoDepth = __params.vibratoDepth; _vibratoSpeed = __params.vibratoSpeed; _changeAmount = __params.changeAmount; _changeSpeed = __params.changeSpeed; _squareDuty = __params.squareDuty; _dutySweep = __params.dutySweep; _repeatSpeed = __params.repeatSpeed; _phaserOffset = __params.phaserOffset; _phaserSweep = __params.phaserSweep; _lpFilterCutoff = __params.lpFilterCutoff; _lpFilterCutoffSweep = __params.lpFilterCutoffSweep; _lpFilterResonance = __params.lpFilterResonance; _hpFilterCutoff = __params.hpFilterCutoff; _hpFilterCutoffSweep = __params.hpFilterCutoffSweep; _masterVolume = __params.masterVolume; if (__makeDirty) paramsDirty = true; }
// Copying methods /** * Returns a copy of this SfxrParams with all settings duplicated * @return A copy of this SfxrParams */ public SfxrParams Clone() { SfxrParams outp = new SfxrParams(); outp.CopyFrom(this); return outp; }
/** * If there is a cached sound to play, reads out of the data. * If there isn't, synthesises new chunch of data, caching it as it goes. * @param data Float[] to write data to * @param channels Number of channels used * @return Whether it needs to continue (there are samples left) or not */ public bool GenerateAudioFilterData(float[] __data, int __channels) { bool endOfSamples = false; if (_waveData != null) { int samplesWritten = WriteSamples(_waveData, (int)_waveDataPos, __data, __channels); _waveDataPos += (uint)samplesWritten; if (samplesWritten == 0) { endOfSamples = true; } } else { if (_mutation) { if (_original != null) { _waveDataPos = _cachedMutationPos; int samplesNeeded = (int)Mathf.Min((__data.Length / __channels), _cachedMutation.Length - _cachedMutationPos); if (SynthWave(_cachedMutation, (int)_cachedMutationPos, (uint)samplesNeeded) || samplesNeeded == 0) { // Finished _params.CopyFrom(_original); _original = null; _cachingMutation++; endOfSamples = true; if (_cachingMutation >= _cachedMutationsNum) { _cachingMutation = -1; } } else { _cachedMutationPos += (uint)samplesNeeded; } WriteSamples(_cachedMutation, (int)_waveDataPos, __data, __channels); } } else { if (_cachingNormal) { _waveDataPos = _cachedWavePos; int samplesNeeded = (int)Mathf.Min((__data.Length / __channels), _cachedWave.Length - _cachedWavePos); if (SynthWave(_cachedWave, (int)_cachedWavePos, (uint)samplesNeeded) || samplesNeeded == 0) { _cachingNormal = false; endOfSamples = true; } else { _cachedWavePos += (uint)samplesNeeded; } WriteSamples(_cachedWave, (int)_waveDataPos, __data, __channels); } } } return(!endOfSamples); }
// ================================================================================================================ // INTERNAL INTERFACE --------------------------------------------------------------------------------------------- /** * Resets the runing variables from the params * Used once at the start (total reset) and for the repeat effect (partial reset) * @param totalReset If the reset is total */ private void Reset(bool __totalReset) { // Shorter reference SfxrParams p = _params; _period = 100.0f / (p.startFrequency * p.startFrequency + 0.001f); _maxPeriod = 100.0f / (p.minFrequency * p.minFrequency + 0.001f); _slide = 1.0f - p.slide * p.slide * p.slide * 0.01f; _deltaSlide = -p.deltaSlide * p.deltaSlide * p.deltaSlide * 0.000001f; if (p.waveType == 0) { _squareDuty = 0.5f - p.squareDuty * 0.5f; _dutySweep = -p.dutySweep * 0.00005f; } _changePeriod = Mathf.Max(((1f - p.changeRepeat) + 0.1f) / 1.1f) * 20000f + 32f; _changePeriodTime = 0; if (p.changeAmount > 0.0) { _changeAmount = 1.0f - p.changeAmount * p.changeAmount * 0.9f; } else { _changeAmount = 1.0f + p.changeAmount * p.changeAmount * 10.0f; } _changeTime = 0; _changeReached = false; if (p.changeSpeed == 1.0f) { _changeLimit = 0; } else { _changeLimit = (int)((1f - p.changeSpeed) * (1f - p.changeSpeed) * 20000f + 32f); } if (p.changeAmount2 > 0f) { _changeAmount2 = 1f - p.changeAmount2 * p.changeAmount2 * 0.9f; } else { _changeAmount2 = 1f + p.changeAmount2 * p.changeAmount2 * 10f; } _changeTime2 = 0; _changeReached2 = false; if (p.changeSpeed2 == 1.0f) { _changeLimit2 = 0; } else { _changeLimit2 = (int)((1f - p.changeSpeed2) * (1f - p.changeSpeed2) * 20000f + 32f); } _changeLimit = (int)(_changeLimit * ((1f - p.changeRepeat + 0.1f) / 1.1f)); _changeLimit2 = (int)(_changeLimit2 * ((1f - p.changeRepeat + 0.1f) / 1.1f)); if (__totalReset) { p.paramsDirty = false; _masterVolume = p.masterVolume * p.masterVolume; _waveType = p.waveType; if (p.sustainTime < 0.01) { p.sustainTime = 0.01f; } float totalTime = p.attackTime + p.sustainTime + p.decayTime; if (totalTime < 0.18f) { float multiplier = 0.18f / totalTime; p.attackTime *= multiplier; p.sustainTime *= multiplier; p.decayTime *= multiplier; } _sustainPunch = p.sustainPunch; _phase = 0; _overtones = (int)(p.overtones * 10f); _overtoneFalloff = p.overtoneFalloff; _minFrequency = p.minFrequency; _bitcrushFreq = 1f - Mathf.Pow(p.bitCrush, 1f / 3f); _bitcrushFreqSweep = -p.bitCrushSweep * 0.000015f; _bitcrushPhase = 0; _bitcrushLast = 0; _compressionFactor = 1f / (1f + 4f * p.compressionAmount); _filters = p.lpFilterCutoff != 1.0 || p.hpFilterCutoff != 0.0; _lpFilterPos = 0.0f; _lpFilterDeltaPos = 0.0f; _lpFilterCutoff = p.lpFilterCutoff * p.lpFilterCutoff * p.lpFilterCutoff * 0.1f; _lpFilterDeltaCutoff = 1.0f + p.lpFilterCutoffSweep * 0.0001f; _lpFilterDamping = 5.0f / (1.0f + p.lpFilterResonance * p.lpFilterResonance * 20.0f) * (0.01f + _lpFilterCutoff); if (_lpFilterDamping > 0.8f) { _lpFilterDamping = 0.8f; } _lpFilterDamping = 1.0f - _lpFilterDamping; _lpFilterOn = p.lpFilterCutoff != 1.0f; _hpFilterPos = 0.0f; _hpFilterCutoff = p.hpFilterCutoff * p.hpFilterCutoff * 0.1f; _hpFilterDeltaCutoff = 1.0f + p.hpFilterCutoffSweep * 0.0003f; _vibratoPhase = 0.0f; _vibratoSpeed = p.vibratoSpeed * p.vibratoSpeed * 0.01f; _vibratoAmplitude = p.vibratoDepth * 0.5f; _envelopeVolume = 0.0f; _envelopeStage = 0; _envelopeTime = 0; _envelopeLength0 = p.attackTime * p.attackTime * 100000.0f; _envelopeLength1 = p.sustainTime * p.sustainTime * 100000.0f; _envelopeLength2 = p.decayTime * p.decayTime * 100000.0f + 10f; _envelopeLength = _envelopeLength0; _envelopeFullLength = (uint)(_envelopeLength0 + _envelopeLength1 + _envelopeLength2); _envelopeOverLength0 = 1.0f / _envelopeLength0; _envelopeOverLength1 = 1.0f / _envelopeLength1; _envelopeOverLength2 = 1.0f / _envelopeLength2; _phaser = p.phaserOffset != 0.0f || p.phaserSweep != 0.0f; _phaserOffset = p.phaserOffset * p.phaserOffset * 1020.0f; if (p.phaserOffset < 0.0f) { _phaserOffset = -_phaserOffset; } _phaserDeltaOffset = p.phaserSweep * p.phaserSweep * p.phaserSweep * 0.2f; _phaserPos = 0; if (_phaserBuffer == null) { _phaserBuffer = new float[1024]; } if (_noiseBuffer == null) { _noiseBuffer = new float[32]; } if (_pinkNoiseBuffer == null) { _pinkNoiseBuffer = new float[32]; } if (_pinkNumber == null) { _pinkNumber = new PinkNumber(); } if (_loResNoiseBuffer == null) { _loResNoiseBuffer = new float[32]; } uint i; for (i = 0; i < 1024; i++) { _phaserBuffer[i] = 0.0f; } for (i = 0; i < 32; i++) { _noiseBuffer[i] = getRandom() * 2.0f - 1.0f; } for (i = 0; i < 32; i++) { _pinkNoiseBuffer[i] = _pinkNumber.getNextValue(); } for (i = 0; i < 32; i++) { _loResNoiseBuffer[i] = ((i % LO_RES_NOISE_PERIOD) == 0) ? getRandom() * 2.0f - 1.0f : _loResNoiseBuffer[i - 1]; } _repeatTime = 0; if (p.repeatSpeed == 0.0) { _repeatLimit = 0; } else { _repeatLimit = (int)((1.0 - p.repeatSpeed) * (1.0 - p.repeatSpeed) * 20000) + 32; } } }
/// <summary> /// Renders the specified SFXR parameters in the editor. /// </summary> /// <param name="parameters">The current parameters to be rendered.</param> /// <remarks> /// This method is called automatically for the standalone editor window /// when a game-object with parameters is selected. However, this public /// method can also be called by CustomEditor implementations for specific /// game-components to render the editor in the Inspector window /// (see UnityEditor.Editor for details). Also, this method can be used /// from PropertyDrawer implementations; future releases of the code may /// include such a default drawer (once SfxrSynth and SfxrParams supports /// native serialization for Unity). /// </remarks> public static void RenderParameters(SfxrParams parameters) { if (parameters == null) { return; } if (waveTypeOptions == null) { waveTypeOptions = new GUIContent[] { new GUIContent("Square Wave", "Square (0)"), new GUIContent("Sawtooth", "Saw (1)"), new GUIContent("Sine Wave", "Sin (2)"), new GUIContent("Noise", "Noise (3)") }; } EditorGUI.BeginChangeCheck(); try { RenderHeading("General Settings"); RenderPopup(waveTypeOptions, ((int)(parameters.waveType)), (value => parameters.waveType = ((uint)(value))), new GUIContent("Wave Type", "Shape of the wave")); bool isSquareWaveType = (parameters.waveType == 0); RenderSlider(+0, +1, parameters.masterVolume, (value => parameters.masterVolume = value), new GUIContent("Volume", "Overall volume of the sound (0 to 1)")); RenderHeading("Wave Envelope"); RenderSlider(+0, +1, parameters.attackTime, (value => parameters.attackTime = value), new GUIContent("Attack Time", "Length of the volume envelope attack (0 to 1)")); RenderSlider(+0, +1, parameters.sustainTime, (value => parameters.sustainTime = value), new GUIContent("Sustain Time", "Length of the volume envelope sustain (0 to 1)")); RenderSlider(+0, +1, parameters.sustainPunch, (value => parameters.sustainPunch = value), new GUIContent("Sustain Punch", "Tilts the sustain envelope for more 'pop' (0 to 1)")); RenderSlider(+0, +1, parameters.decayTime, (value => parameters.decayTime = value), new GUIContent("Decay Time", "Length of the volume envelope decay (yes, I know it's called release) (0 to 1)")); RenderHeading("Frequency"); RenderSlider(+0, +1, parameters.startFrequency, (value => parameters.startFrequency = value), new GUIContent("Start Frequency", "Base note of the sound (0 to 1)")); RenderSlider(+0, +1, parameters.minFrequency, (value => parameters.minFrequency = value), new GUIContent("Minimum Frequency", "If sliding, the sound will stop at this frequency, to prevent really low notes (0 to 1)")); RenderSlider(-1, +1, parameters.slide, (value => parameters.slide = value), new GUIContent("Slide", "Slides the note up or down (-1 to 1)")); RenderSlider(-1, +1, parameters.deltaSlide, (value => parameters.deltaSlide = value), new GUIContent("Delta Slide", "Accelerates the slide (-1 to 1)")); RenderSlider(+0, +1, parameters.vibratoDepth, (value => parameters.vibratoDepth = value), new GUIContent("Vibrato Depth", "Strength of the vibrato effect (0 to 1)")); RenderSlider(+0, +1, parameters.vibratoSpeed, (value => parameters.vibratoSpeed = value), new GUIContent("Vibrato Speed", "Speed of the vibrato effect (i.e. frequency) (0 to 1)")); RenderHeading("Tone Change"); RenderSlider(-1, +1, parameters.changeAmount, (value => parameters.changeAmount = value), new GUIContent("Change Amount", "Shift in note, either up or down (-1 to 1)")); RenderSlider(+0, +1, parameters.changeSpeed, (value => parameters.changeSpeed = value), new GUIContent("Change Speed", "How fast the note shift happens (only happens once) (0 to 1)")); RenderHeading("Square Waves"); RenderSlider(+0, +1, parameters.squareDuty, (value => parameters.squareDuty = value), new GUIContent("Square Duty", "Controls the ratio between the up and down states of the square wave, changing the tibre (0 to 1)"), isSquareWaveType); RenderSlider(-1, +1, parameters.dutySweep, (value => parameters.dutySweep = value), new GUIContent("Duty Sweep", "Sweeps the duty up or down (-1 to 1)"), isSquareWaveType); RenderHeading("Repeats"); RenderSlider(+0, +1, parameters.repeatSpeed, (value => parameters.repeatSpeed = value), new GUIContent("Repeat Speed", "Speed of the note repeating - certain variables are reset each time (0 to 1)")); RenderHeading("Phaser"); RenderSlider(-1, +1, parameters.phaserOffset, (value => parameters.phaserOffset = value), new GUIContent("Phaser Offset", "Offsets a second copy of the wave by a small phase, changing the tibre (-1 to 1)")); RenderSlider(-1, +1, parameters.phaserSweep, (value => parameters.phaserSweep = value), new GUIContent("Phaser Sweep", "Sweeps the phase up or down (-1 to 1)")); RenderHeading("Filters"); RenderSlider(+0, +1, parameters.lpFilterCutoff, (value => parameters.lpFilterCutoff = value), new GUIContent("Low-Pass Cutoff", "Frequency at which the low-pass filter starts attenuating higher frequencies (0 to 1)")); RenderSlider(-1, +1, parameters.lpFilterCutoffSweep, (value => parameters.lpFilterCutoffSweep = value), new GUIContent("Low-Pass Cutoff Sweep", "Sweeps the low-pass cutoff up or down (-1 to 1)")); RenderSlider(+0, +1, parameters.lpFilterResonance, (value => parameters.lpFilterResonance = value), new GUIContent("Low-Pass Resonance", "Changes the attenuation rate for the low-pass filter, changing the timbre (0 to 1)")); RenderSlider(+0, +1, parameters.hpFilterCutoff, (value => parameters.hpFilterCutoff = value), new GUIContent("High-Pass Cutoff", "Frequency at which the high-pass filter starts attenuating lower frequencies (0 to 1)")); RenderSlider(-1, +1, parameters.hpFilterCutoffSweep, (value => parameters.hpFilterCutoffSweep = value), new GUIContent("High-Pass Cutoff Sweep", "Sweeps the high-pass cutoff up or down (-1 to 1)")); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); try { if (CanPlaySound()) { GUILayoutOption buttonHeight = GUILayout.MinHeight(40.0f); RenderButton("Play Sound", () => PlaySound(parameters, false), null, buttonHeight); } else { EditorGUILayout.HelpBox("To play the sound, the editor must be playing the game.", MessageType.Info, true); } } finally { EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); RenderHeading("Tools"); EditorGUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); EditorGUILayout.BeginVertical(); try { if (RenderButton("Randomize")) { parameters.Randomize(); PlaySound(parameters); } if (RenderButton("Mutate")) { parameters.Mutate(); // TODO: Allow for mutation-quantity parameter to be specified PlaySound(parameters); } } finally { EditorGUILayout.EndVertical(); } GUILayout.FlexibleSpace(); } finally { EditorGUILayout.EndHorizontal(); } RenderHeading("Generators"); EditorGUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); EditorGUILayout.BeginVertical(); try { bool play = false; play = (RenderButton("Pickup Coin", parameters.GeneratePickupCoin) || play); play = (RenderButton("Laser Shoot", parameters.GenerateLaserShoot) || play); play = (RenderButton("Explosion", parameters.GenerateExplosion) || play); play = (RenderButton("Powerup", parameters.GeneratePowerup) || play); play = (RenderButton("Hit Hurt", parameters.GenerateHitHurt) || play); play = (RenderButton("Jump", parameters.GenerateJump) || play); play = (RenderButton("Blip Select", parameters.GenerateBlipSelect) || play); if (play) { PlaySound(parameters); } } finally { EditorGUILayout.EndVertical(); } GUILayout.FlexibleSpace(); } finally { EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); RenderHeading("Clipboard"); EditorGUILayout.BeginHorizontal(); try { GUILayout.FlexibleSpace(); if (GUILayout.Button("Copy Parameters")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsString(); } if (GUILayout.Button("Paste Parameters")) { parameters.SetSettingsString(EditorGUIUtility.systemCopyBuffer); PlaySound(parameters); } GUILayout.FlexibleSpace(); } finally { EditorGUILayout.EndHorizontal(); } } finally { if (EditorGUI.EndChangeCheck()) { parameters.paramsDirty = true; } } }
static bool GetRandomBool() { return(SfxrParams.GetRandomBool()); }
static float GetRandom() { return(SfxrParams.GetRandom()); }
public bool RenderLeftColumn(SfxrParams parameters) { bool soundChanged = false; // Begin generator column GUILayout.BeginVertical("box", GUILayout.Width(110)); GUILayout.Label("合成器", EditorStyles.boldLabel); GUILayout.Space(8); if (GUILayout.Button("捡拾/金币")) { suggestedName = "PickupCoin"; parameters.GeneratePickupCoin(); soundChanged = true; } if (GUILayout.Button("激光/射击")) { suggestedName = "LaserShoot"; parameters.GenerateLaserShoot(); soundChanged = true; } if (GUILayout.Button("爆炸")) { suggestedName = "Explosion"; parameters.GenerateExplosion(); soundChanged = true; } if (GUILayout.Button("能量提升")) { suggestedName = "Powerup"; parameters.GeneratePowerup(); soundChanged = true; } if (GUILayout.Button("击中/受伤")) { suggestedName = "HitHurt"; parameters.GenerateHitHurt(); soundChanged = true; } if (GUILayout.Button("跳跃")) { suggestedName = "Jump"; parameters.GenerateJump(); soundChanged = true; } if (GUILayout.Button("选择/切换")) { suggestedName = "BlipSelect"; parameters.GenerateBlipSelect(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("MUTATE")) { parameters.Mutate(); soundChanged = true; } if (GUILayout.Button("随机")) { suggestedName = "Random"; parameters.Randomize(); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("复制 (OLD)")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsStringLegacy(); } if (GUILayout.Button("复制")) { EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsString(); } if (GUILayout.Button("黏贴")) { suggestedName = null; parameters.SetSettingsString(EditorGUIUtility.systemCopyBuffer); soundChanged = true; } GUILayout.Space(30); if (GUILayout.Button("播放")) { PlaySound(); } GUILayout.Space(30); if (GUILayout.Button("导出")) { var path = EditorUtility.SaveFilePanel("导出为WAV", "", getSuggestedName() + ".wav", "wav"); if (path.Length != 0) { SfxrSynth synth = new SfxrSynth(); synth.parameters.SetSettingsString(parameters.GetSettingsString()); File.WriteAllBytes(path, synth.GetWavFile()); } } // End generator column GUILayout.FlexibleSpace(); GUILayout.EndVertical(); return(soundChanged); }
/** * Plays a mutation of the sound. If the parameters are dirty, synthesises sound as it plays, caching it for later. * If they're not, plays from the cached sound. * Won't play if caching asynchronously. * @param mutationAmount Amount of mutation * @param mutationsNum The number of mutations to cache before picking from them */ public void PlayMutated(float __mutationAmount = 0.05f, uint __mutationsNum = 15) { Stop(); if (_cachingAsync) return; _mutation = true; _cachedMutationsNum = __mutationsNum; if (_params.paramsDirty || _cachedMutations == null) { // New set of mutations _cachedMutations = new float[_cachedMutationsNum][]; _cachingMutation = 0; } if (_cachingMutation != -1) { // Continuing caching new mutations Reset(true); // To get _envelopeFullLength _cachedMutation = new float[_envelopeFullLength]; _cachedMutationPos = 0; _cachedMutations[_cachingMutation] = _cachedMutation; _waveData = null; _original = _params.Clone(); _params.Mutate(__mutationAmount); Reset(true); } else { // Play from random cached mutation _waveData = _cachedMutations[(uint)(_cachedMutations.Length * getRandom())]; _waveDataPos = 0; } createGameObject(); }