AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
AudioEmitter.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 {
17  [DisallowMultipleComponent]
18  [RequireComponent(typeof(AudioSource))]
19  public class AudioEmitter : MonoBehaviour
20  {
28  public static readonly float NeutralLowFrequency = 10.0f;
29 
37  public static readonly float NeutralHighFrequency = 22000.0f;
38 
47  [Tooltip("Time, in seconds, between audio influence updates. 0 indicates to update every frame.")]
48  [Range(0.0f, 1.0f)]
49  [SerializeField]
50  private float updateInterval = 0.25f;
51  public float UpdateInterval
52  {
53  get { return updateInterval; }
54  set
55  {
56  // set updateInterval and enforce the specified range
57  if (value < 0.0f)
58  {
59  updateInterval = 0.0f;
60  }
61  else if (value > 1.0f)
62  {
63  updateInterval = 1.0f;
64  }
65  else
66  {
67  updateInterval = value;
68  }
69  }
70  }
71 
79  [Tooltip("Maximum distance, in meters, to look when attempting to find the user and any influencers.")]
80  [Range(1.0f, 50.0f)]
81  [SerializeField]
82  private float maxDistance = 20.0f;
83  public float MaxDistance
84  {
85  get { return maxDistance; }
86  set
87  {
88  // set maxDistance and enforce the specified range
89  if (value < 1.0f)
90  {
91  maxDistance = 1.0f;
92  }
93  else if (value > 50.0f)
94  {
95  maxDistance = 50.0f;
96  }
97  else
98  {
99  maxDistance = value;
100  }
101  }
102  }
103 
113  [Tooltip("Maximum number of objects that will be considered when looking for influencers.")]
114  [Range(1, 25)]
115  [SerializeField]
116  private int MaxObjects = 10;
117 
121  private DateTime lastUpdate = DateTime.MinValue;
122 
126  private AudioSource audioSource;
127 
131  private float initialAudioSourceVolume;
132 
136  private RaycastHit[] hits;
137 
141  private List<IAudioInfluencer> previousInfluencers = new List<IAudioInfluencer>();
142 
147  private AudioLowPassFilter lowPassFilter;
148  private float nativeLowPassCutoffFrequency;
149  private AudioHighPassFilter highPassFilter;
150  private float nativeHighPassCutoffFrequency;
151 
152  private void Awake()
153  {
154  audioSource = gameObject.GetComponent<AudioSource>();
155  initialAudioSourceVolume = audioSource.volume;
156 
157  // Get optional filters (and initial values) that the sound designer / developer
158  // may have applied to this game object
159  lowPassFilter = gameObject.GetComponent<AudioLowPassFilter>();
160  nativeLowPassCutoffFrequency = (lowPassFilter != null) ? lowPassFilter.cutoffFrequency : NeutralHighFrequency;
161  highPassFilter = gameObject.GetComponent<AudioHighPassFilter>();
162  nativeHighPassCutoffFrequency = (highPassFilter != null) ? highPassFilter.cutoffFrequency : NeutralLowFrequency;
163 
164  // Preallocate the array that will be used to collect RaycastHit structures.
165  hits = new RaycastHit[MaxObjects];
166  }
167 
168  private void Update()
169  {
170  DateTime now = DateTime.Now;
171 
172  // Audio influences are not updated every frame.
173  if ((UpdateInterval * 1000.0f) <= (now - lastUpdate).Milliseconds)
174  {
175  audioSource.volume = initialAudioSourceVolume;
176 
177  // Get the audio influencers that should apply to the audio source.
178  List<IAudioInfluencer> influencers = GetInfluencers();
179  foreach (IAudioInfluencer influencer in influencers)
180  {
181  // Apply the influencer's effect.
182  influencer.ApplyEffect(gameObject);
183  }
184 
185  // Find and remove the audio influencers that are to be removed from the audio source.
186  List<IAudioInfluencer> influencersToRemove = new List<IAudioInfluencer>();
187  foreach (IAudioInfluencer prev in previousInfluencers)
188  {
189  MonoBehaviour mbPrev = prev as MonoBehaviour;
190 
191  // Remove influencers that are no longer in line of sight
192  // OR
193  // Have been disabled
194  if (!influencers.Contains(prev) ||
195  ((mbPrev != null) && !mbPrev.isActiveAndEnabled))
196  {
197  influencersToRemove.Add(prev);
198  }
199  }
200  RemoveInfluencers(influencersToRemove);
201 
202  previousInfluencers = influencers;
203  lastUpdate = now;
204  }
205  }
206 
211  private void RemoveInfluencers(List<IAudioInfluencer> influencers)
212  {
213  foreach (IAudioInfluencer influencer in influencers)
214  {
215  influencer.RemoveEffect(gameObject);
216  }
217  }
218 
223  private List<IAudioInfluencer> GetInfluencers()
224  {
225  List<IAudioInfluencer> influencers = new List<IAudioInfluencer>();
226  Transform cameraTransform = CameraCache.Main.transform;
227 
228  // Influencers take effect only when between the emitter and the user.
229  // Perform a raycast from the user toward the object.
230  Vector3 direction = (gameObject.transform.position - cameraTransform.position).normalized;
231  float distance = Vector3.Distance(cameraTransform.position, gameObject.transform.position);
232 
233  int count = Physics.RaycastNonAlloc(cameraTransform.position,
234  direction,
235  hits,
236  distance,
237  Physics.DefaultRaycastLayers,
238  QueryTriggerInteraction.Ignore);
239 
240  for (int i = 0; i < count; i++)
241  {
242  IAudioInfluencer influencer = hits[i].collider.gameObject.GetComponentInParent<IAudioInfluencer>();
243  if (influencer != null)
244  {
245  influencers.Add(influencer);
246  }
247  }
248 
249  return influencers;
250  }
251 
259  {
260  return nativeLowPassCutoffFrequency;
261  }
262 
269  public void SetNativeLowPassCutoffFrequency(float frequency)
270  {
271  nativeLowPassCutoffFrequency = frequency;
272  }
273 
281  {
282  return nativeHighPassCutoffFrequency;
283  }
284 
291  public void SetNativeHighPassCutoffFrequency(float frequency)
292  {
293  nativeHighPassCutoffFrequency = frequency;
294  }
295  }
296 }
Interface that is implemented by any class that wishes to influence how an audio source sounds...
void SetNativeLowPassCutoffFrequency(float frequency)
Sets the cached native cutoff frequency of the attached low pass filter.
float GetNativeHighPassCutoffFrequency()
Gets the native cutoff frequency of the attached high pass filter.
Class which supports IAudioInfluencers being used with audio sources.
Definition: AudioEmitter.cs:19
void RemoveEffect(GameObject soundEmittingObject, AudioSource audioSource)
Removes a previously applied audio effect.
void SetNativeHighPassCutoffFrequency(float frequency)
Sets the cached native cutoff frequency of the attached high pass filter.
void ApplyEffect(GameObject soundEmittingObject, AudioSource audioSource)
Applies an audio effect.
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
float GetNativeLowPassCutoffFrequency()
Gets the native cutoff frequency of the attached low pass filter.
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20