implement StreamingSoundQoa

pull/48/head
cosmonaut 2023-05-02 16:23:52 -07:00
parent 2d7bb24b5c
commit cee218a2dc
2 changed files with 104 additions and 1 deletions

@ -1 +1 @@
Subproject commit c42b6814c2550bd757b25b9387c0881eb4860af7
Subproject commit 4f696ab0735927872b8227d3f335040c53876e3a

View File

@ -0,0 +1,103 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
public class StreamingSoundQoa : StreamingSoundSeekable
{
private IntPtr QoaHandle;
private IntPtr FileDataPtr;
protected override int BUFFER_SIZE { get; }
public override bool AutoUpdate => true;
uint Channels;
uint FrameSize;
uint TotalSamplesPerChannel;
public unsafe static StreamingSoundQoa Load(AudioDevice device, string filePath)
{
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var fileDataPtr = NativeMemory.Alloc((nuint) fileStream.Length);
var fileDataSpan = new Span<byte>(fileDataPtr, (int) fileStream.Length);
fileStream.ReadExactly(fileDataSpan);
fileStream.Close();
var qoaHandle = FAudio.qoa_open((char*) fileDataPtr, fileDataSpan.Length);
if (qoaHandle == 0)
{
NativeMemory.Free(fileDataPtr);
Logger.LogError("Error opening QOA file!");
throw new AudioLoadException("Error opening QOA file!");
}
FAudio.qoa_attributes(qoaHandle, out var frameSize, out var channels, out var sampleRate, out var totalSamplesPerChannel);
return new StreamingSoundQoa(
device,
(IntPtr) fileDataPtr,
qoaHandle,
channels,
sampleRate,
frameSize,
totalSamplesPerChannel
);
}
internal unsafe StreamingSoundQoa(
AudioDevice device,
IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!!
IntPtr qoaHandle,
uint channels,
uint samplesPerSecond,
uint frameSize,
uint totalSamplesPerChannel
) : base(
device,
1,
16,
(ushort) (2 * channels),
(ushort) channels,
samplesPerSecond
) {
FileDataPtr = fileDataPtr;
QoaHandle = qoaHandle;
Channels = channels;
FrameSize = frameSize;
TotalSamplesPerChannel = totalSamplesPerChannel;
}
public override void Seek(uint sampleFrame)
{
FAudio.qoa_seek_frame(QoaHandle, (int) sampleFrame);
}
protected override unsafe void FillBuffer(
void* buffer,
int bufferLengthInBytes,
out int filledLengthInBytes,
out bool reachedEnd
) {
var lengthInShorts = bufferLengthInBytes / sizeof(short);
// NOTE: this function returns samples per channel! */
var samples = FAudio.qoa_decode_next_frame(QoaHandle, (short*) buffer);
var sampleCount = samples * Channels;
reachedEnd = sampleCount < lengthInShorts;
filledLengthInBytes = (int) (sampleCount * sizeof(short));
}
protected override unsafe void Destroy()
{
base.Destroy();
if (!IsDisposed)
{
FAudio.qoa_close(QoaHandle);
NativeMemory.Free((void*) FileDataPtr);
}
}
}
}