//Draw an audio source inline with our event editor //Used for showing/editing audio source proxies void DrawProxy(AudioEvent ev) { var source = EventToSourceMap[ev]; var editor = Editor.CreateEditor(source); editor.OnInspectorGUI(); Object.DestroyImmediate(editor); }
//Convert some bools into flags, and back again void DrawAudioEventOptionsMask(AudioEvent audioEvent) { var names = new string[] { "Loop", "Stop playing immediately when source dies", "Keep looping when source dies", "Do not Track source movement" }; int mask = 0; if (audioEvent.Loop) { mask |= 1 << 0; } if (audioEvent.StopWhenSourceDies) { mask |= 1 << 1; } if (audioEvent.KeepLoopingWhenSourceDies) { mask |= 1 << 2; } if (audioEvent.DoNotTrackSourceMovement) { mask |= 1 << 3; } mask = EditorGUILayout.MaskField("", mask, names, GUILayout.MinWidth(100)); audioEvent.Loop = (mask & (1 << 0)) > 0; audioEvent.StopWhenSourceDies = (mask & 1 << 1) > 0; audioEvent.KeepLoopingWhenSourceDies = (mask & 1 << 2) > 0; audioEvent.DoNotTrackSourceMovement = (mask & 1 << 3) > 0; }
//Used by the AudioEventEditor 'Clone' //Duplicates an AudioEvent. //TODO - Do this via reflection. public AudioEvent Clone() { var ev = new AudioEvent(); ev.RandomWeight = RandomWeight; ev.Volume = Volume; ev.AudioClip = AudioClip; ev.EventName = EventName; ev.Loop = Loop; ev.StopWhenSourceDies = StopWhenSourceDies; ev.Priority = Priority; ev.GroupID = GroupID; ev.KeepLoopingWhenSourceDies = KeepLoopingWhenSourceDies; ev.DoNotTrackSourceMovement = DoNotTrackSourceMovement; ev.BypassEffects = BypassEffects; ev.BypassListenerEffects = BypassListenerEffects; ev.BypassReverbZones = BypassReverbZones; ev.DopplerLevel = DopplerLevel; ev.MaxDistance = MaxDistance; ev.MinDistance = MinDistance; ev.Mute = Mute; ev.OutputAudioMixerGroup = OutputAudioMixerGroup; ev.PanStereo = PanStereo; ev.Pitch = Pitch; ev.RolloffMode = RolloffMode; ev.CustomRolloffCurve = CustomRolloffCurve; ev.SpatialBlend = SpatialBlend; ev.ReverbZoneMix = ReverbZoneMix; ev.Spatialize = Spatialize; return(ev); }
// Play an audio event. // // audioEventName is an audio event name from an audio bank // Event names are made of segments, ordered right to left in increasing order of specialisation // Eg. 'FOOTSTEP', 'GRAVEL, FOOTSTEP', 'WOLF, GRAVEL, FOOTSTEP' // The engine will strip the specialisations off, left to right, until it finds a match // Use MakeEvent to construct these. // // source is a GameObject to attach to - if null, uses a global emitter, useful for 2D sounds // // If successful, returns an AudioEmitter attached to a new GameObject public AudioEmitter Play(string audioEventName, GameObject source = null) { if (string.IsNullOrEmpty(audioEventName)) { return(null); } //If we're not attaching audio to another game object, assume this is a 2D sound and attach it to this manager if (source == null) { source = this.gameObject; } if (LogAllEvents) { Debug.Log("AudioManager: Trying event '" + audioEventName + "'" + (source != null ? (" (source = '" + source.name + "')") : "")); } // Look up an event from this trigger AudioEvent audioEvent = GetSoundForEvent(audioEventName); if (audioEvent != null && audioEvent.AudioClip != null) { var emitter = AudioEmitter.Create(source.transform, audioEvent); emitter.Play(); ActiveEmitters.AddLast(emitter); return(emitter); } else if (LogMissingEvents) { Debug.Log("$$$$Missing sound event '" + audioEventName + "' (source = '" + source.name + "')"); } return(null); }
//Used by the AudioEventEditor 'Clone' //Duplicates an AudioEvent. //TODO - Do this via reflection. public AudioEvent Clone() { var ev = new AudioEvent(); ev.RandomWeight = RandomWeight; ev.Volume = Volume; ev.AudioClip = AudioClip; ev.EventName = EventName; ev.Loop = Loop; ev.StopWhenSourceDies = StopWhenSourceDies; ev.Priority = Priority; ev.GroupID = GroupID; ev.KeepLoopingWhenSourceDies = KeepLoopingWhenSourceDies; ev.DoNotTrackSourceMovement = DoNotTrackSourceMovement; ev.BypassEffects = BypassEffects; ev.BypassListenerEffects = BypassListenerEffects; ev.BypassReverbZones = BypassReverbZones; ev.DopplerLevel = DopplerLevel; ev.MaxDistance = MaxDistance; ev.MinDistance = MinDistance; ev.Mute = Mute; ev.OutputAudioMixerGroup = OutputAudioMixerGroup; ev.PanStereo = PanStereo; ev.Pitch = Pitch; ev.RolloffMode = RolloffMode; ev.CustomRolloffCurve = CustomRolloffCurve; ev.SpatialBlend = SpatialBlend; ev.ReverbZoneMix = ReverbZoneMix; ev.Spatialize = Spatialize; return ev; }
//If an audio source proxy doesn't exist for this event, create one //Regardless, return the proxy AudioSource GetOrCreateAudioSourceProxy(AudioEvent ev) { AudioSource audioSource = null; EventToSourceMap.TryGetValue(ev, out audioSource); if(audioSource==null) { audioSource = AudioSourceProxyGO.AddComponent<AudioSource>(); EventToSourceMap[ev] = audioSource; } return audioSource; }
public static AudioEmitter Create(Transform attachedTo, AudioEvent ev) { GameObject go = new GameObject("AudioEmitter"); AudioEmitter emitter = go.AddComponent<AudioEmitter>(); emitter._Source = go.AddComponent<AudioSource>(); go.transform.parent = AudioManager.Instance.gameObject.transform; go.transform.position = attachedTo.position; emitter.AttachedTo = attachedTo; emitter.AudioSoundEvent = ev; ev.TransferToAudioSource(emitter._Source); return emitter; }
public static AudioEmitter Create(Transform attachedTo, AudioEvent ev) { GameObject go = new GameObject("AudioEmitter"); AudioEmitter emitter = go.AddComponent <AudioEmitter>(); emitter._Source = go.AddComponent <AudioSource>(); go.transform.parent = AudioManager.Instance.gameObject.transform; go.transform.position = attachedTo.position; emitter.AttachedTo = attachedTo; emitter.AudioSoundEvent = ev; ev.TransferToAudioSource(emitter._Source); return(emitter); }
//Play an audio event. //If onlythisOne is false, it chooses a random weighted event from the group void PlayAudio(int index, bool onlyThisOne) { if (Application.isPlaying) { return; } if (AudioPlayer) { AudioPlayer.GetComponent <AudioSource>().Stop(); } else { CreateAudioPlayer(); } AudioEvent audioEvent = null; if (onlyThisOne) { audioEvent = Bank.AudioEvents[index]; } else { var audioEventName = Bank.AudioEvents[index].EventName; List <AudioEvent> audioEvents = new List <AudioEvent>(); foreach (var evt in Bank.AudioEvents) { if (evt.EventName == audioEventName) { audioEvents.Add(evt); } } audioEvent = AudioManager.GetRandomEvent(audioEvents); } if (audioEvent != null) { var source = AudioPlayer.GetComponent <AudioSource>(); audioEvent.TransferToAudioSource(source); source.Play(); } }
//Draw a single audio event public void DisplayLine(int audioEventIndex) { AudioEvent audioEvent = Bank.AudioEvents[audioEventIndex]; //Visually seperate items from different groups if (audioEvent.EventName != LastEventName) { LastEventName = audioEvent.EventName; EditorGUILayout.Space(); } //Draw all these controls on a single line EditorGUILayout.BeginHorizontal(); //Drag handle Rect dropArea = GUILayoutUtility.GetRect(40, 20); dropArea.width = 30; bool topLevelEvent = IsEventIndexTopOfGroup(audioEventIndex); if (topLevelEvent) { GUI.Box(dropArea, ""); DropAreas.Add(new DropArea(audioEventIndex, dropArea)); } //Show all the summary details and buttons EditorGUI.BeginChangeCheck(); //Event name EditorGUIUtility.labelWidth = 20; EditorGUIUtility.fieldWidth = 100; GUI.SetNextControlName("TextField"); audioEvent.EventName = EditorGUILayout.TextField(audioEvent.EventName); //If we've changed the event name, make sure we update any adjacency issues. if (Event.current.isKey && Event.current.keyCode == KeyCode.Return && GUI.GetNameOfFocusedControl() == "TextField") { CheckEventAdjacency = true; } //The audio clip EditorGUIUtility.labelWidth = 30; EditorGUIUtility.fieldWidth = 100; audioEvent.AudioClip = (AudioClip)EditorGUILayout.ObjectField("", audioEvent.AudioClip, typeof(AudioClip), false, GUILayout.MinWidth(60)); //The random weight control EditorGUIUtility.labelWidth = 25; EditorGUIUtility.fieldWidth = 35; audioEvent.RandomWeight = EditorGUILayout.FloatField(new GUIContent("Wgt", "Weight"), audioEvent.RandomWeight, GUILayout.MaxWidth(60)); //Show the loop/lifetime mask DrawAudioEventOptionsMask(audioEvent); //Details foldout bool foldedOut = false; if (FoldedOut.ContainsKey(audioEvent.GetHashCode())) { foldedOut = FoldedOut[audioEvent.GetHashCode()]; } if (GUILayout.Button(new GUIContent("A", "Audio source settings"), GUILayout.MaxWidth(PlayButtonWidth))) { foldedOut = !foldedOut; } FoldedOut[audioEvent.GetHashCode()] = foldedOut; //Playback controls if (GUILayout.Button(new GUIContent("T", "Play this audio event"), GUILayout.MaxWidth(PlayButtonWidth))) // if (GUILayout.Button(new GUIContent("T", "Play this audio event"), GUILayout.ExpandWidth(false))) { PlayAudio(audioEventIndex, true); } if (GUILayout.Button(new GUIContent("R", "Play random event in this group"), GUILayout.MaxWidth(PlayButtonWidth))) { PlayAudio(audioEventIndex, false); } //Clone an item? if (GUILayout.Button(new GUIContent("C", "Clone this event"), GUILayout.MaxWidth(PlayButtonWidth))) { IndexToClone = audioEventIndex; } //Delete an item? if (GUILayout.Button(new GUIContent("X", "Delete this event"), GUILayout.MaxWidth(PlayButtonWidth))) { IndexToDelete = audioEventIndex; } // GUILayout.FlexibleSpace(); //If any data was changed, transfer them to the proxy audio source if (EditorGUI.EndChangeCheck()) { audioEvent.TransferToAudioSource(GetOrCreateAudioSourceProxy(audioEvent)); } EditorGUILayout.EndHorizontal(); //If we're folded out, show the details from the proxy audio source if (foldedOut) { var source = EventToSourceMap[audioEvent]; if (source != null) { EditorGUIUtility.labelWidth = 0; EditorGUIUtility.fieldWidth = 0; EditorGUI.BeginChangeCheck(); DrawProxy(audioEvent); if (EditorGUI.EndChangeCheck()) { audioEvent.TransferFromAudioSource(source); } } } }
//Root of all gui stuff public override void OnInspectorGUI() { IndexToClone = -1; IndexToDelete = -1; DropAreas.Clear(); //Top buttons EditorGUILayout.BeginVertical(); //Add a new audio event if (GUILayout.Button("Add entry...", GUILayout.Height(TopButtonHeight))) { var newAudioEvent = new AudioEvent(); newAudioEvent.EventName = "NEWKEY_" + Bank.AudioEvents.Count; Bank.AudioEvents.Add(newAudioEvent); var source = GetOrCreateAudioSourceProxy(newAudioEvent); newAudioEvent.TransferFromAudioSource(source); } //Stop all sounds from playing if (GUILayout.Button("Stop Playback", GUILayout.Height(TopButtonHeight))) { AudioPlayer.GetComponent <AudioSource>().Stop(); } //Temporarily make our audio proxy sources visible, otherwise they are greyed out in the inspector if (AudioSourceProxyGO != null) { AudioSourceProxyGO.hideFlags = HideFlags.DontSaveInEditor; } EditorGUILayout.Space(); EditorGUILayout.EndVertical(); LastEventName = ""; // ScrollPos = EditorGUILayout.BeginScrollView(ScrollPos); EditorGUILayout.BeginVertical(); //Now display the individual events if (Bank != null) { TransferSettingsToProxies(); if (Bank.AudioEvents != null) { for (int c1 = 0; c1 < Bank.AudioEvents.Count; c1++) { DisplayLine(c1); } } } //Clean up various bits of state we've had to keep going //If we've been asked to delete something, honour that if (IndexToDelete >= 0) { Bank.AudioEvents.RemoveAt(IndexToDelete); } //If we've been asked to clone something, honour that if (IndexToClone >= 0) { var clone = Bank.AudioEvents[IndexToClone].Clone(); Bank.AudioEvents.Insert(IndexToClone, clone); } //Handle drag drop logic DoDragDrop(); // EditorGUILayout.EndScrollView(); EditorGUILayout.EndVertical(); EditorUtility.SetDirty(target); //Set the audio source proxies back to being invisible if (AudioSourceProxyGO != null) { AudioSourceProxyGO.hideFlags = HideFlags.HideAndDontSave; } //Make sure same named events are adjacent if (CheckEventAdjacency) { CheckEventAdjacency = false; CleanupNonAdjacentEvents(); GUI.FocusControl(""); } }
//Convert some bools into flags, and back again void DrawAudioEventOptionsMask(AudioEvent audioEvent) { var names = new string[] {"Loop", "Stop playing immediately when source dies", "Keep looping when source dies", "Do not Track source movement"}; int mask = 0; if(audioEvent.Loop) mask |= 1<<0; if(audioEvent.StopWhenSourceDies) mask |= 1<<1; if(audioEvent.KeepLoopingWhenSourceDies) mask |= 1<<2; if(audioEvent.DoNotTrackSourceMovement) mask |= 1<<3; mask = EditorGUILayout.MaskField("", mask, names, GUILayout.MinWidth(100)); audioEvent.Loop = (mask & (1<<0))>0; audioEvent.StopWhenSourceDies = (mask & 1<<1)>0; audioEvent.KeepLoopingWhenSourceDies = (mask & 1<<2)>0; audioEvent.DoNotTrackSourceMovement = (mask & 1<<3)>0; }
//Root of all gui stuff public override void OnInspectorGUI() { IndexToClone = -1; IndexToDelete = -1; DropAreas.Clear(); //Top buttons EditorGUILayout.BeginVertical(); //Add a new audio event if(GUILayout.Button("Add entry...", GUILayout.Height(TopButtonHeight))) { var newAudioEvent = new AudioEvent(); newAudioEvent.EventName = "NEWKEY_" + Bank.AudioEvents.Count; Bank.AudioEvents.Add(newAudioEvent); var source = GetOrCreateAudioSourceProxy(newAudioEvent); newAudioEvent.TransferFromAudioSource(source); } //Stop all sounds from playing if(GUILayout.Button("Stop Playback", GUILayout.Height(TopButtonHeight))) { AudioPlayer.GetComponent<AudioSource>().Stop(); } //Temporarily make our audio proxy sources visible, otherwise they are greyed out in the inspector if(AudioSourceProxyGO!=null) { AudioSourceProxyGO.hideFlags = HideFlags.DontSaveInEditor; } EditorGUILayout.Space(); EditorGUILayout.EndVertical(); LastEventName = ""; // ScrollPos = EditorGUILayout.BeginScrollView(ScrollPos); EditorGUILayout.BeginVertical(); //Now display the individual events if(Bank != null) { TransferSettingsToProxies(); if(Bank.AudioEvents!=null) { for(int c1=0; c1<Bank.AudioEvents.Count; c1++) { DisplayLine(c1); } } } //Clean up various bits of state we've had to keep going //If we've been asked to delete something, honour that if(IndexToDelete>=0) { Bank.AudioEvents.RemoveAt(IndexToDelete); } //If we've been asked to clone something, honour that if(IndexToClone>=0) { var clone = Bank.AudioEvents[IndexToClone].Clone(); Bank.AudioEvents.Insert(IndexToClone, clone); } //Handle drag drop logic DoDragDrop(); // EditorGUILayout.EndScrollView(); EditorGUILayout.EndVertical(); EditorUtility.SetDirty(target); //Set the audio source proxies back to being invisible if(AudioSourceProxyGO!=null) { AudioSourceProxyGO.hideFlags = HideFlags.HideAndDontSave; } //Make sure same named events are adjacent if(CheckEventAdjacency) { CheckEventAdjacency = false; CleanupNonAdjacentEvents(); GUI.FocusControl(""); } }