/// <summary> /// Play all clips in container simultaneously /// </summary> private float PlaySimultaneousClips(AudioContainer currentContainer, ActiveEvent activeEvent) { float tempDelay = 0; float finalActiveTime = 0f; if (currentContainer.Looping) { finalActiveTime = InfiniteLoop; } for (int i = 0; i < currentContainer.Sounds.Length; i++) { tempDelay = PlayClipAndGetTime(currentContainer.Sounds[i], activeEvent.PrimarySource, activeEvent); if (finalActiveTime != InfiniteLoop) { float estimatedActiveTimeNeeded = GetActiveTimeEstimate(currentContainer.Sounds[i], activeEvent, tempDelay); if (estimatedActiveTimeNeeded == InfiniteLoop || estimatedActiveTimeNeeded > finalActiveTime) { finalActiveTime = estimatedActiveTimeNeeded; } } } return(finalActiveTime); }
/// <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> /// Play a non-continuous container. /// </summary> private float PlayOneOffContainer(ActiveEvent activeEvent) { AudioContainer currentContainer = activeEvent.AudioEvent.Container; // Fading or Looping overrides immediate volume settings. if (activeEvent.AudioEvent.FadeInTime == 0 && !activeEvent.AudioEvent.Container.Looping) { activeEvent.VolDest = activeEvent.PrimarySource.volume; } // Simultaneous sounds. float clipTime = 0; if (currentContainer.ContainerType == AudioContainerType.Simultaneous) { clipTime = PlaySimultaneousClips(currentContainer, activeEvent); } // Sequential and Random sounds. else { clipTime = PlaySingleClip(currentContainer, activeEvent); } activeEvent.ActiveTime = clipTime; return(clipTime); }
private void MoveSound(AudioContainer audioContainer, SerializedObject audioContainerSO, int soundIndex, int positionDiff) { int newIndex = soundIndex + positionDiff; if (soundIndex >= 0 && soundIndex < audioContainer.sounds.Length && newIndex >= 0 && newIndex < audioContainer.sounds.Length) { audioContainerSO.FindProperty("sounds").MoveArrayElement(soundIndex, soundIndex + positionDiff); } }
private void AddSound(AudioContainer audioContainer, SerializedObject audioContainerSO, UPlayable newPlayable) { if (audioContainer.sounds == null) { audioContainer.sounds = new UPlayable[0]; } audioContainerSO.FindProperty("sounds").InsertArrayElementAtIndex(audioContainer.sounds.Length); audioContainerSO.FindProperty("sounds").GetArrayElementAtIndex(audioContainer.sounds.Length).objectReferenceValue = newPlayable; }
private void RemoveAllSounds(AudioContainer audioContainer) { if (audioContainer.sounds != null) { foreach (UPlayable playable in audioContainer.sounds) { if (playable is AudioContainer) { RemoveAllSounds((AudioContainer)playable); } DestroyImmediate(playable); } } }
/// <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 AddAudioContainer(AudioContainer audioContainer, SerializedObject audioContainerSO) { AudioContainer newContainer = this.playablesGameObject.AddComponent <AudioContainer>(); AddSound(audioContainer, audioContainerSO, newContainer); }
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; }
private void DrawContainerInspector(AudioContainer audioContainer, bool canRemove, out bool wasRemoved) { bool addedSound = false; SerializedObject audioContainedSerializedObject = new SerializedObject(audioContainer); audioContainedSerializedObject.Update(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("containerType")); if (canRemove) { if (GUILayout.Button("Remove Container")) { wasRemoved = true; audioContainedSerializedObject.Dispose(); EditorGUILayout.EndHorizontal(); RemoveAllSounds(audioContainer); return; } } EditorGUILayout.EndHorizontal(); if (!audioContainer.IsContinuous) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("delayCenter")); EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("delayRandomization")); EditorGUILayout.EndHorizontal(); if (allowLooping) { EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("loop")); if (audioContainer.Loop) { EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("loopTime")); } } } else { EditorGUILayout.PropertyField(audioContainedSerializedObject.FindProperty("crossfadeTime")); } // Sounds if (audioContainer.isExpanded) { EditorGUILayout.Space(); } EditorGUILayout.BeginHorizontal(); audioContainer.isExpanded = EditorGUILayout.Foldout(audioContainer.isExpanded, "Sounds"); if (audioContainer.isExpanded) { if (GUILayout.Button("Add Audio Clip")) { AddAudioClip(audioContainer, audioContainedSerializedObject); // Skip drawing sound inspector after adding a new sound. addedSound = true; } else if (GUILayout.Button("Add Container")) { AddAudioContainer(audioContainer, audioContainedSerializedObject); // Skip drawing sound inspector after adding a new sound. addedSound = true; } } EditorGUILayout.EndHorizontal(); if (!addedSound && audioContainer.isExpanded) { EditorGUI.indentLevel++; DrawSoundClipInspector(audioContainer, audioContainedSerializedObject); EditorGUI.indentLevel--; } audioContainedSerializedObject.ApplyModifiedProperties(); wasRemoved = false; }