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 static RecyclableBuffer LoadVorbis(
            Stream stream, out ALFormat format, out int frequency, out int channels,
            out int blockAlignment, out int bitsPerSample, out int samplesPerBlock, out int sampleCount)
        {
            RecyclableBuffer?result = null;
            var reader = new VorbisReader(stream, leaveOpen: false);

            try
            {
                bool useFloat   = ALController.Get().SupportsFloat32;
                int  sampleSize = useFloat ? sizeof(float) : sizeof(short);

                channels = reader.Channels;
                if (channels == 1)
                {
                    format = useFloat ? ALFormat.MonoFloat32 : ALFormat.Mono16;
                }
                else if (channels == 2)
                {
                    format = useFloat ? ALFormat.StereoFloat32 : ALFormat.Stereo16;
                }
                else
                {
                    throw new NotSupportedException("Only mono and stereo is supported.");
                }

                sampleCount     = (int)reader.TotalSamples;
                frequency       = reader.SampleRate;
                blockAlignment  = 0;
                samplesPerBlock = 0;
                bitsPerSample   = sampleSize * 8;

                long outputBytes = sampleCount * channels * sampleSize;
                if (outputBytes > int.MaxValue)
                {
                    throw new InvalidDataException("Size of decoded audio data exceeds " + int.MaxValue + " bytes.");
                }

                result = RecyclableMemoryManager.Default.GetBuffer((int)outputBytes, "Vorbis audio data");

                var resultSpan       = result.AsSpan();
                int totalSamplesRead = 0;
                int samplesRead;

                // Both paths allocate around 4096 stack bytes for buffers.
                if (useFloat)
                {
                    Span <float> sampleBuffer      = stackalloc float[1024];
                    Span <byte>  sampleBufferBytes = MemoryMarshal.AsBytes(sampleBuffer);

                    // we can copy directly to output
                    while ((samplesRead = reader.ReadSamples(sampleBuffer)) > 0)
                    {
                        Span <byte> bytes = sampleBufferBytes.Slice(0, samplesRead * sizeof(float));
                        bytes.CopyTo(resultSpan);
                        resultSpan        = resultSpan[bytes.Length..];
        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);
            }
        }
Example #5
0
        public void BufferData <T>(
            ReadOnlySpan <T> data, ALFormat format, int sampleRate, int sampleAlignment = 0)
            where T : unmanaged
        {
            AssertNotDisposed();

            var controller = ALController.Get();

            if (!controller.SupportsFloat32 && (format == ALFormat.MonoFloat32 || format == ALFormat.StereoFloat32))
            {
                throw new InvalidOperationException("Float data is not supported by this OpenAL driver.");
            }

            if (!controller.SupportsAdpcm && (format == ALFormat.MonoMSAdpcm || format == ALFormat.StereoMSAdpcm))
            {
                throw new InvalidOperationException("MS-ADPCM is not supported by this OpenAL driver.");
            }

            if (!controller.SupportsIma4 && (format == ALFormat.MonoIma4 || format == ALFormat.StereoIma4))
            {
                throw new InvalidOperationException("IMA/ADPCM is not supported by this OpenAL driver.");
            }

            if (BufferId != 0)
            {
                ClearBuffer();
            }

            BufferId = AL.GenBuffer();
            ALHelper.CheckError("Failed to generate OpenAL data buffer.");

            if (sampleAlignment > 0)
            {
                AL.Bufferi(BufferId, ALBufferi.UnpackBlockAlignmentSoft, sampleAlignment);
                ALHelper.CheckError("Failed to set buffer alignment.");
            }

            AL.BufferData(BufferId, format, MemoryMarshal.AsBytes(data), sampleRate);
            ALHelper.CheckError("Failed to fill buffer.");
        }
 internal void PlatformInitialize()
 {
     Controller = ALController.Get();
 }