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); } }
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(); }