/// <summary> /// Play a single clip on an AudioSource; if Looping forever, return InfiniteLoop for the event time. /// </summary> /// <param Name="audioClip">The audio clip to play.</param> /// <param Name="emitter">The emitter to use.</param> /// <param Name="activeEvent">The persistent reference to the event as long as it is playing.</param> /// <returns>The amount of delay, if any, we are waiting before playing the clip. A Looping clip will always return InfiniteLoop.</returns> private float PlayClipAndGetTime(UAudioClip audioClip, AudioSource emitter, ActiveEvent activeEvent) { if (audioClip.DelayCenter == 0) { emitter.PlayClip(audioClip.Sound, audioClip.Looping); if (audioClip.Looping) { return(InfiniteLoop); } return(0); } else { float rndDelay = Random.Range(audioClip.DelayCenter - audioClip.DelayRandomization, audioClip.DelayCenter + audioClip.DelayRandomization); StartCoroutine(PlayClipDelayedCoroutine(audioClip, emitter, rndDelay, activeEvent)); if (audioClip.Looping) { return(InfiniteLoop); } return(rndDelay); } }
private void AddSound(TEvent selectedEvent) { UAudioClip[] tempClips = new UAudioClip[selectedEvent.container.sounds.Length + 1]; selectedEvent.container.sounds.CopyTo(tempClips, 0); tempClips[tempClips.Length - 1] = new UAudioClip(); selectedEvent.container.sounds = tempClips; }
/// <summary> /// Coroutine for "continuous" random containers that alternates between two sources to crossfade clips for continuous playlist Looping. /// </summary> /// <param Name="audioContainer">The audio container.</param> /// <param Name="activeEvent">The persistent reference to the event as long as it is playing.</param> /// <param Name="waitTime">The time in seconds to wait before switching AudioSources for crossfading.</param> /// <returns>The coroutine.</returns> private IEnumerator ContinueRandomContainerCoroutine(AudioContainer audioContainer, ActiveEvent activeEvent, float waitTime) { while (!activeEvent.CancelEvent) { yield return(new WaitForSeconds(waitTime)); audioContainer.CurrentClip = Random.Range(0, audioContainer.Sounds.Length); UAudioClip tempClip = audioContainer.Sounds[audioContainer.CurrentClip]; // Play on primary source. if (activeEvent.PlayingAlt) { activeEvent.PrimarySource.volume = 0f; activeEvent.VolDest = activeEvent.AudioEvent.VolumeCenter; activeEvent.AltVolDest = 0f; activeEvent.CurrentFade = audioContainer.CrossfadeTime; waitTime = (tempClip.Sound.length / activeEvent.PrimarySource.pitch) - audioContainer.CrossfadeTime; PlayClipAndGetTime(tempClip, activeEvent.PrimarySource, activeEvent); } // Play on secondary source. else { activeEvent.SecondarySource.volume = 0f; activeEvent.AltVolDest = activeEvent.AudioEvent.VolumeCenter; activeEvent.VolDest = 0f; activeEvent.CurrentFade = audioContainer.CrossfadeTime; waitTime = (tempClip.Sound.length / activeEvent.SecondarySource.pitch) - audioContainer.CrossfadeTime; PlayClipAndGetTime(tempClip, activeEvent.SecondarySource, activeEvent); } activeEvent.PlayingAlt = !activeEvent.PlayingAlt; } }
/// <summary> /// Play one sound from a container based on container behavior. /// </summary> /// <param Name="currentContainer"></param> /// <param Name="activeEvent"></param> /// <returns>The estimated ActiveTime for the clip, or InfiniteLoop if the container and/or clip are set to loop.</returns> private float PlaySingleClip(AudioContainer currentContainer, ActiveEvent activeEvent) { float tempDelay = 0; if (currentContainer.ContainerType == AudioContainerType.Random) { currentContainer.CurrentClip = Random.Range(0, currentContainer.Sounds.Length); } UAudioClip currentClip = currentContainer.Sounds[currentContainer.CurrentClip]; // Trigger sound and save the delay (in seconds) to add to the total amount of time the event will be considered active. tempDelay = PlayClipAndGetTime(currentClip, activeEvent.PrimarySource, activeEvent); // Ready the next clip in the series if sequence container. if (currentContainer.ContainerType == AudioContainerType.Sequence) { currentContainer.CurrentClip++; if (currentContainer.CurrentClip >= currentContainer.Sounds.Length) { currentContainer.CurrentClip = 0; } } // Return active time based on Looping or clip time. return(GetActiveTimeEstimate(currentClip, activeEvent, tempDelay)); }
/// <summary> /// Coroutine for playing a clip after a delay (in seconds). /// </summary> /// <param Name="audioClip">The clip to play.</param> /// <param Name="emitter">The emitter to use.</param> /// <param Name="delay">The amount of time in seconds to wait before playing audio clip.</param> /// <param Name="activeEvent">The persistent reference to the event as long as it is playing.</param> /// <returns>The coroutine.</returns> private IEnumerator PlayClipDelayedCoroutine(UAudioClip audioClip, AudioSource emitter, float delay, ActiveEvent activeEvent) { yield return(new WaitForSeconds(delay)); if (this.ActiveEvents.Contains(activeEvent)) { emitter.PlayClip(audioClip.Sound, audioClip.Looping); } }
/// <summary> /// Calculates the estimated active time for an ActiveEvent playing the given clip. /// </summary> /// <param Name="audioClip">The clip being played.</param> /// <param Name="activeEvent">The event being played.</param> /// <param Name="additionalDelay">The delay before playing in seconds.</param> /// <returns>The estimated active time of the event based on Looping or clip time. If Looping, this will return InfiniteLoop.</returns> private static float GetActiveTimeEstimate(UAudioClip audioClip, ActiveEvent activeEvent, float additionalDelay) { if (audioClip.Looping || activeEvent.AudioEvent.Container.Looping || additionalDelay == InfiniteLoop) { return(InfiniteLoop); } else { float pitchAdjustedClipLength = activeEvent.PrimarySource.pitch != 0 ? (audioClip.Sound.length / activeEvent.PrimarySource.pitch) : 0; // Restrict non-Looping ActiveTime values to be non-negative. return(Mathf.Max(0.0f, pitchAdjustedClipLength + activeEvent.AudioEvent.InstanceTimeBuffer + additionalDelay)); } }
/// <summary> /// Coroutine for "continuous" sequence containers that alternates between two sources to crossfade clips for continuous playlist Looping. /// </summary> /// <param Name="audioContainer">The audio container.</param> /// <param Name="activeEvent">The persistent reference to the event as long as it is playing.</param> /// <param Name="waitTime">The time in seconds to wait before switching AudioSources to crossfading.</param> /// <returns>The coroutine.</returns> private IEnumerator ContinueSequenceContainerCoroutine(AudioContainer audioContainer, ActiveEvent activeEvent, float waitTime) { while (!activeEvent.CancelEvent) { yield return(new WaitForSeconds(waitTime)); UAudioClip tempClip = audioContainer.Sounds[audioContainer.CurrentClip]; if (tempClip.Sound == null) { Debug.LogErrorFormat(this, "Sound clip in event \"{0}\" is null!", activeEvent.AudioEvent.Name); waitTime = 0; } else { // Play on primary source. if (activeEvent.PlayingAlt) { activeEvent.PrimarySource.volume = 0f; activeEvent.VolDest = activeEvent.AudioEvent.VolumeCenter; activeEvent.AltVolDest = 0f; activeEvent.CurrentFade = audioContainer.CrossfadeTime; waitTime = (tempClip.Sound.length / activeEvent.PrimarySource.pitch) - audioContainer.CrossfadeTime; PlayClipAndGetTime(tempClip, activeEvent.PrimarySource, activeEvent); } // Play on secondary source. else { activeEvent.SecondarySource.volume = 0f; activeEvent.AltVolDest = activeEvent.AudioEvent.VolumeCenter; activeEvent.VolDest = 0f; activeEvent.CurrentFade = audioContainer.CrossfadeTime; waitTime = (tempClip.Sound.length / activeEvent.SecondarySource.pitch) - audioContainer.CrossfadeTime; PlayClipAndGetTime(tempClip, activeEvent.SecondarySource, activeEvent); } } audioContainer.CurrentClip++; if (audioContainer.CurrentClip >= audioContainer.Sounds.Length) { audioContainer.CurrentClip = 0; } activeEvent.PlayingAlt = !activeEvent.PlayingAlt; } }
private void DrawAudioClipInspector(AudioContainer audioContainer, UAudioClip currentSound, out bool wasRemoved) { EditorGUILayout.BeginHorizontal(); SerializedObject playableSO = new SerializedObject(currentSound); playableSO.Update(); EditorGUILayout.PropertyField(playableSO.FindProperty("sound")); if (GUILayout.Button("Remove Audio Clip")) { playableSO.Dispose(); EditorGUILayout.EndHorizontal(); wasRemoved = true; return; } EditorGUILayout.EndHorizontal(); if (!audioContainer.IsContinuous) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(playableSO.FindProperty("delayCenter")); EditorGUILayout.PropertyField(playableSO.FindProperty("delayRandomization")); EditorGUILayout.EndHorizontal(); // Disable looping audio clips in a simultaneous container. // Looping containers within a simultaneous container is allowed. if (allowLooping && !audioContainer.IsSimultaneous) { EditorGUILayout.PropertyField(playableSO.FindProperty("loop")); } else { currentSound.Loop = false; } } playableSO.ApplyModifiedProperties(); wasRemoved = false; }
/// <summary> /// Choose a random sound from a container and play, calling the Looping coroutine to constantly choose new audio clips when current clip ends. /// </summary> /// <param Name="audioContainer">The audio container.</param> /// <param Name="emitter">The emitter to use.</param> /// <param Name="activeEvent">The persistent reference to the event as long as it is playing.</param> private void PlayContinuousRandomContainer(AudioContainer audioContainer, AudioSource emitter, ActiveEvent activeEvent) { audioContainer.CurrentClip = Random.Range(0, audioContainer.Sounds.Length); UAudioClip tempClip = audioContainer.Sounds[audioContainer.CurrentClip]; activeEvent.PrimarySource.volume = 0f; activeEvent.VolDest = activeEvent.AudioEvent.VolumeCenter; activeEvent.AltVolDest = 0f; activeEvent.CurrentFade = audioContainer.CrossfadeTime; float waitTime = (tempClip.Sound.length / emitter.pitch) - activeEvent.AudioEvent.Container.CrossfadeTime; // Ignore clip delay since container is continuous. PlayClipAndGetTime(tempClip, emitter, activeEvent); activeEvent.ActiveTime = InfiniteLoop; StartCoroutine(RecordEventInstanceCoroutine(activeEvent)); audioContainer.CurrentClip++; if (audioContainer.CurrentClip >= audioContainer.Sounds.Length) { audioContainer.CurrentClip = 0; } StartCoroutine(ContinueRandomContainerCoroutine(audioContainer, activeEvent, waitTime)); }
private void AddAudioClip(AudioContainer audioContainer, SerializedObject audioContainerSO) { UAudioClip audioClip = this.playablesGameObject.AddComponent <UAudioClip>(); AddSound(audioContainer, audioContainerSO, audioClip); }
private void DrawSoundClipInspector(AudioContainer audioContainer, SerializedObject audioContainerSerializedObject) { bool oldAllowLooping = allowLooping; allowLooping = allowLooping && !audioContainer.Loop && !audioContainer.IsContinuous; for (int i = 0; audioContainer.sounds != null && i < audioContainer.sounds.Length; i++) { if (audioContainer.sounds[i] == null) { UAudioClip audioClip = this.playablesGameObject.AddComponent <UAudioClip>(); audioContainer.sounds[i] = audioClip; } UPlayable currentSound = audioContainer.sounds[i]; EditorGUILayout.Space(); EditorGUILayout.Space(); bool wasRemoved = false; EditorGUILayout.BeginHorizontal(); soundElementArrowsStyle.margin.top = allowLooping ? 10 : 0; EditorGUILayout.BeginVertical(soundElementArrowsStyle); EditorGUI.BeginDisabledGroup(i <= 0); if (GUILayout.Button("▲", GUILayout.Width(20), GUILayout.Height(15))) { MoveSound(audioContainer, audioContainerSerializedObject, i, -1); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(i >= audioContainer.sounds.Length - 1); if (GUILayout.Button("▼", GUILayout.Width(20), GUILayout.Height(15))) { MoveSound(audioContainer, audioContainerSerializedObject, i, 1); } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(); if (currentSound is UAudioClip) { DrawAudioClipInspector(audioContainer, (UAudioClip)currentSound, out wasRemoved); } else if (currentSound is AudioContainer) { DrawContainerInspector((AudioContainer)currentSound, true, out wasRemoved); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); if (wasRemoved) { audioContainerSerializedObject.FindProperty("sounds").GetArrayElementAtIndex(i).DeleteCommand(); audioContainerSerializedObject.FindProperty("sounds").DeleteArrayElementAtIndex(i); DestroyImmediate(currentSound); RemoveAt(audioContainer.sounds, i); } } allowLooping = oldAllowLooping; }