MoonWorks/src/Audio/SourceVoice.cs

150 lines
2.9 KiB
C#

using System;
namespace MoonWorks.Audio
{
public class SourceVoice : SendableVoice
{
private Format format;
public Format Format => format;
protected object StateLock = new object();
public uint BuffersQueued
{
get
{
FAudio.FAudioSourceVoice_GetState(
Handle,
out var state,
FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED
);
return state.BuffersQueued;
}
}
private SoundState state;
public SoundState State
{
get
{
if (BuffersQueued == 0)
{
Stop();
}
return state;
}
internal set
{
state = value;
}
}
public delegate void OnUpdateFunc();
public OnUpdateFunc OnUpdate; // called by AudioDevice thread
public SourceVoice(
AudioDevice device,
Format format
) : base(device, format.Channels, device.DeviceDetails.OutputFormat.Format.nChannels)
{
this.format = format;
var fAudioFormat = format.ToFAudioFormat();
FAudio.FAudio_CreateSourceVoice(
device.Handle,
out var Handle,
ref fAudioFormat,
FAudio.FAUDIO_VOICE_USEFILTER,
FAudio.FAUDIO_DEFAULT_FREQ_RATIO,
IntPtr.Zero,
IntPtr.Zero, // default sends to mastering voice!
IntPtr.Zero
);
}
public void Play(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_Start(Handle, 0, syncGroup);
State = SoundState.Playing;
}
}
public void Pause(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_Stop(Handle, 0, syncGroup);
State = SoundState.Paused;
}
}
public void ExitLoop(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_ExitLoop(Handle, syncGroup);
}
}
public void Stop(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_Stop(Handle, 0, syncGroup);
FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle);
State = SoundState.Stopped;
}
}
public void SubmitBuffer(FAudio.FAudioBuffer buffer)
{
FAudio.FAudioSourceVoice_SubmitSourceBuffer(
Handle,
ref buffer,
IntPtr.Zero
);
}
// FIXME: maybe this is bad
// NOTE: SourceVoices obtained this way will be returned to the voice pool when stopped!
public static SourceVoice ObtainSourceVoice(AudioDevice device, Format format)
{
return device.ObtainSourceVoice(format);
}
// intended for short-lived sound effects
public static SourceVoice PlayStaticSound(AudioDevice device, StaticSound sound, SubmixVoice sendVoice = null)
{
var voice = ObtainSourceVoice(device, sound.Format);
if (sendVoice == null)
{
voice.SetOutputVoice(device.MasteringVoice);
}
else
{
voice.SetOutputVoice(sendVoice);
}
voice.SubmitBuffer(sound.Handle);
voice.Play();
return voice;
}
protected override unsafe void Destroy()
{
Stop();
base.Destroy();
}
}
}