Пример #1
0
        internal SoundInstance(Sound staticSound, AudioListener listener, bool forceLoadInMemory)
        {
            Listener = listener;
            engine = staticSound.AudioEngine;
            sound = staticSound;
            spatialized = staticSound.Spatialized;

            var streamed = staticSound.StreamFromDisk && !forceLoadInMemory;

            if (engine.State == AudioEngineState.Invalidated)
                return;

            Source = AudioLayer.SourceCreate(listener.Listener, staticSound.SampleRate, streamed ? CompressedSoundSource.NumberOfBuffers : 1, staticSound.Channels == 1, spatialized, streamed);
            if (Source.Ptr == IntPtr.Zero)
            {
                throw new Exception("Failed to create an AudioLayer Source");
            }

            if (streamed)
            {
                soundSource = new CompressedSoundSource(this, staticSound.CompressedDataUrl, staticSound.NumberOfPackets, staticSound.SampleRate, staticSound.Channels, staticSound.MaxPacketLength);
            }
            else
            {
                if (sound.PreloadedBuffer.Ptr == IntPtr.Zero)
                {
                    staticSound.LoadSoundInMemory(); //this should be already loaded by the serializer, but in the case of forceLoadInMemory might not be the case yet.
                }
                AudioLayer.SourceSetBuffer(Source, staticSound.PreloadedBuffer);
            }

            ResetStateToDefault();
        }
Пример #2
0
        /// <summary>
        /// Create the audio engine to the sound base instance.
        /// </summary>
        /// <param name="engine">A valid AudioEngine</param>
        /// <exception cref="ArgumentNullException">The engine argument is null</exception>
        internal void AttachEngine(AudioEngine engine)
        {
            if (engine == null)
                throw new ArgumentNullException("engine");

            AudioEngine = engine;
        }
Пример #3
0
        /// <summary>
        /// Create an new instance of AudioSystem
        /// </summary>
        /// <param name="registry">The service registry in which to register the <see cref="AudioSystem"/> services</param>
        public AudioSystem(IServiceRegistry registry)
            : base(registry)
        {
            Enabled = true;
            AudioEngine = new AudioEngine();

            registry.AddService(typeof(AudioSystem), this);
        }
Пример #4
0
        public override void Initialize()
        {
            base.Initialize();

            AudioEngine = AudioEngineFactory.NewAudioEngine();

            Game.Activated += OnActivated;
            Game.Deactivated += OnDeactivated;
        }
Пример #5
0
        /// <summary>
        /// Create and Load a sound effect from an input wav stream.
        /// </summary>
        /// <param name="engine">Name of the audio engine in which to create the sound effect</param>
        /// <param name="stream">A stream corresponding to a wav file.</param>
        /// <returns>A new instance soundEffect ready to be played</returns>
        /// <exception cref="ArgumentNullException"><paramref name="engine"/> or <paramref name="stream"/> is null.</exception>
        /// <exception cref="NotSupportedException">The wave file or has more than 2 channels or is not encoded in 16bits.</exception>
        /// <exception cref="InvalidOperationException">The content of the stream does not correspond to a valid wave file.</exception>
        /// <exception cref="OutOfMemoryException">There is not enough memory anymore to load the specified file in memory. </exception>
        /// <exception cref="ObjectDisposedException">The audio engine has already been disposed</exception>
        /// <remarks>Supported WAV files' audio format is the 16bits PCM format.</remarks>
        public static SoundEffect Load(AudioEngine engine, Stream stream)
        {
            if(engine == null)
                throw new ArgumentNullException(nameof(engine));

            var newSdEff = new SoundEffect();
            newSdEff.AttachEngine(engine);
            newSdEff.Load(stream);

            return newSdEff;
        }
Пример #6
0
        /// <summary>
        /// Create the audio engine to the sound base instance.
        /// </summary>
        /// <param name="engine">A valid AudioEngine</param>
        /// <exception cref="ArgumentNullException">The engine argument is null</exception>
        /// <exception cref="ArgumentException">The engine argument is not an instance of AudioEngineWindows</exception>
        internal void AttachEngine(AudioEngine engine)
        {
            if (engine == null)
                throw new ArgumentNullException("engine");

            AudioEngineWindows e = engine as AudioEngineWindows;
            if (e == null)
            {
                throw new ArgumentException("Invalid type, expected AudioEngineWindows", "enging");
                
            }
            AudioEngine = e;
        }
Пример #7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SoundInstance"/> class using a dynamic sound source.
        /// </summary>
        /// <param name="engine">The audio engine that will be used to play this instance</param>
        /// <param name="listener">The listener of this instance</param>
        /// <param name="dynamicSoundSource">The source from where the PCM data will be fetched</param>
        /// <param name="sampleRate">The sample rate of this audio stream</param>
        /// <param name="mono">Set to true if the souce is mono, false if stereo</param>
        /// <param name="spatialized">If the SoundInstance will be used for spatialized audio set to true, if not false, if true mono must also be true</param>
        public SoundInstance(AudioEngine engine, AudioListener listener, DynamicSoundSource dynamicSoundSource, int sampleRate, bool mono, bool spatialized = false)
        {
            Listener = listener;
            this.engine = engine;
            this.spatialized = spatialized;
            soundSource = dynamicSoundSource;

            if (engine.State == AudioEngineState.Invalidated)
                return;

            Source = AudioLayer.SourceCreate(listener.Listener, sampleRate, dynamicSoundSource.MaxNumberOfBuffers, mono, spatialized, true);
            if (Source.Ptr == IntPtr.Zero)
            {
                throw new Exception("Failed to create an AudioLayer Source");
            }

            ResetStateToDefault();
        }
Пример #8
0
        public AudioListener(AudioEngine engine)
        {
            if (engine.State == AudioEngineState.Invalidated) return;

#if SILICONSTUDIO_PLATFORM_IOS
            if (engine.DefaultListener == null)
            {
                Listener = AudioLayer.ListenerCreate(engine.AudioDevice);
                AudioLayer.ListenerEnable(Listener);
            }
            else
            {
                Listener = engine.DefaultListener.Listener;
            }
#else
            Listener = AudioLayer.ListenerCreate(engine.AudioDevice);
            AudioLayer.ListenerEnable(Listener);
#endif    
        }
Пример #9
0
        /// <summary>
        /// Create and Load a sound music from an input file.
        /// </summary>
        /// <param name="engine">The audio engine in which to load the soundMusic</param>
        /// <param name="stream">The stream.</param>
        /// <returns>A new instance of soundMusic ready to be played</returns>
        /// <exception cref="System.ArgumentNullException">engine
        /// or
        /// filename</exception>
        /// <exception cref="System.ObjectDisposedException">The AudioEngine in which to create the voice is disposed.</exception>
        /// <exception cref="System.ArgumentException">engine or stream</exception>
        /// <exception cref="ObjectDisposedException">The AudioEngine in which to create the voice is disposed.</exception>
        /// <exception cref="ArgumentNullException">File ' + filename + ' does not exist.</exception>
        /// <remarks>On all platform the wav format is supported.
        /// For compressed formats, it is the task of the build engine to automatically adapt the original files to the best hardware specific format.</remarks>
        public static SoundMusic Load(AudioEngine engine, Stream stream)
        {
            if(engine == null)
                throw new ArgumentNullException("engine");

            if (stream == null)
                throw new ArgumentNullException("stream");

            if(engine.IsDisposed)
                throw new ObjectDisposedException("The AudioEngine in which to create the voice is disposed.");

            // TODO: Not portable on WindowsStore

            var ret = new SoundMusic();
            ret.AttachEngine(engine);
            ret.Load(stream);

            return ret;
        }
Пример #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SoundInstance"/> class using a dynamic sound source.
        /// </summary>
        /// <param name="engine">The audio engine that will be used to play this instance</param>
        /// <param name="listener">The listener of this instance</param>
        /// <param name="dynamicSoundSource">The source from where the PCM data will be fetched</param>
        /// <param name="sampleRate">The sample rate of this audio stream</param>
        /// <param name="mono">Set to true if the souce is mono, false if stereo</param>
        /// <param name="spatialized">If the SoundInstance will be used for spatialized audio set to true, if not false, if true mono must also be true</param>
        /// <param name="useHrtf">If the engine should use Hrtf for spatialization</param>
        /// <param name="directionalFactor"></param>
        /// <param name="environment"></param>
        public SoundInstance(AudioEngine engine, AudioListener listener, DynamicSoundSource dynamicSoundSource, int sampleRate, bool mono, bool spatialized = false, bool useHrtf = false, float directionalFactor = 0.0f, HrtfEnvironment environment = HrtfEnvironment.Small)
        {
            Listener         = listener;
            this.engine      = engine;
            this.spatialized = spatialized;
            soundSource      = dynamicSoundSource;

            if (engine.State == AudioEngineState.Invalidated)
            {
                return;
            }

            Source = AudioLayer.SourceCreate(listener.Listener, sampleRate, dynamicSoundSource.MaxNumberOfBuffers, mono, spatialized, true, useHrtf, directionalFactor, environment);
            if (Source.Ptr == IntPtr.Zero)
            {
                throw new Exception("Failed to create an AudioLayer Source");
            }

            ResetStateToDefault();
        }
Пример #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SoundInstance"/> class using a dynamic sound source.
        /// </summary>
        /// <param name="engine">The audio engine that will be used to play this instance</param>
        /// <param name="listener">The listener of this instance</param>
        /// <param name="dynamicSoundSource">The source from where the PCM data will be fetched</param>
        /// <param name="sampleRate">The sample rate of this audio stream</param>
        /// <param name="mono">Set to true if the souce is mono, false if stereo</param>
        /// <param name="spatialized">If the SoundInstance will be used for spatialized audio set to true, if not false, if true mono must also be true</param>
        public SoundInstance(AudioEngine engine, AudioListener listener, DynamicSoundSource dynamicSoundSource, int sampleRate, bool mono, bool spatialized = false)
        {
            Listener         = listener;
            this.engine      = engine;
            this.spatialized = spatialized;
            soundSource      = dynamicSoundSource;

            if (engine.State == AudioEngineState.Invalidated)
            {
                return;
            }

            Source = AudioLayer.SourceCreate(listener.Listener, sampleRate, dynamicSoundSource.MaxNumberOfBuffers, mono, spatialized, true);
            if (Source.Ptr == IntPtr.Zero)
            {
                throw new Exception("Failed to create an AudioLayer Source");
            }

            ResetStateToDefault();
        }
Пример #12
0
        public override void Initialize()
        {
            base.Initialize();

            lock (AudioEngineStaticLock)
            {
                if (audioEngineSingleton == null)
                {
                    audioEngineSingleton = AudioEngineFactory.NewAudioEngine(RequestedAudioDevice);
                }
                else
                {
                    ((IReferencable)audioEngineSingleton).AddReference();
                }

                AudioEngine = audioEngineSingleton;
            }

            Game.Activated += OnActivated;
            Game.Deactivated += OnDeactivated;
        }
Пример #13
0
        public override void Initialize()
        {
            base.Initialize();

            lock (AudioEngineStaticLock)
            {
                if (audioEngineSingleton == null)
                {
                    audioEngineSingleton = AudioEngineFactory.NewAudioEngine(RequestedAudioDevice);
                }
                else
                {
                    ((IReferencable)audioEngineSingleton).AddReference();
                }

                AudioEngine = audioEngineSingleton;
            }

            Game.Activated   += OnActivated;
            Game.Deactivated += OnDeactivated;
        }
Пример #14
0
        internal override void PlayImpl()
        {
            AudioEngine.SubmitMusicActionRequest(new SoundMusicActionRequest(this, SoundMusicAction.Play));

            // Actual Playing is happening during the Audio Engine update
            // but we can not wait this long to update the PlayState of the currently playing SoundMusic
            // after this call to Play, PlayState of the previous playing music should directly be set to Stopped
            // this is why we use here the static field PreviousPlayingInstance
            lock (PreviousPlayingInstanceLock) // protection again possible future multithreading.
            {
                if (previousPlayingInstance != this)
                {
                    if (previousPlayingInstance != null)
                    {
                        previousPlayingInstance.SetStateToStopped();
                    }

                    previousPlayingInstance = this;
                }
            }
        }
Пример #15
0
        public AudioListener(AudioEngine engine)
        {
            if (engine.State == AudioEngineState.Invalidated)
            {
                return;
            }

#if SILICONSTUDIO_PLATFORM_IOS
            if (engine.DefaultListener == null)
            {
                Listener = AudioLayer.ListenerCreate(engine.AudioDevice);
                AudioLayer.ListenerEnable(Listener);
            }
            else
            {
                Listener = engine.DefaultListener.Listener;
            }
#else
            Listener = AudioLayer.ListenerCreate(engine.AudioDevice);
            AudioLayer.ListenerEnable(Listener);
#endif
        }
Пример #16
0
        public override void Initialize()
        {
            base.Initialize();

            lock (AudioEngineStaticLock)
            {
                if (audioEngineSingleton == null)
                {
                    var settings = ((Game)Game)?.Settings?.Configurations?.Get <AudioEngineSettings>();
                    audioEngineSingleton = AudioEngineFactory.NewAudioEngine(RequestedAudioDevice, settings != null && settings.HrtfSupport ? AudioLayer.DeviceFlags.Hrtf : AudioLayer.DeviceFlags.None);
                }
                else
                {
                    ((IReferencable)audioEngineSingleton).AddReference();
                }

                AudioEngine = audioEngineSingleton;
            }

            Game.Activated   += OnActivated;
            Game.Deactivated += OnDeactivated;
        }
Пример #17
0
        internal override void DestroyImpl()
        {
            AudioEngine.UnregisterSound(this);

            IsDisposing = true;

            lock (WorkerLock) // avoid to have simultaneous destroy and submit buffer (via BufferNeeded of working thread).
            {
                base.DestroyImpl();
            }

            Interlocked.Decrement(ref numberOfInstances);

            if (numberOfInstances == 0)
            {
                awakeWorkerThread.Set();
                if (!workerTask.Wait(500))
                {
                    throw new AudioSystemInternalException("The DynamicSoundEffectInstance worker did not complete in allowed time.");
                }
                awakeWorkerThread.Dispose();
            }
        }
Пример #18
0
        /// <summary>
        /// Create a dynamic sound effect instance with the given sound properties.
        /// </summary>
        /// <param name="engine">The engine in which the dynamicSoundEffectInstance is created</param>
        /// <param name="sampleRate">Sample rate, in Hertz (Hz), of audio content. Must between 8000 Hz and 48000 Hz</param>
        /// <param name="channels">Number of channels in the audio data.</param>
        /// <param name="encoding">Encoding of a sound data sample</param>
        /// <returns>A new DynamicSoundEffectInstance instance ready to filled with data and then played</returns>
        /// <exception cref="ArgumentOutOfRangeException">This exception is thrown for one of the following reason:
        /// <list type="bullet">
        /// <item>The value specified for sampleRate is less than 8000 Hz or greater than 48000 Hz. </item>
        /// <item>The value specified for channels is something other than mono or stereo. </item>
        /// <item>The value specified for data encoding is something other than 8 or 16 bits. </item>
        /// </list>
        ///  </exception>
        /// <exception cref="ArgumentNullException"><paramref name="engine"/> is null.</exception>
        public DynamicSoundEffectInstance(AudioEngine engine, int sampleRate, AudioChannels channels, AudioDataEncoding encoding)
        {
            AttachEngine(engine);

            if (sampleRate < 8000 || 48000 < sampleRate)
                throw new ArgumentOutOfRangeException("sampleRate");

            if(channels != AudioChannels.Mono && channels != AudioChannels.Stereo)
                throw new ArgumentOutOfRangeException("channels");

            if(encoding != AudioDataEncoding.PCM_8Bits && encoding != AudioDataEncoding.PCM_16Bits)
                throw new ArgumentOutOfRangeException("encoding");

            waveFormat = new WaveFormat(sampleRate, (int)encoding, (int)channels);

            Interlocked.Increment(ref totalNbOfInstances);
            Interlocked.Increment(ref numberOfInstances);

            // first instance of dynamic sound effect instance => we create the workerThead and the associated event.
            if (numberOfInstances == 1)
            {
                instancesNeedingBuffer = new ThreadSafeQueue<DynamicSoundEffectInstance>(); // to be sure that there is no remaining request from previous sessions
                awakeWorkerThread = new AutoResetEvent(false);
                CreateWorkerThread();
            }
            
            Name = "Dynamic Sound Effect Instance - "+totalNbOfInstances;

            CreateVoice(WaveFormat);

            InitializeDynamicSound();

            AudioEngine.RegisterSound(this);

            ResetStateToDefault();
        }
Пример #19
0
 internal override void PauseImpl()
 {
     AudioEngine.SubmitMusicActionRequest(new SoundMusicActionRequest(this, SoundMusicAction.Pause));
 }
Пример #20
0
 private void OnDeactivated(object sender, EventArgs e)
 {
     // pause the audio
     AudioEngine.PauseAudio();
     AudioEngine.Update(); // force the update of the audio to pause the Musics
 }
Пример #21
0
 private void OnActivated(object sender, EventArgs e)
 {
     // resume the audio
     AudioEngine.ResumeAudio();
 }
Пример #22
0
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            AudioEngine.Update();
        }
Пример #23
0
 internal override void DestroyImpl()
 {
     AudioEngine.UnregisterSound(this);
     // mediaInputStream is disposed by AudioEngine.ProcessPlayerClosed()
 }
Пример #24
0
        public AudioVoice(AudioEngine engine, SoundEffectInstance effectInstance, WaveFormat desiredFormat)
        {
            if (engine == null) throw new ArgumentNullException("engine");
            if (desiredFormat == null) throw new ArgumentNullException("desiredFormat");

            audioEngine = engine;
            soundEffectInstance = effectInstance;
            waveFormat = desiredFormat;
            BusIndexMixer = uint.MaxValue;

            if (desiredFormat.BitsPerSample != 16)
                throw new AudioSystemInternalException("Invalid Audio Format. " + desiredFormat.BitsPerSample + " bits by sample is not supported.");

            lock (StaticMembersLock)
            {
                if (nbOfInstances == 0)
                {
                    // Create the Audio Graph
                    audioGraph = new AUGraph();

                    // Open the graph (does not initialize it yet)
                    audioGraph.Open();
                    
                    // Create the AudioComponentDescrition corresponding to the IO Remote output and MultiChannelMixer 
                    var remoteInOutComponentDesc = AudioComponentDescription.CreateOutput(AudioTypeOutput.Remote);
                    var mixerMultiChannelComponentDesc = AudioComponentDescription.CreateMixer(AudioTypeMixer.MultiChannel);
                    var mixer3DComponentDesc = AudioComponentDescription.CreateMixer(AudioTypeMixer.Spacial);

                    // Add the Audio Unit nodes to the AudioGraph
                    var outputUnitNodeId = audioGraph.AddNode(remoteInOutComponentDesc);
                    var idChannelMixerNode = audioGraph.AddNode(mixerMultiChannelComponentDesc);
                    var id3DMixerNode = audioGraph.AddNode(mixer3DComponentDesc);

                    // Connect the nodes together
                    CheckGraphError(audioGraph.ConnnectNodeInput(idChannelMixerNode, 0, outputUnitNodeId, 0), "Connection of the graph node failed.");
                    CheckGraphError(audioGraph.ConnnectNodeInput(id3DMixerNode, 0, idChannelMixerNode, MaxNumberOfTracks), "Connection of the graph node failed.");

                    // Get the MixerUnit objects
                    unitChannelMixer = audioGraph.GetNodeInfo(idChannelMixerNode);
                    unit3DMixer = audioGraph.GetNodeInfo(id3DMixerNode);
                    
                    // Set the mixers' output formats (the stream format is propagated along the linked input during the graph initialization)
                    var desiredSampleRate = (engine.AudioSampleRate != 0) ? engine.AudioSampleRate : AudioUnitOutputSampleRate;
                    unit3DMixer.SetAudioFormat(CreateLinear16BitsPcm(2, desiredSampleRate), AudioUnitScopeType.Output);
                    unitChannelMixer.SetAudioFormat(CreateLinear16BitsPcm(2, desiredSampleRate), AudioUnitScopeType.Output);

                    // set the element count to the max number of possible tracks before initializing the audio graph
                    CheckUnitStatus(unitChannelMixer.SetElementCount(AudioUnitScopeType.Input, MaxNumberOfTracks+1), string.Format("Failed to set element count on ChannelMixer [{0}]", MaxNumberOfTracks+1)); // +1 for the 3DMixer output
                    CheckUnitStatus(unit3DMixer.SetElementCount(AudioUnitScopeType.Input, MaxNumberOfTracks), string.Format("Failed to set element count on 3DMixer [{0}]", MaxNumberOfTracks));

                    // set a null renderer callback to the channel and 3d mixer input bus
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                    {
                        CheckUnitStatus((AudioUnitStatus)SetInputRenderCallbackToNull(unit3DMixer.Handle, i), "Failed to set the render callback");
                        CheckUnitStatus((AudioUnitStatus)SetInputRenderCallbackToNull(unitChannelMixer.Handle, i), "Failed to set the render callback");
                    }
                    
                    // Initialize the graph (validation of the topology)
                    CheckGraphError(audioGraph.Initialize(), "The audio graph initialization failed.");

                    // Start audio rendering
                    CheckGraphError(audioGraph.Start(), "Audio Graph could not start.");

                    // disable all the input bus at the beginning
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                    {
                        CheckUnitStatus(unitChannelMixer.SetParameter(AudioUnitParameterType.MultiChannelMixerEnable, 0f, AudioUnitScopeType.Input, i), "Failed to enable/disable the ChannelMixerInput.");
                        CheckUnitStatus(unit3DMixer.SetParameter(AudioUnitParameterType.Mixer3DEnable, 0f, AudioUnitScopeType.Input, i), "Failed to enable/disable the 3DMixerInput.");
                    }

                    // At initialization all UnitElement are available.
                    availableMixerBusIndices = new Queue<uint>();
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                        availableMixerBusIndices.Enqueue(i);
                }
                ++nbOfInstances;

                // Create a AudioDataRendererInfo for the sounds.
                pAudioDataRendererInfo = (AudioDataRendererInfo*)Utilities.AllocateClearedMemory(sizeof(AudioDataRendererInfo));
                pAudioDataRendererInfo->HandleChannelMixer = unitChannelMixer.Handle;
                pAudioDataRendererInfo->Handle3DMixer = unit3DMixer.Handle;
            }
        }
Пример #25
0
        internal void Attach(AudioEngine engine)
        {
            AttachEngine(engine);

            Name = "Sound Effect " + Interlocked.Add(ref soundEffectCreationCount, 1);

            // register the sound to the AudioEngine so that it will be properly freed if AudioEngine is disposed before this.
            AudioEngine.RegisterSound(this);
        }
Пример #26
0
        // called on dispose
        protected override void Destroy()
        {
            Game.Activated -= OnActivated;
            Game.Deactivated -= OnDeactivated;

            base.Destroy();

            lock (AudioEngineStaticLock)
            {
                AudioEngine = null;
                var count = ((IReferencable)audioEngineSingleton).Release();
                if (count == 0)
                {
                    audioEngineSingleton = null;
                }
            }
        }
Пример #27
0
        internal override void StopImpl()
        {
            ShouldExitLoop = false;

            AudioEngine.SubmitMusicActionRequest(new SoundMusicActionRequest(this, SoundMusicAction.Stop));
        }
Пример #28
0
 internal override void UpdateVolume()
 {
     AudioEngine.SubmitMusicActionRequest(new SoundMusicActionRequest(this, SoundMusicAction.Volume));
 }
Пример #29
0
        // called on dispose
        protected override void Destroy()
        {
            Game.Activated -= OnActivated;
            Game.Deactivated -= OnDeactivated;

            base.Destroy();

            AudioEngine.Dispose();
            AudioEngine = null;
        }
Пример #30
0
        public AudioVoice(AudioEngine engine, SoundEffectInstance effectInstance, WaveFormat desiredFormat)
        {
            if (engine == null)
            {
                throw new ArgumentNullException("engine");
            }
            if (desiredFormat == null)
            {
                throw new ArgumentNullException("desiredFormat");
            }

            audioEngine         = engine;
            soundEffectInstance = effectInstance;
            waveFormat          = desiredFormat;
            BusIndexMixer       = uint.MaxValue;

            if (desiredFormat.BitsPerSample != 16)
            {
                throw new AudioSystemInternalException("Invalid Audio Format. " + desiredFormat.BitsPerSample + " bits by sample is not supported.");
            }

            lock (StaticMembersLock)
            {
                if (nbOfInstances == 0)
                {
                    // Create the Audio Graph
                    audioGraph = new AUGraph();

                    // Open the graph (does not initialize it yet)
                    audioGraph.Open();

                    // Create the AudioComponentDescrition corresponding to the IO Remote output and MultiChannelMixer
                    var remoteInOutComponentDesc       = AudioComponentDescription.CreateOutput(AudioTypeOutput.Remote);
                    var mixerMultiChannelComponentDesc = AudioComponentDescription.CreateMixer(AudioTypeMixer.MultiChannel);
                    var mixer3DComponentDesc           = AudioComponentDescription.CreateMixer(AudioTypeMixer.Spacial);

                    // Add the Audio Unit nodes to the AudioGraph
                    var outputUnitNodeId   = audioGraph.AddNode(remoteInOutComponentDesc);
                    var idChannelMixerNode = audioGraph.AddNode(mixerMultiChannelComponentDesc);
                    var id3DMixerNode      = audioGraph.AddNode(mixer3DComponentDesc);

                    // Connect the nodes together
                    CheckGraphError(audioGraph.ConnnectNodeInput(idChannelMixerNode, 0, outputUnitNodeId, 0), "Connection of the graph node failed.");
                    CheckGraphError(audioGraph.ConnnectNodeInput(id3DMixerNode, 0, idChannelMixerNode, MaxNumberOfTracks), "Connection of the graph node failed.");

                    // Get the MixerUnit objects
                    unitChannelMixer = audioGraph.GetNodeInfo(idChannelMixerNode);
                    unit3DMixer      = audioGraph.GetNodeInfo(id3DMixerNode);

                    // Set the mixers' output formats (the stream format is propagated along the linked input during the graph initialization)
                    var desiredSampleRate = (engine.AudioSampleRate != 0) ? engine.AudioSampleRate : AudioUnitOutputSampleRate;
                    unit3DMixer.SetAudioFormat(CreateLinear16BitsPcm(2, desiredSampleRate), AudioUnitScopeType.Output);
                    unitChannelMixer.SetAudioFormat(CreateLinear16BitsPcm(2, desiredSampleRate), AudioUnitScopeType.Output);

                    // set the element count to the max number of possible tracks before initializing the audio graph
                    CheckUnitStatus(unitChannelMixer.SetElementCount(AudioUnitScopeType.Input, MaxNumberOfTracks + 1), string.Format("Failed to set element count on ChannelMixer [{0}]", MaxNumberOfTracks + 1)); // +1 for the 3DMixer output
                    CheckUnitStatus(unit3DMixer.SetElementCount(AudioUnitScopeType.Input, MaxNumberOfTracks), string.Format("Failed to set element count on 3DMixer [{0}]", MaxNumberOfTracks));

                    // set a null renderer callback to the channel and 3d mixer input bus
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                    {
                        CheckUnitStatus((AudioUnitStatus)SetInputRenderCallbackToNull(unit3DMixer.Handle, i), "Failed to set the render callback");
                        CheckUnitStatus((AudioUnitStatus)SetInputRenderCallbackToNull(unitChannelMixer.Handle, i), "Failed to set the render callback");
                    }

                    // Initialize the graph (validation of the topology)
                    CheckGraphError(audioGraph.Initialize(), "The audio graph initialization failed.");

                    // Start audio rendering
                    CheckGraphError(audioGraph.Start(), "Audio Graph could not start.");

                    // disable all the input bus at the beginning
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                    {
                        CheckUnitStatus(unitChannelMixer.SetParameter(AudioUnitParameterType.MultiChannelMixerEnable, 0f, AudioUnitScopeType.Input, i), "Failed to enable/disable the ChannelMixerInput.");
                        CheckUnitStatus(unit3DMixer.SetParameter(AudioUnitParameterType.Mixer3DEnable, 0f, AudioUnitScopeType.Input, i), "Failed to enable/disable the 3DMixerInput.");
                    }

                    // At initialization all UnitElement are available.
                    availableMixerBusIndices = new Queue <uint>();
                    for (uint i = 0; i < MaxNumberOfTracks; i++)
                    {
                        availableMixerBusIndices.Enqueue(i);
                    }
                }
                ++nbOfInstances;

                // Create a AudioDataRendererInfo for the sounds.
                pAudioDataRendererInfo = (AudioDataRendererInfo *)Utilities.AllocateClearedMemory(sizeof(AudioDataRendererInfo));
                pAudioDataRendererInfo->HandleChannelMixer = unitChannelMixer.Handle;
                pAudioDataRendererInfo->Handle3DMixer      = unit3DMixer.Handle;
            }
        }