AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
UAudioManager.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using System.Collections.Generic;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity
9 {
15  public partial class UAudioManager : UAudioManagerBase<AudioEvent, AudioEventBank>
16  {
17  [Tooltip("The maximum number of AudioEvents that can be played at once. Zero (0) indicates there is no limit.")]
18  [SerializeField]
19  private int globalEventInstanceLimit = 0;
20 
21  [Tooltip("The desired behavior when the instance limit is reached.")]
22  [SerializeField]
23  private AudioEventInstanceBehavior globalInstanceBehavior = AudioEventInstanceBehavior.KillOldest;
24 
31  public Func<GameObject, GameObject> AudioEmitterTransform { get; set; }
32 
36  private Dictionary<string, AudioEvent> eventsDictionary;
37 
38  private static UAudioManager instance;
39  public static UAudioManager Instance
40  {
41  get { return instance ?? (instance = FindObjectOfType<UAudioManager>()); }
42  }
43 
44  protected new void Awake()
45  {
46  base.Awake();
47 
48  CreateEventsDictionary();
49  }
50 
56  public void PlayEvent(string eventName)
57  {
58  PlayEvent(eventName, gameObject);
59  }
60 
67  public void PlayEvent(string eventName, GameObject emitter, string messageOnAudioEnd = null)
68  {
69  PlayEvent(eventName, emitter, null, null, messageOnAudioEnd);
70  }
71 
78  public void PlayEvent(string eventName, AudioSource primarySource, AudioSource secondarySource = null)
79  {
80  PlayEvent(eventName, primarySource.gameObject, primarySource, secondarySource);
81  }
82 
91  private void PlayEvent(string eventName, GameObject emitter, AudioSource primarySource, AudioSource secondarySource, string messageOnAudioEnd = null)
92  {
93  if (!CanPlayNewEvent())
94  {
95  return;
96  }
97 
98  emitter = ApplyAudioEmitterTransform(emitter);
99 
100  if (emitter == null)
101  {
102  //if emitter is null, use the uAudioManager GameObject(2dSound)
103  emitter = gameObject;
104  }
105 
106  if (string.IsNullOrEmpty(eventName))
107  {
108  Debug.LogWarning("Audio Event string is null or empty!");
109  return;
110  }
111 
112  AudioEvent currentEvent;
113 
114  if (!eventsDictionary.TryGetValue(eventName, out currentEvent))
115  {
116  Debug.LogFormat("Could not find event \"{0}\"", eventName);
117  return;
118  }
119 
120  // If the instance limit has been reached...
121  if (currentEvent.InstanceLimit != 0 && GetInstances(eventName) >= currentEvent.InstanceLimit)
122  {
123  if (currentEvent.AudioEventInstanceBehavior == AudioEventInstanceBehavior.KillNewest)
124  {
125  // Do not play the event.
126  Debug.LogFormat(this, "Instance limit reached, not playing event \"{0}\"", eventName);
127  return;
128  }
129  else
130  {
131  // Top the oldest instance of this event.
132  KillOldestInstance(eventName);
133  }
134  }
135 
136  if (primarySource == null)
137  {
138  primarySource = GetUnusedAudioSource(emitter);
139  }
140 
141  if (currentEvent.IsContinuous() && secondarySource == null)
142  {
143  secondarySource = GetUnusedAudioSource(emitter);
144  }
145 
146  PlayEvent(currentEvent, emitter, primarySource, secondarySource, messageOnAudioEnd);
147  }
148 
157  private void PlayEvent(AudioEvent audioEvent,
158  GameObject emitter,
159  AudioSource primarySource,
160  AudioSource secondarySource,
161  string messageOnAudioEnd = null)
162  {
163  ActiveEvent tempEvent = new ActiveEvent(audioEvent, emitter, primarySource, secondarySource, messageOnAudioEnd);
164 
165  // The base class owns this event once we pass it to PlayContainer, and may dispose it if it cannot be played.
166  PlayContainer(tempEvent);
167  }
168 
175  public void StopEventsOnGameObject(string eventName, GameObject gameObjectToStop, float fadeOutTime = 0f)
176  {
177  for (int i = ActiveEvents.Count - 1; i >= 0; i--)
178  {
179  ActiveEvent activeEvent = ActiveEvents[i];
180 
181  if (activeEvent.AudioEmitter == gameObjectToStop)
182  {
183  StopEvent(activeEvent.AudioEvent.Name, gameObjectToStop, fadeOutTime);
184  }
185  }
186  }
187 
188 
194  public void StopAllEvents(string eventName, GameObject emitter = null, float fadeOutTime = 0f)
195  {
196 
197  for (int i = ActiveEvents.Count - 1; i >= 0; i--)
198  {
199  ActiveEvent activeEvent = ActiveEvents[i];
200 
201  if (activeEvent.AudioEvent.Name == eventName)
202  {
203  if (fadeOutTime > 0)
204  {
205  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, fadeOutTime));
206  }
207  else
208  {
209  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, activeEvent.AudioEvent.FadeOutTime));
210  }
211  }
212  }
213  }
214 
219  public void StopAll(GameObject emitter = null, float fadeOutTime = 0f)
220  {
221  foreach (ActiveEvent activeEvent in ActiveEvents)
222  {
223  if (fadeOutTime > 0)
224  {
225  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, fadeOutTime));
226  }
227  else
228  {
229  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, activeEvent.AudioEvent.FadeOutTime));
230  }
231  }
232  }
233 
234 
235 
242  public void StopEvent(string eventName, GameObject emitter = null, float fadeOutTime = 0f)
243  {
244  emitter = ApplyAudioEmitterTransform(emitter);
245  if (emitter == null)
246  {
247  //if emitter is null, use the uaudiomanager GameObject (2dsound)
248  emitter = gameObject;
249  }
250 
251  for (int i = ActiveEvents.Count - 1; i >= 0; i--)
252  {
253  ActiveEvent activeEvent = ActiveEvents[i];
254 
255  if (activeEvent.AudioEvent.Name == eventName && activeEvent.AudioEmitter == emitter)
256  {
257  //if there's no fade specified, use the fade stored in the event
258  if (fadeOutTime > 0f)
259  {
260  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, fadeOutTime));
261  }
262  else
263  {
264  StartCoroutine(StopEventWithFadeCoroutine(activeEvent, ActiveEvents[i].AudioEvent.FadeOutTime));
265 
266  }
267  }
268  }
269  }
270 
276  public void SetPitch(string eventName, float newPitch)
277  {
278  if (newPitch <= 0 || newPitch > 3)
279  {
280  Debug.LogErrorFormat(this, "Invalid pitch {0} set for event \"{1}\"", newPitch, eventName);
281  return;
282  }
283 
284  for (int i = ActiveEvents.Count - 1; i >= 0; i--)
285  {
286  ActiveEvent activeEvent = ActiveEvents[i];
287  if (activeEvent.AudioEvent.Name == eventName)
288  {
289  activeEvent.SetPitch(newPitch);
290  }
291  }
292  }
293 
299  public void SetLoopingContainerFrequency(string eventName, float newLoopTime)
300  {
301  AudioEvent currentEvent;
302 
303  if (!eventsDictionary.TryGetValue(eventName, out currentEvent))
304  {
305  Debug.LogErrorFormat(this, "Could not find event \"{0}\"", eventName);
306  return;
307  }
308 
309  if (newLoopTime <= 0)
310  {
311  Debug.LogErrorFormat(this, "Invalid loop time set for event \"{0}\"", eventName);
312  return;
313  }
314 
315  currentEvent.Container.LoopTime = newLoopTime;
316  }
317 
324  public void ModulateVolume(string eventName, GameObject emitter, float volume)
325  {
326  emitter = ApplyAudioEmitterTransform(emitter);
327 
328  if (emitter == null)
329  {
330  return;
331  }
332 
333  for (int i = 0; i < ActiveEvents.Count; i++)
334  {
335  ActiveEvent activeEvent = ActiveEvents[i];
336 
337  if (ActiveEvents[i].AudioEvent.Name == eventName && ActiveEvents[i].AudioEmitter == emitter)
338  {
339  activeEvent.VolDest = volume;
340  activeEvent.AltVolDest = volume;
341  activeEvent.CurrentFade = 0;
342  }
343  }
344  }
345 
352  private AudioSource GetUnusedAudioSource(GameObject emitter, ActiveEvent currentEvent = null)
353  {
354  // Get or create valid AudioSource.
355  AudioSourcesReference sourcesReference = emitter.GetComponent<AudioSourcesReference>();
356  if (sourcesReference != null)
357  {
358  List<AudioSource> sources = sourcesReference.AudioSources;
359  for (int s = 0; s < sources.Count; s++)
360  {
361  if (!sources[s].isPlaying && !sources[s].enabled)
362  {
363  if (currentEvent == null)
364  {
365  return sources[s];
366  }
367  else if (sources[s] != currentEvent.PrimarySource)
368  {
369  return sources[s];
370  }
371  }
372  }
373  }
374  else
375  {
376  sourcesReference = emitter.AddComponent<AudioSourcesReference>();
377  }
378 
379  return sourcesReference.AddNewAudioSource();
380  }
381 
388  private bool CanPlayNewEvent()
389  {
390  if (globalEventInstanceLimit == 0 || ActiveEvents.Count < globalEventInstanceLimit)
391  {
392  return true;
393  }
394  else
395  {
396  if (globalInstanceBehavior == AudioEventInstanceBehavior.KillOldest)
397  {
398  StopEvent(ActiveEvents[0]);
399  return true;
400  }
401  else
402  {
403  return false;
404  }
405  }
406  }
407 
412  private void KillOldestInstance(string eventName)
413  {
414  for (int i = 0; i < ActiveEvents.Count; i++)
415  {
416  ActiveEvent tempEvent = ActiveEvents[i];
417 
418  if (tempEvent.AudioEvent.Name == eventName)
419  {
420  StopEvent(tempEvent);
421  return;
422  }
423  }
424  }
425 
433  private GameObject ApplyAudioEmitterTransform(GameObject emitter)
434  {
435  if (AudioEmitterTransform != null)
436  {
437  emitter = AudioEmitterTransform(emitter);
438  }
439 
440  return emitter;
441  }
442 
446  protected override void BanksChanged()
447  {
448  CreateEventsDictionary();
449  }
450 
454  private void CreateEventsDictionary()
455  {
456  int numEvents = 0;
457  for(int i=0; i<LoadedBanks.Count; i++)
458  {
459  numEvents += LoadedBanks[i].Events.Length;
460  }
461 
462  eventsDictionary = new Dictionary<string, AudioEvent>(numEvents);
463 
464  for (int b = 0; b < LoadedBanks.Count; b++)
465  {
466  for (int i = 0; i < LoadedBanks[b].Events.Length; i++)
467  {
468  AudioEvent tempEvent = LoadedBanks[b].Events[i];
469  try
470  {
471  eventsDictionary.Add(tempEvent.Name, tempEvent);
472  }
473  catch (ArgumentException)
474  {
475  Debug.LogErrorFormat("Name {0} already exists in Event dictionary", tempEvent.Name);
476  }
477  }
478  }
479  }
480  }
481 }
void ModulateVolume(string eventName, GameObject emitter, float volume)
Sets the volume for active AudioEvents.
override void BanksChanged()
Update the dictionary of available audio events.
UAudioManagerBase provides the base functionality for UAudioManager classes.
void StopAllEvents(string eventName, GameObject emitter=null, float fadeOutTime=0f)
Stops all events by name.
The AudioEvent class is the main component of UAudioManager and contains settings and a container for...
Definition: AudioEvent.cs:54
void PlayEvent(string eventName, GameObject emitter, string messageOnAudioEnd=null)
Plays an AudioEvent.
The AudioSourcesReference class encapsulates a cache of references to audio source components on a gi...
void PlayEvent(string eventName)
Plays an AudioEvent.
Currently active AudioEvents along with their AudioSource components for instance limiting events ...
Definition: ActiveEvent.cs:12
AudioEventInstanceBehavior
Defines the behavior for when the instance limit is reached for a particular event.
Definition: AudioEvent.cs:25
void StopAll(GameObject emitter=null, float fadeOutTime=0f)
Stops all.
void PlayEvent(string eventName, AudioSource primarySource, AudioSource secondarySource=null)
Plays an AudioEvent.
void StopEventsOnGameObject(string eventName, GameObject gameObjectToStop, float fadeOutTime=0f)
Stop event by gameObject.
void SetLoopingContainerFrequency(string eventName, float newLoopTime)
Sets an AudioEvent&#39;s container loop frequency
void StopEvent(string eventName, GameObject emitter=null, float fadeOutTime=0f)
Stops an AudioEvent.
void SetPitch(string eventName, float newPitch)
Sets the pitch value on active AudioEvents.
The UAudioManager class is a singleton that provides organization and control of an application&#39;s Aud...
void SetPitch(float newPitch)
Sets the pitch value for the primary source.
Definition: ActiveEvent.cs:222