Exemple #1
0
        /// <summary>
        /// Start or resume playing the current <see cref="Sound"/> object.
        /// </summary>
        protected override void Play()
        {
            if (Handle <= 0)
            {
                Logger.Warning("SoundSource Handle is not created.\n" +
                               "Use SoundSystem.Play() to play a SoundSource.");

                return;
            }

            // Attach the sound if it's not attached yet
            // In case the first time call or the Source handle is replaced due to recycle
            int buffer = 0;

            ALChecker.Check(() => AL.GetSource(Handle, ALGetSourcei.Buffer, out buffer));

            if (!Buffer.IsAttached(this) || Buffer.Handle != buffer)
            {
                // Only attach if its not attached
                if (!Buffer.IsAttached(this))
                {
                    Buffer.AttachSound(this);
                }

                ALChecker.Check(() => AL.Source(Handle, ALSourcei.Buffer, _buffer.Handle));
            }

            ALChecker.Check(() => AL.SourcePlay(Handle));
        }
Exemple #2
0
        static AudioDevice()
        {
            // Create audio context (which create the ALCdevice and ALCcontext)
            _context = new AudioContext();
            _context.MakeCurrent();

            // Configure default state of listener
            _listenerVolume    = 100f;
            _listenerPosition  = new Vector3(0f, 0f, 0f);
            _listenerDirection = new Vector3(0f, 0f, -1f);
            _listenerUpVector  = new Vector3(0f, 1f, 0f);


            // Apply the listener properties the user might have set
            float[] orientation = { _listenerDirection.X,
                                    _listenerDirection.Y,
                                    _listenerDirection.Z,
                                    _listenerUpVector.X,
                                    _listenerUpVector.Y,
                                    _listenerUpVector.Z };

            ALChecker.Check(() => AL.Listener(ALListenerf.Gain, _listenerVolume * 0.01f));
            ALChecker.Check(() => AL.Listener(ALListener3f.Position, _listenerPosition.X, _listenerPosition.Y, _listenerPosition.Z));
            ALChecker.Check(() => AL.Listener(ALListenerfv.Orientation, ref orientation));

            // Dispose Audio Device when exiting application
            AppDomain.CurrentDomain.ProcessExit += (s, e) => Free();
        }
Exemple #3
0
        /// <summary>
        /// Update the <see cref="SoundSystem"/>.
        /// </summary>
        public void Update()
        {
            // Audio Device no longer active?
            if (AudioDevice.IsDisposed)
            {
                return;
            }

            // Remove and dispose unused sources
            for (int i = _sources.Count - 1; i >= 0; i--)
            {
                if (_sources[i] == null)
                {
                    _sources.RemoveAt(i);
                    continue;
                }

                // Check whether the specified source has valid handle
                bool valid = false;
                ALChecker.Check(() => valid = AL.IsSource(_sources[i].Handle));

                if (!valid || (_sources[i].Status == SoundStatus.Stopped && !_sources[i].IsLooping))
                {
                    // No need to dispose invalid source handle
                    if (valid)
                    {
                        _sources[i].Dispose();
                    }
                    _sources.RemoveAt(i);
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Play the <see cref="Sound"/>.
        /// When the <see cref="Sound"/> is provided with valid buffer data,
        /// <see cref="SoundBuffer.IsValid"/> property will return true.
        /// </summary>
        public void Play()
        {
            // Just resume if the sounds is paused
            if (State == SoundState.Paused)
            {
                Resume();
                return;
            }

            // Make sure the sound is well-queued
            if (Deferred || !IsReady)
            {
                Initialize();
            }
            else
            {
                SoundSystem.Instance.Add(this);
            }

            // Let's rock!
            ALChecker.Check(() => AL.SourcePlay(Source));

            // Triger the event
            if (SoundStarted != null)
            {
                SoundStarted(this, EventArgs.Empty);
            }
        }
Exemple #5
0
        /// <summary>
        /// Initialize the sound buffer with a <see cref="SoundDecoder"/>.
        /// </summary>
        /// <param name="decoder"><see cref="SoundDecoder"/> containing audio information and sample to fill the current buffer.</param>
        private void Initialize(SoundDecoder decoder)
        {
            // Retrieve the decoder
            Decoder = decoder;

            // Retrieve sound parameters
            SampleCount  = decoder.SampleCount;
            ChannelCount = decoder.ChannelCount;
            SampleRate   = decoder.SampleRate;

            // Compute duration
            Duration = TimeSpan.FromSeconds((float)SampleCount / SampleRate / ChannelCount);

            // Fill entire buffer immediately if its a sample mode
            if (Mode == BufferMode.Sample)
            {
                // Create the buffer handle
                Handle = ALChecker.Check(() => AL.GenBuffer());

                // Decode the samples
                var samples = new short[SampleCount];
                if (decoder.Decode(samples, SampleCount) == SampleCount)
                {
                    // Update the internal buffer with the new samples
                    LoadBuffer(samples, ChannelCount, SampleRate);
                }
                else
                {
                    throw new Exception("Failed to initialize Sample Buffer");
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Queue the Buffer Data.
        /// </summary>
        /// <param name="reader">Specify the <see cref="ISoundStreamReader"/>, be sure that the stream reader is able to handle the provided buffer.</param>
        /// <param name="precache">Specify whether the buffer should be pre-cached.</param>
        protected void QueueBuffer(ISoundStreamReader reader, bool precache = false)
        {
            // Reset position of the Stream
            Stream.Seek(0, SeekOrigin.Begin);

            // Use specified reader
            Reader = reader;

            if (precache)
            {
                // Fill first buffer synchronously
                Reader.BufferData(SoundSystem.Instance.BufferSize, Buffers[0]);

                // Here we attach the Source to the Buffer
                ALChecker.Check(() => AL.SourceQueueBuffer(Source, Buffers[0]));

                // Schedule the others buffer asynchronously as the game update
                if (Deferred)
                {
                    SoundSystem.Instance.Add(this);
                }
                else
                {
                    SoundSystem.Instance.AddUndeferredSource(Source);
                }
            }

            IsReady = true;
        }
Exemple #7
0
        /// <summary>
        /// Stop the <see cref="Sound"/>.
        /// </summary>
        public void Stop()
        {
            // This may cause OpenAL error if the Source is not valid.
            ALChecker.Check(() => AL.SourceStop(Source));
            Reader.DecodeTime = 0;

            if (!Deferred)
            {
                SoundSystem.Instance.RemoveUndeferredSource(Source);
                Deferred = true;
            }

            if (SoundStopped != null)
            {
                SoundStopped(this, EventArgs.Empty);
            }

            // In this case, we really need to check this first
            // Whether the Source is valid
            bool isValidSource = AL.IsSource(Source);

            ALChecker.CheckError();
            if (isValidSource)
            {
                // TODO: Should we really need to dispose the source here?
                ALChecker.Check(() => AL.DeleteSource(Source));
                Source = -1; // Set to invalid Source to make the next cycle source available
            }
        }
Exemple #8
0
        private bool FillAndPushBuffer(int bufferNum, bool immediateLoop = false)
        {
            bool requestStop = false;

            // Acquire audio data
            short[] samples = null;
            for (int retryCount = 0; !OnGetData(out samples) && (retryCount < BUFFER_RETRIES); ++retryCount)
            {
                // Mark the buffer as the last one (so that we know when to reset the playing position)
                _endBuffers[bufferNum] = true;

                // Check if the stream must loop or stop
                if (!_loop)
                {
                    // Not looping: request stop
                    requestStop = true;
                    break;
                }

                // Return to the beginning of the stream source
                OnSeek(TimeSpan.Zero);

                // If we got data, break and process it, else try to fill the buffer once again
                if (samples != null && (samples.Length > 0))
                {
                    break;
                }

                // If immediateLoop is specified, we have to immediately adjust the sample count
                if (immediateLoop)
                {
                    // We just tried to begin preloading at EOF: reset the sample count
                    _processed             = 0;
                    _endBuffers[bufferNum] = false;
                }

                // We're a looping sound that got no data, so we retry onGetData()
            }

            // Fill the buffer if some data was returned
            if (samples != null && samples.Length > 0)
            {
                int buffer = _buffers[bufferNum];

                // Fill the buffer
                int size = samples.Length * sizeof(short);
                ALChecker.Check(() => AL.BufferData(buffer, _format, samples, size, _sampleRate));

                // Push it into the sound queue
                ALChecker.Check(() => AL.SourceQueueBuffer(Handle, buffer));
            }
            else
            {
                // If we get here, we most likely ran out of retries
                requestStop = true;
            }

            return(requestStop);
        }
Exemple #9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SoundSource"/> class.
        /// </summary>
        public SoundSource()
        {
            // Ensure that AudioDevice is initialized
            AudioDevice.Initialize();

            ALChecker.Check(() => _source = AL.GenSource());
            ALChecker.Check(() => AL.Source(_source, ALSourcei.Buffer, 0));
        }
        /// <summary>
        /// Process buffer of specified index.
        /// </summary>
        /// <param name="index">Index of buffer to process.</param>
        /// <param name="immediateLoop">Treat empty buffers as spent, and act on loops immediately.</param>
        /// <returns><c>true</c> if the stream source has requested to stop; otherwise, <c>false</c></returns>
        private bool ProcessBuffer(int index, bool immediateLoop = false)
        {
            short[] samples;
            bool    terminating = false;

            for (int retry = 0; !GetStreamData(out samples) && retry < BufferRetries; ++retry)
            {
                // Check if the stream must loop or stop
                if (!IsLooping)
                {
                    if (samples != null && samples.Length != 0)
                    {
                        bufferLoop[index] = 0;
                    }

                    terminating = true;
                    break;
                }

                // Return to the beginning or loop-start of the stream source using GetLoopPoint(), and store the result in the buffer seek array
                // This marks the buffer as the "last" one (so that we know where to reset the playing position)
                bufferLoop[index] = GetLoopPoint();

                // If we got data, break and process it, else try to fill the buffer once again
                if (samples != null && samples.Length != 0)
                {
                    break;
                }

                // If immediateLoop is specified, we have to immediately adjust the sample count
                if (immediateLoop && (bufferLoop[index] != -1))
                {
                    // We just tried to begin preloading at EOF or Loop End: reset the sample count
                    processed         = bufferLoop[index];
                    bufferLoop[index] = -1;
                }
            }

            // Fill the buffer if some data was returned
            if (samples != null && samples.Length != 0)
            {
                int buffer = buffers[index];

                // Fill the buffer
                int size = samples.Length * sizeof(short);
                ALChecker.Check(() => AL.BufferData(buffer, format, samples, size, SampleRate));

                // Push it into the sound queue
                ALChecker.Check(() => AL.SourceQueueBuffer(Handle, buffer));
            }
            else
            {
                // If we get here, we most likely ran out of retries
                terminating = true;
            }

            return(terminating);
        }
Exemple #11
0
        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="Sound"/> and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            Decoder?.Dispose();
            if (Handle > 0)
            {
                ALChecker.Check(() => AL.DeleteBuffer(Handle));
            }
        }
Exemple #12
0
        public bool BufferData(int bufferSize, int bufferId)
        {
            byte[] readSampleBuffer = new byte[SoundSystem.Instance.BufferSize];
            int    readSamples      = Read(readSampleBuffer, 0, bufferSize);

            ALChecker.Check(() => AL.BufferData(bufferId, _alFormat, readSampleBuffer,
                                                readSamples, SampleRate));

            return(readSamples != bufferSize);
        }
Exemple #13
0
        /// <summary>
        /// Start or resume playing the <see cref="SoundSource"/> object.
        /// </summary>
        /// <param name="source">The <see cref="SoundSource"/> to play or resume.</param>
        public virtual void Play(SoundSource source)
        {
            // Audio Device no longer active?
            if (AudioDevice.IsDisposed)
            {
                throw new ObjectDisposedException("AudioDevice");
            }

            // Nothing to play?
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            // Check whether the number of playing sounds is exceed the limit
            if (_sources.Count >= MAX_SOURCE_COUNT)
            {
                // Force to recycle unused source
                Update();

                // Check again if it exceed the limit
                if (_sources.Count >= MAX_SOURCE_COUNT)
                {
                    // It still exceed and throw the exception
                    throw new InvalidOperationException("Failed to play the source:\n" +
                                                        "The number of playing sources is exceed the limit.");
                }
            }

            // Create the source handle, in case it is first call
            bool valid = false;

            ALChecker.Check(() => valid = AL.IsSource(source.Handle));
            if (!valid)
            {
                int handle = 0;
                ALChecker.Check(() => handle = AL.GenSource());
                ALChecker.Check(() => AL.Source(handle, ALSourcei.Buffer, 0));

                source.Handle = handle;
            }

            // Play the sound
            try
            {
                _play.Invoke(source, null);

                // Add to the list
                _sources.Add(source);
            }
            catch (Exception ex)
            {
                throw ex.InnerException;
            }
        }
Exemple #14
0
        /// <summary>
        /// Stop playing the current <see cref="Sound"/> object.
        /// </summary>
        protected override void Stop()
        {
            if (Handle <= 0)
            {
                Logger.Warning("SoundSource Handle is not created.\n" +
                               "Use SoundSystem.Pause() to play a SoundSource.");

                return;
            }

            ALChecker.Check(() => AL.SourceStop(Handle));
        }
Exemple #15
0
        /// <summary>
        /// Initialize the Native Handle, De-queue existing buffer and (re)Queue the buffer of the <see cref="SoundBuffer"/>.
        /// </summary>
        protected void Initialize()
        {
            // Check whether the buffer is already initializing state
            if (IsPreparing)
            {
                return;
            }

            // Check whether the current Source is valid
            bool isValidSource = AL.IsSource(Source);

            ALChecker.CheckError();
            if (!isValidSource || Source == -1)
            {
                // Get unused Source from SoundSystem
                Source = SoundSystem.Instance.GetAvailableSource();
            }

            // We don't have clue which buffer id that being attached to the source right now
            // So we don't attach (queue) the buffer to the source now
            // We will attach (queue) it when we are (really) going to queue the buffer (read: Play())

            // Initialize() call will dequeue current buffer and queue the buffer when its required

            // Check the sound state
            switch (State)
            {
            // Sound is already playing, no need preparation(?)
            case SoundState.Paused:
            case SoundState.Playing:
                return;

            // The sounds is already stopped (which mean its been played once or more before)
            case SoundState.Stopped:
                // Reset to 0 Position
                Reader.DecodeTime = 0;
                // Dequeue remaining buffer before we (re)queue the buffer
                DequeueBuffer();
                // We are not ready to start yet, we haven't queue the buffer
                IsReady = false;

                break;
            }

            // Check whether our buffer is ready
            if (!IsReady)
            {
                // If its not ready, lets queue them
                IsPreparing = true;  // set the flag to prevent requeue during process
                QueueBuffer(precache: true);
                IsPreparing = false; // done
            }
        }
Exemple #16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SoundBuffer"/> class.
        /// </summary>
        public SoundBuffer()
        {
            // Ensure that AudioDevice is initialized
            AudioDevice.Initialize();

            _samples  = new short[0];
            _sounds   = new List <Sound>();
            _duration = TimeSpan.Zero;

            // Create the buffer
            ALChecker.Check(() => _buffer = AL.GenBuffer());
        }
        internal int GetAvailableSource()
        {
            for (int i = 0; i < _sources.Length; i++)
            {
                bool isValidSource = AL.IsSource(_sources[i]);
                ALChecker.CheckError();

                if (isValidSource)
                {
                    // Some sources are probably used by another sounds
                    // Return the one that not in use

                    // Identify source state
                    ALSourceState state = AL.GetSourceState(_sources[i]);
                    ALChecker.CheckError();

                    // Do not use un-deferred source
                    if (_unDeferredSources.Contains(_sources[i]) && state == ALSourceState.Initial)
                    {
                        continue;
                    }
                    else if (_unDeferredSources.Contains(_sources[i]) && state == ALSourceState.Stopped)
                    {
                        _unDeferredSources.Remove(_sources[i]);
                    }

                    // No sounds using it or no longer in use, use it
                    if (state == ALSourceState.Initial || (state == ALSourceState.Stopped))
                    {
                        return(_sources[i]);
                    }
                    // Source is in use by a sound, find another one
                    else if (state == ALSourceState.Paused || state == ALSourceState.Playing)
                    {
                        continue;
                    }
                }
                else
                {
                    // Not a source (anymore..?)
                    // Generate and use it
                    _sources[i] = AL.GenSource();

                    // Since it's newly generated, it must be unused source
                    return(_sources[i]);
                }
            }

            // All sources are used at the moment...
            // Return invalid source
            return(-1);
        }
Exemple #18
0
        internal void ResetBuffer()
        {
            // First stop the sound in case it is playing
            Stop();

            // Detach the buffer
            if (_buffer != null)
            {
                ALChecker.Check(() => AL.Source(Handle, ALSourcei.Buffer, 0));
                _buffer.DetachSound(this);
                _buffer = null;
            }
        }
Exemple #19
0
        /// <summary>
        /// Resume the <see cref="Sound"/>.
        /// </summary>
        public void Resume()
        {
            // This may cause OpenAL error if the Source is not valid.
            if (State == SoundState.Paused)
            {
                ALChecker.Check(() => AL.SourcePlay(Source));

                if (SoundResumed != null)
                {
                    SoundResumed(this, EventArgs.Empty);
                }
            }
        }
Exemple #20
0
        /// <summary>
        /// Pause the current <see cref="SoundStream"/> object.
        /// </summary>
        protected override void Pause()
        {
            lock (_mutex)
            {
                if (!_isStreaming)
                {
                    return;
                }

                _state = SoundStatus.Paused;
            }

            ALChecker.Check(() => AL.SourcePause(Handle));
        }
        /// <summary>
        /// Pause the playing <see cref="SoundStream"/>.
        /// </summary>
        /// <inheritdoc/>
        protected internal override void Pause()
        {
            lock (mutex)
            {
                if (!streaming)
                {
                    return;
                }

                state = SoundStatus.Paused;
            }

            ALChecker.Check(() => AL.SourcePause(Handle));
        }
        public bool BufferData(int bufferSize, int bufferId)
        {
            float[] readSampleBuffer = new float[SoundSystem.Instance.BufferSize];
            short[] castBuffer       = new short[SoundSystem.Instance.BufferSize];

            int readSamples = ReadSamples(readSampleBuffer, 0, bufferSize);

            CastBuffer(readSampleBuffer, castBuffer, readSamples);

            ALChecker.Check(() => AL.BufferData(bufferId, Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer,
                                                readSamples * sizeof(short), SampleRate));

            return(readSamples != bufferSize);
        }
        /// <summary>
        /// Clear all the audio buffers and empty the playing queue.
        /// </summary>
        private void ClearQueue()
        {
            // Reset the playing position
            processed = 0;

            // Get the number of buffers that still in queue then enqueue all of them
            int queued = 0;

            ALChecker.Check(() => AL.GetSource(Handle, ALGetSourcei.BuffersQueued, out queued));
            ALChecker.Check(() => queued > 0 ? AL.SourceUnqueueBuffers(Handle, queued) : new int[0]);

            // Detach and delete the buffers
            ALChecker.Check(() => AL.Source(Handle, ALSourcei.Buffer, 0));
            ALChecker.Check(() => AL.DeleteBuffers(buffers));
        }
Exemple #24
0
        /// <summary>
        /// Update <see cref="Sound"/> with filled audio samples and given channel count and sample rate.
        /// </summary>
        /// <param name="samples">The audio sample to fill the buffer.</param>
        /// <param name="channelCount">The number of audio channels.</param>
        /// <param name="sampleRate">The number of sample rate.</param>
        private void LoadBuffer(short[] samples, int channelCount, int sampleRate)
        {
            // Check audio properties
            if (channelCount == 0 || sampleRate == 0 || samples == null || samples.Length == 0)
            {
                throw new ArgumentNullException();
            }

            // Fill the buffer
            int size = samples.Length * sizeof(short);

            ALChecker.Check(() => AL.BufferData(Handle, Format, samples, size, sampleRate));

            Decoder?.Dispose();
        }
Exemple #25
0
        private void ClearQueue()
        {
            // Get the number of buffers still in the queue
            int nbQueued = 0;

            ALChecker.Check(() => AL.GetSource(Handle, ALGetSourcei.BuffersQueued, out nbQueued));

            // Dequeue them all
            int buffer = 0;

            for (int i = 0; i < nbQueued; ++i)
            {
                ALChecker.Check(() => buffer = AL.SourceUnqueueBuffer(Handle));
            }
        }
        /// <summary>
        /// Initialize the <see cref="SoundSystem"/>.
        /// </summary>
        /// <param name="bufferSize"></param>
        public void Initialize(int bufferSize = DEFAULT_BUFFER_SIZE)
        {
            if (_context == null)
            {
                _context = new ALContext();
            }

            BufferSize = bufferSize;

            XRam = new XRamExtension();
            Efx  = new EffectsExtension();

            // Init empty sources
            _sources = AL.GenSources(MAXIMUM_NUMBER_OF_SOURCES);
            ALChecker.CheckError();
        }
Exemple #27
0
        /// <summary>
        /// Queue the Buffer Data.
        /// </summary>
        /// <param name="precache">Specify whether the buffer should be pre-cached.</param>
        protected void QueueBuffer(bool precache = false)
        {
            // Reset position of the Stream
            Stream.Seek(0, SeekOrigin.Begin);

            // Use approriate Sound Stream Reader
            if (Reader == null)
            {
                if (Format == SoundFormat.Vorbis)
                {
                    Reader = new VorbisStreamReader(this, false);
                }
                else if (Format == SoundFormat.Wav)
                {
                    Reader = new WaveStreamReader(this, false);
                }
                else if (Format == SoundFormat.Unknown)
                {
                    // You need to implement your own Sound Stream Reader
                    // Inherit ISoundStreamReader and pass it via QueueBuffer(ISoundStreamReader, bool)
                    // Or set the implementation under SoundBuffer.Reader property
                    throw new NotSupportedException("Unknown sound data buffer format.");
                }
            }

            if (precache)
            {
                // Fill first buffer synchronously
                Reader.BufferData(SoundSystem.Instance.BufferSize, Buffers[0]);

                // Here we attach the Source to the Buffer
                ALChecker.Check(() => AL.SourceQueueBuffer(Source, Buffers[0]));

                // Schedule the others buffer asynchronously as the game update
                if (Deferred)
                {
                    SoundSystem.Instance.Add(this);
                }
                else
                {
                    SoundSystem.Instance.AddUndeferredSource(Source);
                }
            }

            IsReady = true;
        }
Exemple #28
0
        /// <summary>
        /// Start or resume playing current <see cref="SoundStream"/> object.
        /// </summary>
        protected override void Play()
        {
            // Check if the sound parameters have been set
            if (_format == 0)
            {
                throw new InvalidOperationException(
                          "Audio parameters must be initialized before played.");
            }

            bool        isStreaming = false;
            SoundStatus state       = SoundStatus.Stopped;

            lock (_mutex)
            {
                isStreaming = _isStreaming;
                state       = _state;
            }


            if (isStreaming && (state == SoundStatus.Paused))
            {
                // If the sound is paused, resume it
                lock (_mutex)
                {
                    _state = SoundStatus.Playing;
                    ALChecker.Check(() => AL.SourcePlay(Handle));
                }

                return;
            }
            else if (isStreaming && (state == SoundStatus.Playing))
            {
                // If the sound is playing, stop it and continue as if it was stopped
                Stop();
            }

            // Move to the beginning
            OnSeek(TimeSpan.Zero);

            // Start updating the stream in a separate thread to avoid blocking the application
            _processed   = 0;
            _isStreaming = true;
            _state       = SoundStatus.Playing;

            _thread.Start();
        }
Exemple #29
0
        private bool FillAndPushBuffer(int bufferNum)
        {
            bool requestStop = false;

            // Acquire audio data
            short[] samples = null;
            if (!OnGetData(out samples))
            {
                // Mark the buffer as the last one (so that we know when to reset the playing position)
                _endBuffers[bufferNum] = true;

                // Check if the stream must loop or stop
                if (_loop)
                {
                    // Return to the beginning of the stream source
                    OnSeek(TimeSpan.Zero);

                    // If we previously had no data, try to fill the buffer once again
                    if (samples == null || (samples.Length == 0))
                    {
                        return(FillAndPushBuffer(bufferNum));
                    }
                }
                else
                {
                    // Not looping: request stop
                    requestStop = true;
                }
            }

            // Fill the buffer if some data was returned
            if (samples != null && samples.Length > 0)
            {
                int buffer = _buffers[bufferNum];

                // Fill the buffer
                int size = samples.Length * sizeof(short);
                ALChecker.Check(() => AL.BufferData(buffer, _format, samples, size, _sampleRate));

                // Push it into the sound queue
                ALChecker.Check(() => AL.SourceQueueBuffer(Handle, buffer));
            }

            return(requestStop);
        }
Exemple #30
0
        /// <summary>
        /// Generate or retrieve available OpenAL Source Handle from the source pool.
        /// </summary>
        /// <returns>OpenAL Source Handle.</returns>
        private int GenSource()
        {
            // Reuse stopped channel
            var channel = channels.FirstOrDefault(ch => ch.Status == SoundStatus.Stopped);

            if (channel != null)
            {
                return(Enqueue(channel)?.Handle ?? throw new Exception("Failed to retrieve available channel"));
            }
            else if (channels.Count < MaxSource)
            {
                // No stopped channel available, generate one as long the pool still below the limit
                return(ALChecker.Check(() => AL.GenSource()));
            }

            // No stopped channel available and the source pool is already at its limit
            throw new OutOfMemoryException("Insufficient audio source handles.");
        }