Sound instancing rework
parent
537517afb9
commit
5df08727c1
|
@ -1 +1 @@
|
|||
Subproject commit aaf2568c3e5b202c5cfbd74734386e69f204482c
|
||||
Subproject commit 63071f2c309f6fc2193de1c6b85da0e31df80040
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace MoonWorks.Audio
|
||||
|
@ -27,7 +28,8 @@ namespace MoonWorks.Audio
|
|||
}
|
||||
|
||||
private readonly HashSet<WeakReference> resources = new HashSet<WeakReference>();
|
||||
private readonly HashSet<WeakReference> autoUpdateStreamingSoundReferences = new HashSet<WeakReference>();
|
||||
private readonly List<WeakReference> autoUpdateStreamingSoundReferences = new List<WeakReference>();
|
||||
private readonly List<WeakReference> autoFreeStaticSoundInstanceReferences = new List<WeakReference>();
|
||||
|
||||
private AudioTweenManager AudioTweenManager;
|
||||
|
||||
|
@ -150,15 +152,35 @@ namespace MoonWorks.Audio
|
|||
previousTickTime = TickStopwatch.Elapsed.Ticks;
|
||||
float elapsedSeconds = (float) tickDelta / System.TimeSpan.TicksPerSecond;
|
||||
|
||||
foreach (var weakReference in autoUpdateStreamingSoundReferences)
|
||||
for (var i = autoUpdateStreamingSoundReferences.Count - 1; i >= 0; i -= 1)
|
||||
{
|
||||
if (weakReference.Target is StreamingSound streamingSound)
|
||||
var weakReference = autoUpdateStreamingSoundReferences[i];
|
||||
|
||||
if (weakReference.Target is StreamingSound streamingSound && streamingSound.Loaded)
|
||||
{
|
||||
streamingSound.Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
autoUpdateStreamingSoundReferences.Remove(weakReference);
|
||||
autoUpdateStreamingSoundReferences.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = autoFreeStaticSoundInstanceReferences.Count - 1; i >= 0; i -= 1)
|
||||
{
|
||||
var weakReference = autoFreeStaticSoundInstanceReferences[i];
|
||||
|
||||
if (weakReference.Target is StaticSoundInstance staticSoundInstance)
|
||||
{
|
||||
if (staticSoundInstance.State == SoundState.Stopped)
|
||||
{
|
||||
staticSoundInstance.Free();
|
||||
autoFreeStaticSoundInstanceReferences.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
autoFreeStaticSoundInstanceReferences.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,11 +235,6 @@ namespace MoonWorks.Audio
|
|||
lock (StateLock)
|
||||
{
|
||||
resources.Add(resource.weakReference);
|
||||
|
||||
if (resource is StreamingSound streamingSound && streamingSound.AutoUpdate)
|
||||
{
|
||||
AddAutoUpdateStreamingSoundInstance(streamingSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,22 +243,17 @@ namespace MoonWorks.Audio
|
|||
lock (StateLock)
|
||||
{
|
||||
resources.Remove(resource.weakReference);
|
||||
|
||||
if (resource is StreamingSound streamingSound && streamingSound.AutoUpdate)
|
||||
{
|
||||
RemoveAutoUpdateStreamingSoundInstance(streamingSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAutoUpdateStreamingSoundInstance(StreamingSound instance)
|
||||
internal void AddAutoUpdateStreamingSoundInstance(StreamingSound instance)
|
||||
{
|
||||
autoUpdateStreamingSoundReferences.Add(instance.weakReference);
|
||||
}
|
||||
|
||||
private void RemoveAutoUpdateStreamingSoundInstance(StreamingSound instance)
|
||||
internal void AddAutoFreeStaticSoundInstance(StaticSoundInstance instance)
|
||||
{
|
||||
autoUpdateStreamingSoundReferences.Remove(instance.weakReference);
|
||||
autoFreeStaticSoundInstanceReferences.Add(instance.weakReference);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace MoonWorks.Audio
|
|||
if (weakReference != null)
|
||||
{
|
||||
Device.RemoveResourceReference(this);
|
||||
weakReference.Target = null;
|
||||
weakReference = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ namespace MoonWorks.Audio
|
|||
public uint LoopStart { get; set; } = 0;
|
||||
public uint LoopLength { get; set; } = 0;
|
||||
|
||||
private Stack<StaticSoundInstance> Instances = new Stack<StaticSoundInstance>();
|
||||
private Stack<StaticSoundInstance> AvailableInstances = new Stack<StaticSoundInstance>();
|
||||
private HashSet<StaticSoundInstance> UsedInstances = new HashSet<StaticSoundInstance>();
|
||||
|
||||
private bool OwnsBuffer;
|
||||
|
||||
|
@ -267,22 +268,25 @@ namespace MoonWorks.Audio
|
|||
|
||||
/// <summary>
|
||||
/// Gets a sound instance from the pool.
|
||||
/// NOTE: If you lose track of instances, you will create garbage collection pressure!
|
||||
/// NOTE: If AutoFree is false, you will have to call StaticSoundInstance.Free() yourself or leak the instance!
|
||||
/// </summary>
|
||||
public StaticSoundInstance GetInstance()
|
||||
public StaticSoundInstance GetInstance(bool autoFree = true)
|
||||
{
|
||||
if (Instances.Count == 0)
|
||||
if (AvailableInstances.Count == 0)
|
||||
{
|
||||
Instances.Push(new StaticSoundInstance(Device, this));
|
||||
AvailableInstances.Push(new StaticSoundInstance(Device, this, autoFree));
|
||||
}
|
||||
|
||||
return Instances.Pop();
|
||||
var instance = AvailableInstances.Pop();
|
||||
UsedInstances.Add(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
internal void FreeInstance(StaticSoundInstance instance)
|
||||
{
|
||||
instance.Reset();
|
||||
Instances.Push(instance);
|
||||
UsedInstances.Remove(instance);
|
||||
AvailableInstances.Push(instance);
|
||||
}
|
||||
|
||||
protected override unsafe void Destroy()
|
||||
|
|
|
@ -32,12 +32,21 @@ namespace MoonWorks.Audio
|
|||
}
|
||||
}
|
||||
|
||||
public bool AutoFree { get; }
|
||||
|
||||
internal StaticSoundInstance(
|
||||
AudioDevice device,
|
||||
StaticSound parent
|
||||
StaticSound parent,
|
||||
bool autoFree
|
||||
) : base(device, parent.FormatTag, parent.BitsPerSample, parent.BlockAlign, parent.Channels, parent.SamplesPerSecond)
|
||||
{
|
||||
Parent = parent;
|
||||
AutoFree = autoFree;
|
||||
|
||||
if (AutoFree)
|
||||
{
|
||||
device.AddAutoFreeStaticSoundInstance(this);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Play()
|
||||
|
@ -113,9 +122,11 @@ namespace MoonWorks.Audio
|
|||
Parent.Handle.PlayBegin = sampleFrame;
|
||||
}
|
||||
|
||||
// Call this when you no longer need the sound instance.
|
||||
// If AutoFree is set, this will automatically be called when the sound instance stops playing.
|
||||
// If the sound isn't stopped when you call this, things might get weird!
|
||||
public void Free()
|
||||
{
|
||||
StopImmediate();
|
||||
Parent.FreeInstance(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,6 @@ namespace MoonWorks.Audio
|
|||
/// </summary>
|
||||
public abstract class StreamingSound : SoundInstance
|
||||
{
|
||||
// Should the AudioDevice thread automatically update this class?
|
||||
public abstract bool AutoUpdate { get; }
|
||||
|
||||
// Are we actively consuming buffers?
|
||||
protected bool ConsumingBuffers = false;
|
||||
|
||||
|
@ -24,6 +21,10 @@ namespace MoonWorks.Audio
|
|||
|
||||
private readonly object StateLock = new object();
|
||||
|
||||
public bool AutoUpdate { get; }
|
||||
|
||||
public abstract bool Loaded { get; }
|
||||
|
||||
public unsafe StreamingSound(
|
||||
AudioDevice device,
|
||||
ushort formatTag,
|
||||
|
@ -31,7 +32,8 @@ namespace MoonWorks.Audio
|
|||
ushort blockAlign,
|
||||
ushort channels,
|
||||
uint samplesPerSecond,
|
||||
uint bufferSize
|
||||
uint bufferSize,
|
||||
bool autoUpdate // should the AudioDevice thread automatically update this sound?
|
||||
) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond)
|
||||
{
|
||||
BufferSize = bufferSize;
|
||||
|
@ -41,6 +43,8 @@ namespace MoonWorks.Audio
|
|||
{
|
||||
buffers[i] = (IntPtr) NativeMemory.Alloc(bufferSize);
|
||||
}
|
||||
|
||||
AutoUpdate = autoUpdate;
|
||||
}
|
||||
|
||||
public override void Play()
|
||||
|
@ -57,6 +61,12 @@ namespace MoonWorks.Audio
|
|||
{
|
||||
lock (StateLock)
|
||||
{
|
||||
if (!Loaded)
|
||||
{
|
||||
Logger.LogError("Cannot play StreamingSound before calling Load!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (State == SoundState.Playing)
|
||||
{
|
||||
return;
|
||||
|
@ -65,6 +75,11 @@ namespace MoonWorks.Audio
|
|||
State = SoundState.Playing;
|
||||
|
||||
ConsumingBuffers = true;
|
||||
if (AutoUpdate)
|
||||
{
|
||||
Device.AddAutoUpdateStreamingSoundInstance(this);
|
||||
}
|
||||
|
||||
QueueBuffers();
|
||||
FAudio.FAudioSourceVoice_Start(Voice, 0, operationSet);
|
||||
}
|
||||
|
@ -192,6 +207,9 @@ namespace MoonWorks.Audio
|
|||
}
|
||||
}
|
||||
|
||||
public abstract void Load();
|
||||
public abstract void Unload();
|
||||
|
||||
protected unsafe abstract void FillBuffer(
|
||||
void* buffer,
|
||||
int bufferLengthInBytes, /* in bytes */
|
||||
|
@ -208,6 +226,7 @@ namespace MoonWorks.Audio
|
|||
if (!IsDisposed)
|
||||
{
|
||||
StopImmediate();
|
||||
Unload();
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i += 1)
|
||||
{
|
||||
|
|
|
@ -6,41 +6,38 @@ namespace MoonWorks.Audio
|
|||
{
|
||||
public class StreamingSoundOgg : StreamingSoundSeekable
|
||||
{
|
||||
private IntPtr VorbisHandle;
|
||||
private IntPtr FileDataPtr;
|
||||
private IntPtr FileDataPtr = IntPtr.Zero;
|
||||
private IntPtr VorbisHandle = IntPtr.Zero;
|
||||
private FAudio.stb_vorbis_info Info;
|
||||
public override bool AutoUpdate => true;
|
||||
|
||||
public unsafe static StreamingSoundOgg Load(AudioDevice device, string filePath)
|
||||
public override bool Loaded => VorbisHandle != IntPtr.Zero;
|
||||
private string FilePath;
|
||||
|
||||
public unsafe static StreamingSoundOgg Create(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 vorbisHandle = FAudio.stb_vorbis_open_memory((IntPtr) fileDataPtr, fileDataSpan.Length, out int error, IntPtr.Zero);
|
||||
var handle = FAudio.stb_vorbis_open_filename(filePath, out int error, IntPtr.Zero);
|
||||
if (error != 0)
|
||||
{
|
||||
NativeMemory.Free(fileDataPtr);
|
||||
Logger.LogError("Error opening OGG file!");
|
||||
Logger.LogError("Error: " + error);
|
||||
throw new AudioLoadException("Error opening OGG file!");
|
||||
throw new AudioLoadException("Error opening ogg file!");
|
||||
}
|
||||
var info = FAudio.stb_vorbis_get_info(vorbisHandle);
|
||||
|
||||
return new StreamingSoundOgg(
|
||||
var info = FAudio.stb_vorbis_get_info(handle);
|
||||
|
||||
var streamingSound = new StreamingSoundOgg(
|
||||
device,
|
||||
(IntPtr) fileDataPtr,
|
||||
vorbisHandle,
|
||||
filePath,
|
||||
info
|
||||
);
|
||||
|
||||
FAudio.stb_vorbis_close(handle);
|
||||
|
||||
return streamingSound;
|
||||
}
|
||||
|
||||
internal unsafe StreamingSoundOgg(
|
||||
AudioDevice device,
|
||||
IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!!
|
||||
IntPtr vorbisHandle,
|
||||
string filePath,
|
||||
FAudio.stb_vorbis_info info,
|
||||
uint bufferSize = 32768
|
||||
) : base(
|
||||
|
@ -50,11 +47,11 @@ namespace MoonWorks.Audio
|
|||
(ushort) (4 * info.channels),
|
||||
(ushort) info.channels,
|
||||
info.sample_rate,
|
||||
bufferSize
|
||||
bufferSize,
|
||||
true
|
||||
) {
|
||||
FileDataPtr = fileDataPtr;
|
||||
VorbisHandle = vorbisHandle;
|
||||
Info = info;
|
||||
FilePath = filePath;
|
||||
}
|
||||
|
||||
public override void Seek(uint sampleFrame)
|
||||
|
@ -62,6 +59,36 @@ namespace MoonWorks.Audio
|
|||
FAudio.stb_vorbis_seek(VorbisHandle, sampleFrame);
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -82,16 +109,5 @@ namespace MoonWorks.Audio
|
|||
reachedEnd = sampleCount < lengthInFloats;
|
||||
filledLengthInBytes = sampleCount * sizeof(float);
|
||||
}
|
||||
|
||||
protected unsafe override void Destroy()
|
||||
{
|
||||
base.Destroy();
|
||||
|
||||
if (!IsDisposed)
|
||||
{
|
||||
FAudio.stb_vorbis_close(VorbisHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,39 +6,31 @@ namespace MoonWorks.Audio
|
|||
{
|
||||
public class StreamingSoundQoa : StreamingSoundSeekable
|
||||
{
|
||||
private IntPtr QoaHandle;
|
||||
private IntPtr FileDataPtr;
|
||||
|
||||
public override bool AutoUpdate => true;
|
||||
private IntPtr QoaHandle = IntPtr.Zero;
|
||||
private IntPtr FileDataPtr = IntPtr.Zero;
|
||||
|
||||
uint Channels;
|
||||
uint SamplesPerChannelPerFrame;
|
||||
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();
|
||||
public override bool Loaded => QoaHandle != IntPtr.Zero;
|
||||
private string FilePath;
|
||||
|
||||
var qoaHandle = FAudio.qoa_open_from_memory((char*) fileDataPtr, (uint) fileDataSpan.Length, 0);
|
||||
if (qoaHandle == 0)
|
||||
public unsafe static StreamingSoundQoa Create(AudioDevice device, string filePath)
|
||||
{
|
||||
var handle = FAudio.qoa_open_from_filename(filePath);
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
NativeMemory.Free(fileDataPtr);
|
||||
Logger.LogError("Error opening QOA file!");
|
||||
throw new AudioLoadException("Error opening QOA file!");
|
||||
}
|
||||
|
||||
FAudio.qoa_attributes(qoaHandle, out var channels, out var sampleRate, out var samplesPerChannelPerFrame, out var totalSamplesPerChannel);
|
||||
FAudio.qoa_attributes(handle, out var channels, out var samplerate, out var samplesPerChannelPerFrame, out var totalSamplesPerChannel);
|
||||
|
||||
return new StreamingSoundQoa(
|
||||
device,
|
||||
(IntPtr) fileDataPtr,
|
||||
qoaHandle,
|
||||
filePath,
|
||||
channels,
|
||||
sampleRate,
|
||||
samplerate,
|
||||
samplesPerChannelPerFrame,
|
||||
totalSamplesPerChannel
|
||||
);
|
||||
|
@ -46,8 +38,7 @@ namespace MoonWorks.Audio
|
|||
|
||||
internal unsafe StreamingSoundQoa(
|
||||
AudioDevice device,
|
||||
IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!!
|
||||
IntPtr qoaHandle,
|
||||
string filePath,
|
||||
uint channels,
|
||||
uint samplesPerSecond,
|
||||
uint samplesPerChannelPerFrame,
|
||||
|
@ -59,13 +50,13 @@ namespace MoonWorks.Audio
|
|||
(ushort) (2 * channels),
|
||||
(ushort) channels,
|
||||
samplesPerSecond,
|
||||
samplesPerChannelPerFrame * channels * sizeof(short)
|
||||
samplesPerChannelPerFrame * channels * sizeof(short),
|
||||
true
|
||||
) {
|
||||
FileDataPtr = fileDataPtr;
|
||||
QoaHandle = qoaHandle;
|
||||
Channels = channels;
|
||||
SamplesPerChannelPerFrame = samplesPerChannelPerFrame;
|
||||
TotalSamplesPerChannel = totalSamplesPerChannel;
|
||||
FilePath = filePath;
|
||||
}
|
||||
|
||||
public override void Seek(uint sampleFrame)
|
||||
|
@ -73,6 +64,35 @@ namespace MoonWorks.Audio
|
|||
FAudio.qoa_seek_frame(QoaHandle, (int) sampleFrame);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
QoaHandle = FAudio.qoa_open_from_memory((char*) FileDataPtr, (uint) fileDataSpan.Length, 0);
|
||||
if (QoaHandle == IntPtr.Zero)
|
||||
{
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
Logger.LogError("Error opening QOA file!");
|
||||
throw new AudioLoadException("Error opening QOA file!");
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void Unload()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
FAudio.qoa_close(QoaHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
|
||||
QoaHandle = IntPtr.Zero;
|
||||
FileDataPtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected override unsafe void FillBuffer(
|
||||
void* buffer,
|
||||
int bufferLengthInBytes,
|
||||
|
@ -88,16 +108,5 @@ namespace MoonWorks.Audio
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace MoonWorks.Audio
|
|||
ushort blockAlign,
|
||||
ushort channels,
|
||||
uint samplesPerSecond,
|
||||
uint bufferSize
|
||||
uint bufferSize,
|
||||
bool autoUpdate
|
||||
) : base(
|
||||
device,
|
||||
formatTag,
|
||||
|
@ -19,7 +20,8 @@ namespace MoonWorks.Audio
|
|||
blockAlign,
|
||||
channels,
|
||||
samplesPerSecond,
|
||||
bufferSize
|
||||
bufferSize,
|
||||
autoUpdate
|
||||
) {
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
QueueDestroyFunction(Device.Handle, Handle);
|
||||
Device.RemoveResourceReference(weakReference);
|
||||
weakReference.SetTarget(null);
|
||||
weakReference = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@ using MoonWorks.Audio;
|
|||
|
||||
namespace MoonWorks.Video
|
||||
{
|
||||
public unsafe class StreamingSoundTheora : StreamingSound
|
||||
// TODO: should we just not handle theora sound? it sucks!
|
||||
internal unsafe class StreamingSoundTheora : StreamingSound
|
||||
{
|
||||
private IntPtr VideoHandle;
|
||||
|
||||
// Theorafile is not thread safe, so let's update on the main thread.
|
||||
public override bool AutoUpdate => false;
|
||||
public override bool Loaded => true;
|
||||
|
||||
internal StreamingSoundTheora(
|
||||
AudioDevice device,
|
||||
|
@ -23,11 +22,22 @@ namespace MoonWorks.Video
|
|||
(ushort) (4 * channels),
|
||||
(ushort) channels,
|
||||
sampleRate,
|
||||
bufferSize
|
||||
bufferSize,
|
||||
false // Theorafile is not thread safe, so let's update on the main thread
|
||||
) {
|
||||
VideoHandle = videoHandle;
|
||||
}
|
||||
|
||||
public override unsafe void Load()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
public override unsafe void Unload()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected override unsafe void FillBuffer(
|
||||
void* buffer,
|
||||
int bufferLengthInBytes,
|
||||
|
|
Loading…
Reference in New Issue