MoonWorks/src/Audio/StreamingSoundOgg.cs

114 lines
2.8 KiB
C#
Raw Normal View History

2022-02-23 05:14:32 +00:00
using System;
using System.IO;
2022-04-07 21:19:43 +00:00
using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
public class StreamingSoundOgg : StreamingSoundSeekable
2022-02-23 05:14:32 +00:00
{
2023-05-12 00:56:40 +00:00
private IntPtr FileDataPtr = IntPtr.Zero;
private IntPtr VorbisHandle = IntPtr.Zero;
2022-04-07 21:19:43 +00:00
private FAudio.stb_vorbis_info Info;
2023-05-12 00:56:40 +00:00
public override bool Loaded => VorbisHandle != IntPtr.Zero;
private string FilePath;
2023-05-12 00:56:40 +00:00
public unsafe static StreamingSoundOgg Create(AudioDevice device, string filePath)
{
var handle = FAudio.stb_vorbis_open_filename(filePath, out int error, IntPtr.Zero);
2022-02-23 05:14:32 +00:00
if (error != 0)
{
Logger.LogError("Error: " + error);
2023-05-12 00:56:40 +00:00
throw new AudioLoadException("Error opening ogg file!");
2022-02-23 05:14:32 +00:00
}
2023-05-12 00:56:40 +00:00
var info = FAudio.stb_vorbis_get_info(handle);
var streamingSound = new StreamingSoundOgg(
2022-02-23 05:14:32 +00:00
device,
2023-05-12 00:56:40 +00:00
filePath,
2022-04-07 21:19:43 +00:00
info
2022-02-23 05:14:32 +00:00
);
2023-05-12 00:56:40 +00:00
FAudio.stb_vorbis_close(handle);
return streamingSound;
2022-02-23 05:14:32 +00:00
}
internal unsafe StreamingSoundOgg(
2022-02-23 05:14:32 +00:00
AudioDevice device,
2023-05-12 00:56:40 +00:00
string filePath,
FAudio.stb_vorbis_info info,
uint bufferSize = 32768
) : base(
device,
3, /* float type */
32, /* size of float */
(ushort) (4 * info.channels),
(ushort) info.channels,
info.sample_rate,
2023-05-12 00:56:40 +00:00
bufferSize,
true
) {
2022-02-23 05:14:32 +00:00
Info = info;
2023-05-12 00:56:40 +00:00
FilePath = filePath;
2022-02-23 05:14:32 +00:00
}
public override void Seek(uint sampleFrame)
2022-04-20 21:29:46 +00:00
{
FAudio.stb_vorbis_seek(VorbisHandle, sampleFrame);
}
2023-05-12 00:56:40 +00:00
public override unsafe void Load()
{
var fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
FileDataPtr = (nint) NativeMemory.Alloc((nuint) fileStream.Length);
var fileDataSpan = new Span<byte>((void*) FileDataPtr, (int) fileStream.Length);
fileStream.ReadExactly(fileDataSpan);
fileStream.Close();
VorbisHandle = FAudio.stb_vorbis_open_memory(FileDataPtr, fileDataSpan.Length, out int error, IntPtr.Zero);
if (error != 0)
{
NativeMemory.Free((void*) FileDataPtr);
Logger.LogError("Error opening OGG file!");
Logger.LogError("Error: " + error);
throw new AudioLoadException("Error opening OGG file!");
}
}
public override unsafe void Unload()
{
if (Loaded)
{
FAudio.stb_vorbis_close(VorbisHandle);
NativeMemory.Free((void*) FileDataPtr);
VorbisHandle = IntPtr.Zero;
FileDataPtr = IntPtr.Zero;
}
}
protected unsafe override void FillBuffer(
void* buffer,
int bufferLengthInBytes,
out int filledLengthInBytes,
2022-02-23 05:14:32 +00:00
out bool reachedEnd
) {
var lengthInFloats = bufferLengthInBytes / sizeof(float);
2022-02-23 05:14:32 +00:00
/* NOTE: this function returns samples per channel, not total samples */
var samples = FAudio.stb_vorbis_get_samples_float_interleaved(
2022-04-07 21:19:43 +00:00
VorbisHandle,
2022-02-23 05:14:32 +00:00
Info.channels,
(IntPtr) buffer,
lengthInFloats
2022-02-23 05:14:32 +00:00
);
2022-02-23 05:14:32 +00:00
var sampleCount = samples * Info.channels;
reachedEnd = sampleCount < lengthInFloats;
filledLengthInBytes = sampleCount * sizeof(float);
2022-02-23 05:14:32 +00:00
}
}
}