Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

787 lines
25 KiB

  1. using UnityEngine;
  2. using UnityEngine.Audio;
  3. namespace OVR
  4. {
  5. //-------------------------------------------------------------------------
  6. // Types
  7. //-------------------------------------------------------------------------
  8. public enum EmitterChannel {
  9. None = -1,
  10. Reserved = 0, // plays on the single reserved emitter
  11. Any // queues to the next available emitter
  12. }
  13. [System.Serializable]
  14. public class MixerSnapshot {
  15. public AudioMixerSnapshot snapshot = null;
  16. public float transitionTime = 0.25f;
  17. }
  18. /*
  19. -----------------------
  20. GameManager Sound Routines
  21. -----------------------
  22. */
  23. public partial class AudioManager : MonoBehaviour {
  24. public enum Fade {
  25. In,
  26. Out
  27. }
  28. private float audioMaxFallOffDistanceSqr = 25.0f * 25.0f; // past this distance, sounds are ignored for the local player
  29. private SoundEmitter[] soundEmitters = null; // pool of sound emitters to play sounds through
  30. private FastList<SoundEmitter> playingEmitters = new FastList<SoundEmitter>();
  31. private FastList<SoundEmitter> nextFreeEmitters = new FastList<SoundEmitter>();
  32. private MixerSnapshot currentSnapshot = null;
  33. static private GameObject soundEmitterParent = null; // parent object for the sound emitters
  34. static private Transform staticListenerPosition = null; // play position for regular 2D sounds
  35. static private bool showPlayingEmitterCount = false;
  36. static private bool forceShowEmitterCount = false;
  37. static private bool soundEnabled = true;
  38. static public bool SoundEnabled { get { return soundEnabled; } }
  39. static readonly AnimationCurve defaultReverbZoneMix = new AnimationCurve( new Keyframe[2] { new Keyframe( 0f, 1.0f ), new Keyframe( 1f, 1f ) } );
  40. /*
  41. -----------------------
  42. InitializeSoundSystem()
  43. initialize persistent sound emitter objects that live across scene loads
  44. -----------------------
  45. */
  46. void InitializeSoundSystem() {
  47. int bufferLength = 960;
  48. int numBuffers = 4;
  49. AudioSettings.GetDSPBufferSize( out bufferLength, out numBuffers );
  50. if ( Application.isPlaying ) {
  51. Debug.Log( "[AudioManager] Audio Sample Rate: " + AudioSettings.outputSampleRate );
  52. Debug.Log( "[AudioManager] Audio Buffer Length: " + bufferLength + " Size: " + numBuffers );
  53. }
  54. // find the audio listener for playing regular 2D sounds
  55. AudioListener audioListenerObject = GameObject.FindObjectOfType<AudioListener>() as AudioListener;
  56. if ( audioListenerObject == null ) {
  57. Debug.LogError( "[AudioManager] Missing AudioListener object! Add one to the scene." );
  58. } else {
  59. staticListenerPosition = audioListenerObject.transform;
  60. }
  61. // we allocate maxSoundEmitters + reserved channels
  62. soundEmitters = new SoundEmitter[maxSoundEmitters+(int)EmitterChannel.Any];
  63. // see if the sound emitters have already been created, if so, nuke it, it shouldn't exist in the scene upon load
  64. soundEmitterParent = GameObject.Find( "__SoundEmitters__" );
  65. if ( soundEmitterParent != null ) {
  66. // delete any sound emitters hanging around
  67. Destroy( soundEmitterParent );
  68. }
  69. // create them all
  70. soundEmitterParent = new GameObject( "__SoundEmitters__" );
  71. for ( int i = 0; i < maxSoundEmitters + (int)EmitterChannel.Any; i++ ) {
  72. GameObject emitterObject = new GameObject( "SoundEmitter_" + i );
  73. emitterObject.transform.parent = soundEmitterParent.transform;
  74. emitterObject.transform.position = Vector3.zero;
  75. // don't ever save this to the scene
  76. emitterObject.hideFlags = HideFlags.DontSaveInEditor;
  77. // add the sound emitter components
  78. soundEmitters[i] = emitterObject.AddComponent<SoundEmitter>();
  79. soundEmitters[i].SetDefaultParent( soundEmitterParent.transform );
  80. soundEmitters[i].SetChannel( i );
  81. soundEmitters[i].Stop();
  82. // save off the original index
  83. soundEmitters[i].originalIdx = i;
  84. }
  85. // reset the free emitter lists
  86. ResetFreeEmitters();
  87. soundEmitterParent.hideFlags = HideFlags.DontSaveInEditor;
  88. audioMaxFallOffDistanceSqr = audioMaxFallOffDistance * audioMaxFallOffDistance;
  89. }
  90. /*
  91. -----------------------
  92. UpdateFreeEmitters()
  93. -----------------------
  94. */
  95. void UpdateFreeEmitters() {
  96. if ( verboseLogging ) {
  97. if ( Input.GetKeyDown( KeyCode.A ) ) {
  98. forceShowEmitterCount = !forceShowEmitterCount;
  99. }
  100. if ( forceShowEmitterCount ) {
  101. showPlayingEmitterCount = true;
  102. }
  103. }
  104. // display playing emitter count when the sound system is overwhelmed
  105. int total = 0, veryLow = 0, low = 0, def = 0, high = 0, veryHigh = 0;
  106. // find emitters that are done playing and add them to the nextFreeEmitters list
  107. for ( int i = 0; i < playingEmitters.size; ) {
  108. if ( playingEmitters[i] == null ) {
  109. Debug.LogError( "[AudioManager] ERROR: playingEmitters list had a null emitter! Something nuked a sound emitter!!!" );
  110. playingEmitters.RemoveAtFast( i );
  111. return;
  112. }
  113. if ( !playingEmitters[i].IsPlaying() ) {
  114. // add to the free list and remove from the playing list
  115. if ( verboseLogging ) {
  116. if ( nextFreeEmitters.Contains( playingEmitters[i] ) ) {
  117. Debug.LogError( "[AudioManager] ERROR: playing sound emitter already in the free emitters list!" );
  118. }
  119. }
  120. playingEmitters[i].Stop();
  121. nextFreeEmitters.Add( playingEmitters[i] );
  122. playingEmitters.RemoveAtFast( i );
  123. continue;
  124. }
  125. // debugging/profiling
  126. if ( verboseLogging && showPlayingEmitterCount ) {
  127. total++;
  128. switch ( playingEmitters[i].priority ) {
  129. case SoundPriority.VeryLow: veryLow++; break;
  130. case SoundPriority.Low: low++; break;
  131. case SoundPriority.Default: def++; break;
  132. case SoundPriority.High: high++; break;
  133. case SoundPriority.VeryHigh: veryHigh++; break;
  134. }
  135. }
  136. i++;
  137. }
  138. if ( verboseLogging && showPlayingEmitterCount ) {
  139. Debug.LogWarning( string.Format( "[AudioManager] Playing sounds: Total {0} | VeryLow {1} | Low {2} | Default {3} | High {4} | VeryHigh {5} | Free {6}", Fmt( total ), Fmt( veryLow ), Fmt( low ), Fmt( def ), Fmt( high ), Fmt( veryHigh ), FmtFree( nextFreeEmitters.Count ) ) );
  140. showPlayingEmitterCount = false;
  141. }
  142. }
  143. /*
  144. -----------------------
  145. Fmt()
  146. -----------------------
  147. */
  148. string Fmt( int count ) {
  149. float t = count / (float)theAudioManager.maxSoundEmitters;
  150. if ( t < 0.5f ) {
  151. return "<color=green>" + count.ToString() + "</color>";
  152. } else if ( t < 0.7 ) {
  153. return "<color=yellow>" + count.ToString() + "</color>";
  154. } else {
  155. return "<color=red>" + count.ToString() + "</color>";
  156. }
  157. }
  158. /*
  159. -----------------------
  160. FmtFree()
  161. -----------------------
  162. */
  163. string FmtFree( int count ) {
  164. float t = count / (float)theAudioManager.maxSoundEmitters;
  165. if ( t < 0.2f ) {
  166. return "<color=red>" + count.ToString() + "</color>";
  167. } else if ( t < 0.3 ) {
  168. return "<color=yellow>" + count.ToString() + "</color>";
  169. } else {
  170. return "<color=green>" + count.ToString() + "</color>";
  171. }
  172. }
  173. /*
  174. -----------------------
  175. OnPreSceneLoad()
  176. -----------------------
  177. */
  178. void OnPreSceneLoad() {
  179. // move any attached sounds back to the sound emitters parent before changing levels so they don't get destroyed
  180. Debug.Log( "[AudioManager] OnPreSceneLoad cleanup" );
  181. for ( int i = 0; i < soundEmitters.Length; i++ ) {
  182. soundEmitters[i].Stop();
  183. soundEmitters[i].ResetParent( soundEmitterParent.transform );
  184. }
  185. // reset our emitter lists
  186. ResetFreeEmitters();
  187. }
  188. /*
  189. -----------------------
  190. ResetFreeEmitters()
  191. -----------------------
  192. */
  193. void ResetFreeEmitters() {
  194. nextFreeEmitters.Clear();
  195. playingEmitters.Clear();
  196. for ( int i = (int)EmitterChannel.Any; i < soundEmitters.Length; i++ ) {
  197. nextFreeEmitters.Add( soundEmitters[i] );
  198. }
  199. }
  200. /*
  201. -----------------------
  202. FadeOutSoundChannel()
  203. utility function to fade out a playing sound channel
  204. -----------------------
  205. */
  206. static public void FadeOutSoundChannel( int channel, float delaySecs, float fadeTime ) {
  207. theAudioManager.soundEmitters[channel].FadeOutDelayed( delaySecs, fadeTime );
  208. }
  209. /*
  210. -----------------------
  211. StopSound()
  212. -----------------------
  213. */
  214. static public bool StopSound( int idx, bool fadeOut = true, bool stopReserved = false ) {
  215. if ( !stopReserved && ( idx == (int)EmitterChannel.Reserved ) ) {
  216. return false;
  217. }
  218. if ( !fadeOut ) {
  219. theAudioManager.soundEmitters[idx].Stop();
  220. }
  221. else {
  222. theAudioManager.soundEmitters[idx].FadeOut( theAudioManager.soundFxFadeSecs );
  223. }
  224. return true;
  225. }
  226. /*
  227. -----------------------
  228. FadeInSound()
  229. -----------------------
  230. */
  231. public static void FadeInSound( int idx, float fadeTime, float volume ) {
  232. theAudioManager.soundEmitters[idx].FadeIn( fadeTime, volume );
  233. }
  234. /*
  235. -----------------------
  236. FadeInSound()
  237. -----------------------
  238. */
  239. public static void FadeInSound( int idx, float fadeTime ) {
  240. theAudioManager.soundEmitters[idx].FadeIn( fadeTime );
  241. }
  242. /*
  243. -----------------------
  244. FadeOutSound()
  245. -----------------------
  246. */
  247. public static void FadeOutSound( int idx, float fadeTime ) {
  248. theAudioManager.soundEmitters[idx].FadeOut( fadeTime );
  249. }
  250. /*
  251. -----------------------
  252. StopAllSounds()
  253. -----------------------
  254. */
  255. public static void StopAllSounds( bool fadeOut, bool stopReserved = false ) {
  256. for ( int i = 0; i < theAudioManager.soundEmitters.Length; i++ ) {
  257. StopSound( i, fadeOut, stopReserved );
  258. }
  259. }
  260. /*
  261. -----------------------
  262. MuteAllSounds()
  263. -----------------------
  264. */
  265. public void MuteAllSounds( bool mute, bool muteReserved = false ) {
  266. for ( int i = 0; i < soundEmitters.Length; i++ ) {
  267. if ( !muteReserved && ( i == (int)EmitterChannel.Reserved ) ) {
  268. continue;
  269. }
  270. soundEmitters[i].audioSource.mute = true;
  271. }
  272. }
  273. /*
  274. -----------------------
  275. UnMuteAllSounds()
  276. -----------------------
  277. */
  278. public void UnMuteAllSounds( bool unmute, bool unmuteReserved = false ) {
  279. for ( int i = 0; i < soundEmitters.Length; i++ ) {
  280. if ( !unmuteReserved && ( i == (int)EmitterChannel.Reserved ) ) {
  281. continue;
  282. }
  283. if ( soundEmitters[i].audioSource.isPlaying ) {
  284. soundEmitters[i].audioSource.mute = false;
  285. }
  286. }
  287. }
  288. /*
  289. -----------------------
  290. GetEmitterEndTime()
  291. -----------------------
  292. */
  293. static public float GetEmitterEndTime( int idx ) {
  294. return theAudioManager.soundEmitters[idx].endPlayTime;
  295. }
  296. /*
  297. -----------------------
  298. SetEmitterTime()
  299. -----------------------
  300. */
  301. static public float SetEmitterTime( int idx, float time ) {
  302. return theAudioManager.soundEmitters[idx].time = time;
  303. }
  304. /*
  305. -----------------------
  306. PlaySound()
  307. -----------------------
  308. */
  309. static public int PlaySound( AudioClip clip, float volume, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitchVariance = 1.0f, bool loop = false ) {
  310. if ( !SoundEnabled ) {
  311. return -1;
  312. }
  313. return PlaySoundAt( ( staticListenerPosition != null ) ? staticListenerPosition.position : Vector3.zero, clip, volume, src, delay, pitchVariance, loop );
  314. }
  315. /*
  316. -----------------------
  317. FindFreeEmitter()
  318. -----------------------
  319. */
  320. static private int FindFreeEmitter( EmitterChannel src, SoundPriority priority ) {
  321. // default to the reserved emitter
  322. SoundEmitter next = theAudioManager.soundEmitters[0];
  323. if ( src == EmitterChannel.Any ) {
  324. // pull from the free emitter list if possible
  325. if ( theAudioManager.nextFreeEmitters.size > 0 ) {
  326. // return the first in the list
  327. next = theAudioManager.nextFreeEmitters[0];
  328. // remove it from the free list
  329. theAudioManager.nextFreeEmitters.RemoveAtFast( 0 );
  330. } else {
  331. // no free emitters available so pull from the lowest priority sound
  332. if ( priority == SoundPriority.VeryLow ) {
  333. // skip low priority sounds
  334. return -1;
  335. } else {
  336. // find a playing emitter that has a lower priority than what we're requesting
  337. // TODO - we could first search for Very Low, then Low, etc ... TBD if it's worth the effort
  338. next = theAudioManager.playingEmitters.Find( item => item != null && item.priority < priority );
  339. if ( next == null ) {
  340. // last chance to find a free emitter
  341. if ( priority < SoundPriority.Default ) {
  342. // skip sounds less than the default priority
  343. if ( theAudioManager.verboseLogging ) {
  344. Debug.LogWarning( "[AudioManager] skipping sound " + priority );
  345. }
  346. return -1;
  347. } else {
  348. // grab a default priority emitter so that we don't cannabalize a high priority sound
  349. next = theAudioManager.playingEmitters.Find( item => item != null && item.priority <= SoundPriority.Default ); ;
  350. }
  351. }
  352. if ( next != null ) {
  353. if ( theAudioManager.verboseLogging ) {
  354. Debug.LogWarning( "[AudioManager] cannabalizing " + next.originalIdx + " Time: " + Time.time );
  355. }
  356. // remove it from the playing list
  357. next.Stop();
  358. theAudioManager.playingEmitters.RemoveFast( next );
  359. }
  360. }
  361. }
  362. }
  363. if ( next == null ) {
  364. Debug.LogError( "[AudioManager] ERROR - absolutely couldn't find a free emitter! Priority = " + priority + " TOO MANY PlaySound* calls!" );
  365. showPlayingEmitterCount = true;
  366. return -1;
  367. }
  368. return next.originalIdx;
  369. }
  370. /*
  371. -----------------------
  372. PlaySound()
  373. -----------------------
  374. */
  375. static public int PlaySound( SoundFX soundFX, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f ) {
  376. if ( !SoundEnabled ) {
  377. return -1;
  378. }
  379. return PlaySoundAt( ( staticListenerPosition != null ) ? staticListenerPosition.position : Vector3.zero, soundFX, src, delay );
  380. }
  381. /*
  382. -----------------------
  383. PlaySoundAt()
  384. -----------------------
  385. */
  386. static public int PlaySoundAt( Vector3 position, SoundFX soundFX, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float volumeOverride = 1.0f, float pitchMultiplier = 1.0f ) {
  387. if ( !SoundEnabled ) {
  388. return -1;
  389. }
  390. AudioClip clip = soundFX.GetClip();
  391. if ( clip == null ) {
  392. return -1;
  393. }
  394. // check the distance from the local player and ignore sounds out of range
  395. if ( staticListenerPosition != null ) {
  396. float distFromListener = ( staticListenerPosition.position - position ).sqrMagnitude;
  397. if ( distFromListener > theAudioManager.audioMaxFallOffDistanceSqr ) {
  398. return -1;
  399. }
  400. if ( distFromListener > soundFX.MaxFalloffDistSquared ) {
  401. return -1;
  402. }
  403. }
  404. // check max playing sounds
  405. if ( soundFX.ReachedGroupPlayLimit() ) {
  406. if ( theAudioManager.verboseLogging ) {
  407. Debug.Log( "[AudioManager] PlaySoundAt() with " + soundFX.name + " skipped due to group play limit" );
  408. }
  409. return -1;
  410. }
  411. int idx = FindFreeEmitter( src, soundFX.priority );
  412. if ( idx == -1 ) {
  413. // no free emitters - should only happen on very low priority sounds
  414. return -1;
  415. }
  416. SoundEmitter emitter = theAudioManager.soundEmitters[idx];
  417. // make sure to detach the emitter from a previous parent
  418. emitter.ResetParent( soundEmitterParent.transform );
  419. emitter.gameObject.SetActive( true );
  420. // set up the sound emitter
  421. AudioSource audioSource = emitter.audioSource;
  422. ONSPAudioSource osp = emitter.osp;
  423. audioSource.enabled = true;
  424. audioSource.volume = Mathf.Clamp01( Mathf.Clamp01( theAudioManager.volumeSoundFX * soundFX.volume ) * volumeOverride * soundFX.GroupVolumeOverride );
  425. audioSource.pitch = soundFX.GetPitch() * pitchMultiplier;
  426. audioSource.time = 0.0f;
  427. audioSource.spatialBlend = 1.0f;
  428. audioSource.rolloffMode = soundFX.falloffCurve;
  429. if ( soundFX.falloffCurve == AudioRolloffMode.Custom ) {
  430. audioSource.SetCustomCurve( AudioSourceCurveType.CustomRolloff, soundFX.volumeFalloffCurve );
  431. }
  432. audioSource.SetCustomCurve( AudioSourceCurveType.ReverbZoneMix, soundFX.reverbZoneMix );
  433. audioSource.dopplerLevel = 0;
  434. audioSource.clip = clip;
  435. audioSource.spread = soundFX.spread;
  436. audioSource.loop = soundFX.looping;
  437. audioSource.mute = false;
  438. audioSource.minDistance = soundFX.falloffDistance.x;
  439. audioSource.maxDistance = soundFX.falloffDistance.y;
  440. audioSource.outputAudioMixerGroup = soundFX.GetMixerGroup( AudioManager.EmitterGroup );
  441. // set the play time so we can check when sounds are done
  442. emitter.endPlayTime = Time.time + clip.length + delay;
  443. // cache the default volume for fading
  444. emitter.defaultVolume = audioSource.volume;
  445. // sound priority
  446. emitter.priority = soundFX.priority;
  447. // reset this
  448. emitter.onFinished = null;
  449. // update the sound group limits
  450. emitter.SetPlayingSoundGroup( soundFX.Group );
  451. // add to the playing list
  452. if ( src == EmitterChannel.Any ) {
  453. theAudioManager.playingEmitters.AddUnique( emitter );
  454. }
  455. // OSP properties
  456. if ( osp != null ) {
  457. osp.EnableSpatialization = soundFX.ospProps.enableSpatialization;
  458. osp.EnableRfl = theAudioManager.enableSpatializedFastOverride || soundFX.ospProps.useFastOverride ? true : false;
  459. osp.Gain = soundFX.ospProps.gain;
  460. osp.UseInvSqr = soundFX.ospProps.enableInvSquare;
  461. osp.Near = soundFX.ospProps.invSquareFalloff.x;
  462. osp.Far = soundFX.ospProps.invSquareFalloff.y;
  463. audioSource.spatialBlend = (soundFX.ospProps.enableSpatialization) ? 1.0f : 0.8f;
  464. // make sure to set the properties in the audio source before playing
  465. osp.SetParameters(ref audioSource);
  466. }
  467. audioSource.transform.position = position;
  468. if ( theAudioManager.verboseLogging ) {
  469. Debug.Log( "[AudioManager] PlaySoundAt() channel = " + idx + " soundFX = " + soundFX.name + " volume = " + emitter.volume + " Delay = " + delay + " time = " + Time.time + "\n" );
  470. }
  471. // play the sound
  472. if ( delay > 0f ) {
  473. audioSource.PlayDelayed( delay );
  474. } else {
  475. audioSource.Play();
  476. }
  477. return idx;
  478. }
  479. /*
  480. -----------------------
  481. PlayRandomSoundAt()
  482. -----------------------
  483. */
  484. static public int PlayRandomSoundAt( Vector3 position, AudioClip[] clips, float volume, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitch = 1.0f, bool loop = false ) {
  485. if ( ( clips == null ) || ( clips.Length == 0 ) ) {
  486. return -1;
  487. }
  488. int idx = Random.Range( 0, clips.Length );
  489. return PlaySoundAt( position, clips[idx], volume, src, delay, pitch, loop );
  490. }
  491. /*
  492. -----------------------
  493. PlaySoundAt()
  494. -----------------------
  495. */
  496. static public int PlaySoundAt( Vector3 position, AudioClip clip, float volume = 1.0f, EmitterChannel src = EmitterChannel.Any, float delay = 0.0f, float pitch = 1.0f, bool loop = false ) {
  497. if ( !SoundEnabled ) {
  498. return -1;
  499. }
  500. if ( clip == null ) {
  501. return -1;
  502. }
  503. // check the distance from the local player and ignore sounds out of range
  504. if ( staticListenerPosition != null ) {
  505. if ( ( staticListenerPosition.position - position ).sqrMagnitude > theAudioManager.audioMaxFallOffDistanceSqr ) {
  506. // no chance of being heard
  507. return -1;
  508. }
  509. }
  510. int idx = FindFreeEmitter( src, 0 );
  511. if ( idx == -1 ) {
  512. // no free emitters - should only happen on very low priority sounds
  513. return -1;
  514. }
  515. SoundEmitter emitter = theAudioManager.soundEmitters[idx];
  516. // make sure to detach the emitter from a previous parent
  517. emitter.ResetParent( soundEmitterParent.transform );
  518. emitter.gameObject.SetActive( true );
  519. // set up the sound emitter
  520. AudioSource audioSource = emitter.audioSource;
  521. ONSPAudioSource osp = emitter.osp;
  522. audioSource.enabled = true;
  523. audioSource.volume = Mathf.Clamp01( theAudioManager.volumeSoundFX * volume );
  524. audioSource.pitch = pitch;
  525. audioSource.spatialBlend = 0.8f;
  526. audioSource.rolloffMode = AudioRolloffMode.Linear;
  527. audioSource.SetCustomCurve( AudioSourceCurveType.ReverbZoneMix, defaultReverbZoneMix );
  528. audioSource.dopplerLevel = 0.0f;
  529. audioSource.clip = clip;
  530. audioSource.spread = 0.0f;
  531. audioSource.loop = loop;
  532. audioSource.mute = false;
  533. audioSource.minDistance = theAudioManager.audioMinFallOffDistance;
  534. audioSource.maxDistance = theAudioManager.audioMaxFallOffDistance;
  535. audioSource.outputAudioMixerGroup = AudioManager.EmitterGroup;
  536. // set the play time so we can check when sounds are done
  537. emitter.endPlayTime = Time.time + clip.length + delay;
  538. // cache the default volume for fading
  539. emitter.defaultVolume = audioSource.volume;
  540. // default priority
  541. emitter.priority = 0;
  542. // reset this
  543. emitter.onFinished = null;
  544. // update the sound group limits
  545. emitter.SetPlayingSoundGroup( null );
  546. // add to the playing list
  547. if ( src == EmitterChannel.Any ) {
  548. theAudioManager.playingEmitters.AddUnique( emitter );
  549. }
  550. // disable spatialization (by default for regular AudioClips)
  551. if ( osp != null ) {
  552. osp.EnableSpatialization = false;
  553. }
  554. audioSource.transform.position = position;
  555. if ( theAudioManager.verboseLogging ) {
  556. Debug.Log( "[AudioManager] PlaySoundAt() channel = " + idx + " clip = " + clip.name + " volume = " + emitter.volume + " Delay = " + delay + " time = " + Time.time + "\n" );
  557. }
  558. // play the sound
  559. if ( delay > 0f ) {
  560. audioSource.PlayDelayed( delay );
  561. } else {
  562. audioSource.Play();
  563. }
  564. return idx;
  565. }
  566. /*
  567. -----------------------
  568. SetOnFinished()
  569. -----------------------
  570. */
  571. public static void SetOnFinished( int emitterIdx, System.Action onFinished ) {
  572. if ( emitterIdx >= 0 && emitterIdx < theAudioManager.maxSoundEmitters ) {
  573. theAudioManager.soundEmitters[emitterIdx].SetOnFinished( onFinished );
  574. }
  575. }
  576. /*
  577. -----------------------
  578. SetOnFinished()
  579. -----------------------
  580. */
  581. public static void SetOnFinished( int emitterIdx, System.Action<object> onFinished, object obj ) {
  582. if ( emitterIdx >= 0 && emitterIdx < theAudioManager.maxSoundEmitters ) {
  583. theAudioManager.soundEmitters[emitterIdx].SetOnFinished( onFinished, obj );
  584. }
  585. }
  586. /*
  587. -----------------------
  588. AttachSoundToParent()
  589. -----------------------
  590. */
  591. public static void AttachSoundToParent( int idx, Transform parent ) {
  592. if ( theAudioManager.verboseLogging ) {
  593. string parentName = parent.name;
  594. if ( parent.parent != null ) {
  595. parentName = parent.parent.name + "/" + parentName;
  596. }
  597. Debug.Log( "[AudioManager] ATTACHING INDEX " + idx + " to " + parentName );
  598. }
  599. theAudioManager.soundEmitters[idx].ParentTo( parent );
  600. }
  601. /*
  602. -----------------------
  603. DetachSoundFromParent()
  604. -----------------------
  605. */
  606. public static void DetachSoundFromParent( int idx ) {
  607. if ( theAudioManager.verboseLogging ) {
  608. Debug.Log( "[AudioManager] DETACHING INDEX " + idx );
  609. }
  610. theAudioManager.soundEmitters[idx].DetachFromParent();
  611. }
  612. /*
  613. -----------------------
  614. DetachSoundsFromParent()
  615. -----------------------
  616. */
  617. public static void DetachSoundsFromParent( SoundEmitter[] emitters, bool stopSounds = true ) {
  618. if ( emitters == null ) {
  619. return;
  620. }
  621. foreach ( SoundEmitter emitter in emitters ) {
  622. if ( emitter.defaultParent != null ) {
  623. if ( stopSounds ) {
  624. emitter.Stop();
  625. }
  626. emitter.DetachFromParent();
  627. // make sure it's active
  628. emitter.gameObject.SetActive( true );
  629. } else {
  630. if ( stopSounds ) {
  631. emitter.Stop();
  632. }
  633. }
  634. }
  635. }
  636. /*
  637. -----------------------
  638. SetEmitterMixerGroup()
  639. -----------------------
  640. */
  641. public static void SetEmitterMixerGroup( int idx, AudioMixerGroup mixerGroup ) {
  642. if ( ( theAudioManager != null ) && ( idx > -1 ) ) {
  643. theAudioManager.soundEmitters[idx].SetAudioMixer( mixerGroup );
  644. }
  645. }
  646. /*
  647. -----------------------
  648. GetActiveSnapshot()
  649. -----------------------
  650. */
  651. public static MixerSnapshot GetActiveSnapshot() {
  652. return ( theAudioManager != null ) ? theAudioManager.currentSnapshot : null;
  653. }
  654. /*
  655. -----------------------
  656. SetCurrentSnapshot()
  657. -----------------------
  658. */
  659. public static void SetCurrentSnapshot( MixerSnapshot mixerSnapshot ) {
  660. #if UNITY_EDITOR
  661. if ( mixerSnapshot == null || mixerSnapshot.snapshot == null ) {
  662. Debug.LogError( "[AudioManager] ERROR setting empty mixer snapshot!" );
  663. } else {
  664. Debug.Log( "[AudioManager] Setting audio mixer snapshot: " + ( ( mixerSnapshot != null && mixerSnapshot.snapshot != null ) ? mixerSnapshot.snapshot.name : "None" ) + " Time: " + Time.time );
  665. }
  666. #endif
  667. if ( theAudioManager != null ) {
  668. if ( ( mixerSnapshot != null ) && ( mixerSnapshot.snapshot != null ) ) {
  669. mixerSnapshot.snapshot.TransitionTo( mixerSnapshot.transitionTime );
  670. } else {
  671. mixerSnapshot = null;
  672. }
  673. theAudioManager.currentSnapshot = mixerSnapshot;
  674. }
  675. }
  676. /*
  677. -----------------------
  678. BlendWithCurrentSnapshot()
  679. -----------------------
  680. */
  681. public static void BlendWithCurrentSnapshot( MixerSnapshot blendSnapshot, float weight, float blendTime = 0.0f ) {
  682. if ( theAudioManager != null ) {
  683. if ( theAudioManager.audioMixer == null ) {
  684. Debug.LogWarning( "[AudioManager] can't call BlendWithCurrentSnapshot if the audio mixer is not set!" );
  685. return;
  686. }
  687. if ( blendTime == 0.0f ) {
  688. blendTime = Time.deltaTime;
  689. }
  690. if ( ( theAudioManager.currentSnapshot != null ) && (theAudioManager.currentSnapshot.snapshot != null ) ) {
  691. if ( ( blendSnapshot != null ) && ( blendSnapshot.snapshot != null ) ) {
  692. weight = Mathf.Clamp01( weight );
  693. if ( weight == 0.0f ) {
  694. // revert to the default snapshot
  695. theAudioManager.currentSnapshot.snapshot.TransitionTo( blendTime );
  696. } else {
  697. AudioMixerSnapshot[] snapshots = new AudioMixerSnapshot[] { theAudioManager.currentSnapshot.snapshot, blendSnapshot.snapshot };
  698. float[] weights = new float[] { 1.0f - weight, weight };
  699. theAudioManager.audioMixer.TransitionToSnapshots( snapshots, weights, blendTime );
  700. }
  701. }
  702. }
  703. }
  704. }
  705. }
  706. } // namespace OVR