private void PlatformInitializeIeeeFloat(
            ReadOnlySpan <byte> data, int sampleRate, AudioChannels channels, int loopStart, int loopLength)
        {
            if (ALController.Get().SupportsFloat32)
            {
                var format = AudioLoader.GetSoundFormat(AudioLoader.FormatIeee, (int)channels, 32);
                SoundBuffer = ALBufferPool.Rent();
                SoundBuffer.BufferData(data, format, sampleRate);
            }
            else
            {
                var floatData = MemoryMarshal.Cast <byte, float>(data);
                int byteCount = floatData.Length * sizeof(short);

                string bufferTag = nameof(PlatformInitializeIeeeFloat);
                using (var buffer = RecyclableMemoryManager.Default.GetBuffer(byteCount, bufferTag))
                {
                    var largeBuffer = buffer.Buffer;

                    // If 32-bit IEEE float is not supported, convert to 16-bit signed PCM
                    AudioLoader.ConvertSingleToInt16(floatData, MemoryMarshal.Cast <byte, short>(largeBuffer));
                    PlatformInitializePcm(largeBuffer, 16, sampleRate, channels, loopStart, loopLength);
                }
            }
        }
        private void PlatformInitializeAdpcm(
            ReadOnlySpan <byte> data, int sampleRate, AudioChannels channels, int blockAlignment,
            int loopStart, int loopLength)
        {
            if (ALController.Get().SupportsAdpcm)
            {
                var format          = AudioLoader.GetSoundFormat(AudioLoader.FormatMsAdpcm, (int)channels, 0);
                int sampleAlignment = AudioLoader.SampleAlignment(format, blockAlignment);

                // Buffer length must be aligned with the block alignment
                int alignedCount = data.Length - (data.Length % blockAlignment);
                data = data.Slice(0, alignedCount);

                SoundBuffer = ALBufferPool.Rent();
                SoundBuffer.BufferData(data, format, sampleRate, sampleAlignment);
            }
            else
            {
                // If MS-ADPCM is not supported, convert to 16-bit signed PCM
                var pcmData = MemoryMarshal.AsBytes(
                    AudioLoader.ConvertMsAdpcmToPcm(data, (int)channels, blockAlignment).AsSpan());

                PlatformInitializePcm(pcmData, 16, sampleRate, channels, loopStart, loopLength);
            }
        }
        private void PlatformInitializePcm(
            ReadOnlySpan <byte> data, int sampleBits, int sampleRate, AudioChannels channels,
            int loopStart, int loopLength)
        {
            byte[]? largeBuffer = null;
            string?bufferTag = null;

            try
            {
                if (sampleBits == 24)
                {
                    // Convert 24-bit signed PCM to 16-bit signed PCM
                    largeBuffer = AudioLoader.Convert24To16(data, out bufferTag, out int size);
                    data        = largeBuffer.AsSpan(0, size);
                    sampleBits  = 16;
                }

                var format = AudioLoader.GetSoundFormat(AudioLoader.FormatPcm, (int)channels, sampleBits);
                SoundBuffer = ALBufferPool.Rent();
                SoundBuffer.BufferData(data, format, sampleRate);
            }
            finally
            {
                if (largeBuffer != null)
                {
                    RecyclableMemoryManager.Default.ReturnBuffer(largeBuffer, bufferTag);
                }
            }
        }
        private void PlatformSubmitBuffer <T>(ReadOnlySpan <T> data, AudioDepth depth)
            where T : unmanaged
        {
            // Bind the data
            ALFormat alFormat = ALHelper.GetALFormat(_channels, depth);
            var      buffer   = ALBufferPool.Rent();

            buffer.BufferData(data, alFormat, _sampleRate);

            // Queue the buffer
            AL.SourceQueueBuffer(SourceId.Value, buffer.BufferId);
            ALHelper.CheckError("Failed to queue buffer.");

            lock (_queuedBuffers)
                _queuedBuffers.Enqueue(buffer);

            // If the source has run out of buffers, restart it
            var sourceState = AL.GetSourceState(SourceId.Value);

            if (_state == SoundState.Playing && sourceState == ALSourceState.Stopped)
            {
                AL.SourcePlay(SourceId.Value);
                ALHelper.CheckError("Failed to resume source playback.");
            }
        }
        private void PlatformUpdateQueue()
        {
            // Get the completed buffers
            AL.GetSource(SourceId.Value, ALGetSourcei.BuffersProcessed, out int numBuffers);
            ALHelper.CheckError("Failed to get processed buffer count.");

            // Unqueue them
            if (numBuffers > 0)
            {
                AL.SourceUnqueueBuffers(SourceId.Value, numBuffers);
                ALHelper.CheckError("Failed to unqueue buffers.");

                lock (_queuedBuffers)
                {
                    for (int i = 0; i < numBuffers; i++)
                    {
                        var buffer = _queuedBuffers.Dequeue();
                        ALBufferPool.Return(buffer);
                    }
                }
            }

            // Raise the event for each removed buffer, if needed
            for (int i = 0; i < numBuffers; i++)
            {
                CheckBufferCount();
            }
        }
        private void PlatformStop()
        {
            AL.SourceStop(SourceId.Value);
            ALHelper.CheckError("Failed to stop the source.");

            // Remove all queued buffers
            AL.Source(SourceId.Value, ALSourcei.Buffer, 0);
            ALHelper.CheckError("Failed to unbind the buffer.");

            lock (_queuedBuffers)
            {
                while (_queuedBuffers.Count > 0)
                {
                    var buffer = _queuedBuffers.Dequeue();
                    ALBufferPool.Return(buffer);
                }
            }
        }
        private void PlatformDispose(bool disposing)
        {
            // SFXI disposal handles buffer detachment and source recycling
            base.Dispose(disposing);

            if (disposing)
            {
                lock (_queuedBuffers)
                {
                    while (_queuedBuffers.Count > 0)
                    {
                        var buffer = _queuedBuffers.Dequeue();
                        ALBufferPool.Return(buffer);
                    }
                }
            }
            DynamicSoundEffectInstanceManager.RemoveInstance(this);
        }
        private void PlatformInitializeIma4(
            ReadOnlySpan <byte> data, int sampleRate, AudioChannels channels, int blockAlignment,
            int loopStart, int loopLength)
        {
            if (ALController.Get().SupportsIma4)
            {
                var format          = AudioLoader.GetSoundFormat(AudioLoader.FormatIma4, (int)channels, 0);
                int sampleAlignment = AudioLoader.SampleAlignment(format, blockAlignment);
                SoundBuffer = ALBufferPool.Rent();
                SoundBuffer.BufferData(data, format, sampleRate, sampleAlignment);
            }
            else
            {
                // If IMA4 is not supported, convert to 16-bit signed PCM
                data = MemoryMarshal.AsBytes(
                    AudioLoader.ConvertIma4ToPcm(data, (int)channels, blockAlignment).AsSpan());

                PlatformInitializePcm(data, 16, sampleRate, channels, loopStart, loopLength);
            }
        }