6 using System.Collections.Generic;
8 using SiliconStudio.Core;
9 using SiliconStudio.Core.Diagnostics;
11 namespace SiliconStudio.
Paradox.Audio
17 internal enum SoundMusicAction
28 internal struct SoundMusicActionRequest
30 public SoundMusic Requester;
32 public SoundMusicAction RequestedAction;
34 public SoundMusicActionRequest(SoundMusic requester, SoundMusicAction request)
36 Requester = requester;
37 RequestedAction = request;
44 internal enum SoundMusicEvent
56 internal struct SoundMusicEventNotification
58 public SoundMusicEvent Event;
60 public object EventData;
62 public SoundMusicEventNotification(SoundMusicEvent mEvent,
object eventData)
65 EventData = eventData;
85 public static readonly
Logger Logger = GlobalLogger.GetLogger(
"AudioEngine");
93 : this(null, sampleRate)
104 private AudioEngine(AudioDevice device, uint sampleRate = 0)
107 throw new NotImplementedException();
109 State = AudioEngineState.Running;
111 AudioSampleRate = sampleRate;
113 AudioEngineImpl(device);
115 ++nbOfAudioEngineInstances;
123 private static List<AudioDevice> GetAvailableDevices()
125 throw new NotImplementedException();
128 private static int nbOfAudioEngineInstances;
133 private readonly List<SoundInstanceBase> pausedSounds =
new List<SoundInstanceBase>();
138 internal uint AudioSampleRate {
get;
private set; }
163 State = AudioEngineState.Paused;
165 PauseAudioPlatformSpecific();
167 pausedSounds.Clear();
168 foreach (var sound
in notDisposedSounds)
171 if (soundEffect != null)
173 foreach (var instance
in soundEffect.Instances)
178 pausedSounds.Add(instance);
183 if(soundInstance != null && soundInstance.PlayState ==
SoundPlayState.Playing)
185 soundInstance.Pause();
186 pausedSounds.Add(soundInstance);
199 State = AudioEngineState.Running;
201 ResumeAudioPlatformSpecific();
203 foreach (var playableSound
in pausedSounds)
205 if (!playableSound.IsDisposed && playableSound.PlayState ==
SoundPlayState.Paused)
206 playableSound.Play();
218 var bestCandidateSize = int.MaxValue;
219 lock (notDisposedSounds)
221 foreach (var notDisposedSound
in notDisposedSounds)
224 if(soundEffect == null)
227 var sizeSoundEffect = soundEffect.WaveDataSize / soundEffect.WaveFormat.BlockAlign;
228 if(sizeSoundEffect >= bestCandidateSize)
231 foreach (var instance
in soundEffect.Instances)
233 if (instance.PlayState !=
SoundPlayState.Stopped && !instance.IsLooped)
235 bestCandidate = soundEffect;
236 bestCandidateSize = sizeSoundEffect;
244 return bestCandidate;
250 internal void ForceSoundEffectInstanceUpdate()
252 lock (notDisposedSounds)
254 foreach (var notDisposedSound
in notDisposedSounds)
257 if (soundEffect == null)
260 foreach (var instance
in soundEffect.Instances)
261 instance.PlayState = instance.PlayState;
266 private readonly List<SoundBase> notDisposedSounds =
new List<SoundBase>();
268 internal void RegisterSound(SoundBase newSound)
270 lock (notDisposedSounds)
272 notDisposedSounds.Add(newSound);
276 internal void UnregisterSound(SoundBase disposedSound)
278 lock (notDisposedSounds)
280 if (!notDisposedSounds.Remove(disposedSound))
281 throw new AudioSystemInternalException(
"Try to remove a disposed sound not in the list of registered sounds.");
292 State = AudioEngineState.Disposed;
295 lock (notDisposedSounds)
297 notDisposedSoundsArray = notDisposedSounds.ToArray();
301 foreach (var soundBase
in notDisposedSoundsArray)
304 --nbOfAudioEngineInstances;
312 private readonly ThreadSafeQueue<SoundMusicActionRequest> musicActionRequests =
new ThreadSafeQueue<SoundMusicActionRequest>();
318 internal void SubmitMusicActionRequest(SoundMusicActionRequest request)
320 musicActionRequests.Enqueue(request);
326 private SoundMusic currentMusic;
328 private void QueueLastPendingRequests(Dictionary<SoundMusicAction, bool> requestAftPlay, SoundMusic requester)
330 lock (musicActionRequests)
332 foreach (var action
in requestAftPlay.Where(x => x.Value).Select(x => x.Key))
333 musicActionRequests.Enqueue(
new SoundMusicActionRequest(requester, action));
344 private void UpdateMusicImpl()
347 ProccessQueuedMediaSessionEvents();
350 ProcessMusicActionRequests();
358 private void ProcessMusicActionRequests()
363 if (musicActionRequests.Count == 0)
367 if (currentMusic != null && !isMusicPlayerReady)
371 var lastPlayRequestMusicInstance = currentMusic;
372 var actionRequestedAftLastPlay =
new Dictionary<SoundMusicAction, bool>
374 { SoundMusicAction.Pause,
false },
375 { SoundMusicAction.Stop,
false },
376 { SoundMusicAction.Volume,
false }
378 var shouldRestartCurrentMusic =
false;
379 var shouldStartCurrentMusic =
false;
381 foreach (var actionRequest
in musicActionRequests.DequeueAsList())
383 if (actionRequest.RequestedAction == SoundMusicAction.Play)
385 lastPlayRequestMusicInstance = actionRequest.Requester;
386 shouldRestartCurrentMusic = shouldRestartCurrentMusic || lastPlayRequestMusicInstance != currentMusic || actionRequestedAftLastPlay[SoundMusicAction.Stop];
387 shouldStartCurrentMusic =
true;
388 foreach (var action
in actionRequestedAftLastPlay.Keys.ToArray())
389 actionRequestedAftLastPlay[action] =
false;
391 else if (actionRequest.Requester == lastPlayRequestMusicInstance)
393 actionRequestedAftLastPlay[actionRequest.RequestedAction] =
true;
398 if (currentMusic == null)
404 if (lastPlayRequestMusicInstance == null)
408 if(!lastPlayRequestMusicInstance.IsDisposed)
409 LoadNewMusic(lastPlayRequestMusicInstance);
412 QueueLastPendingRequests(actionRequestedAftLastPlay, currentMusic);
420 if (currentMusic != lastPlayRequestMusicInstance)
423 musicActionRequests.Enqueue(
new SoundMusicActionRequest(lastPlayRequestMusicInstance, SoundMusicAction.Play));
424 QueueLastPendingRequests(actionRequestedAftLastPlay, lastPlayRequestMusicInstance);
426 else if(!currentMusic.IsDisposed)
428 if (shouldRestartCurrentMusic)
429 RestartCurrentMusic();
431 if (shouldStartCurrentMusic)
434 if (actionRequestedAftLastPlay[SoundMusicAction.Volume])
437 if (actionRequestedAftLastPlay[SoundMusicAction.Stop])
439 else if (actionRequestedAftLastPlay[SoundMusicAction.Pause])
449 private void ProcessMusicEnded()
451 if (currentMusic == null || currentMusic.IsDisposed)
455 if (currentMusic.IsLooped && !currentMusic.ShouldExitLoop && currentMusic.PlayState !=
SoundPlayState.Stopped)
457 RestartCurrentMusic();
463 currentMusic.SetStateToStopped();
467 private void ProcessMusicReady()
469 PlatformSpecificProcessMusicReady();
471 isMusicPlayerReady =
true;
473 if (!currentMusic.IsDisposed)
486 private readonly ThreadSafeQueue<SoundMusicEventNotification> musicMediaEvents =
new ThreadSafeQueue<SoundMusicEventNotification>();
488 private bool isMusicPlayerReady;
490 private void ProccessQueuedMediaSessionEvents()
492 foreach (var eventNotification
in musicMediaEvents.DequeueAsList())
496 ProcessMusicError(eventNotification);
498 switch (eventNotification.Event)
500 case SoundMusicEvent.MetaDataLoaded:
501 ProcessMusicMetaData();
503 case SoundMusicEvent.ReadyToBePlayed:
506 case SoundMusicEvent.EndOfTrackReached:
509 case SoundMusicEvent.MusicPlayerClosed:
510 ProcessPlayerClosed();
515 var dispEventData = eventNotification.EventData as IDisposable;
516 if (dispEventData != null)
517 dispEventData.Dispose();
void Update()
Method that updates all the sounds play status.
AudioEngineState
Describe the possible states of the AudioEngine.
void PauseAudio()
Pause the audio engine. That is, pause all the currently playing SoundInstanceBase, and block any future play until ResumeAudio is called.
This class provides a loaded sound resource which is localizable in the 3D scene. ...
SoundPlayState
Current state (playing, paused, or stopped) of a sound implementing the IPlayableSound interface...
void ResumeAudio()
Resume all audio engine. That is, resume the sounds paused by PauseAudio, and re-authorize future cal...
SoundEffect GetLeastSignificativeSoundEffect()
Return the SoundEffect evaluated as having least impact onto the final audio output among all the non...
Base class for a framework component.
Base class for sound that creates voices
Base implementation for ILogger.
Represents the audio engine. In current version, the audio engine necessarily creates its context on ...
Base class for all the sounds and sound instances.
AudioEngine(uint sampleRate=0)
Create an Audio Engine on the default audio device
override void Destroy()
Disposes of object resources.