Formatting pass

main
cosmonaut 2022-02-22 21:14:32 -08:00
parent 7a754e1c90
commit 26dc361d31
10 changed files with 912 additions and 910 deletions

View File

@ -1,277 +1,277 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class AudioDevice : IDisposable public class AudioDevice : IDisposable
{ {
public IntPtr Handle { get; } public IntPtr Handle { get; }
public byte[] Handle3D { get; } public byte[] Handle3D { get; }
public IntPtr MasteringVoice { get; } public IntPtr MasteringVoice { get; }
public FAudio.FAudioDeviceDetails DeviceDetails { get; } public FAudio.FAudioDeviceDetails DeviceDetails { get; }
public IntPtr ReverbVoice { get; } public IntPtr ReverbVoice { get; }
public float CurveDistanceScalar = 1f; public float CurveDistanceScalar = 1f;
public float DopplerScale = 1f; public float DopplerScale = 1f;
public float SpeedOfSound = 343.5f; public float SpeedOfSound = 343.5f;
internal FAudio.FAudioVoiceSends ReverbSends; internal FAudio.FAudioVoiceSends ReverbSends;
private readonly List<WeakReference<AudioResource>> resources = new List<WeakReference<AudioResource>>(); private readonly List<WeakReference<AudioResource>> resources = new List<WeakReference<AudioResource>>();
private readonly List<WeakReference<StreamingSound>> streamingSounds = new List<WeakReference<StreamingSound>>(); private readonly List<WeakReference<StreamingSound>> streamingSounds = new List<WeakReference<StreamingSound>>();
private bool IsDisposed; private bool IsDisposed;
public unsafe AudioDevice() public unsafe AudioDevice()
{ {
FAudio.FAudioCreate(out var handle, 0, 0); FAudio.FAudioCreate(out var handle, 0, 0);
Handle = handle; Handle = handle;
/* Find a suitable device */ /* Find a suitable device */
FAudio.FAudio_GetDeviceCount(Handle, out var devices); FAudio.FAudio_GetDeviceCount(Handle, out var devices);
if (devices == 0) if (devices == 0)
{ {
Logger.LogError("No audio devices found!"); Logger.LogError("No audio devices found!");
Handle = IntPtr.Zero; Handle = IntPtr.Zero;
FAudio.FAudio_Release(Handle); FAudio.FAudio_Release(Handle);
return; return;
} }
FAudio.FAudioDeviceDetails deviceDetails; FAudio.FAudioDeviceDetails deviceDetails;
uint i = 0; uint i = 0;
for (i = 0; i < devices; i++) for (i = 0; i < devices; i++)
{ {
FAudio.FAudio_GetDeviceDetails( FAudio.FAudio_GetDeviceDetails(
Handle, Handle,
i, i,
out deviceDetails out deviceDetails
); );
if ((deviceDetails.Role & FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) == FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) if ((deviceDetails.Role & FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) == FAudio.FAudioDeviceRole.FAudioDefaultGameDevice)
{ {
DeviceDetails = deviceDetails; DeviceDetails = deviceDetails;
break; break;
} }
} }
if (i == devices) if (i == devices)
{ {
i = 0; /* whatever we'll just use the first one I guess */ i = 0; /* whatever we'll just use the first one I guess */
FAudio.FAudio_GetDeviceDetails( FAudio.FAudio_GetDeviceDetails(
Handle, Handle,
i, i,
out deviceDetails out deviceDetails
); );
DeviceDetails = deviceDetails; DeviceDetails = deviceDetails;
} }
/* Init Mastering Voice */ /* Init Mastering Voice */
IntPtr masteringVoice; IntPtr masteringVoice;
if (FAudio.FAudio_CreateMasteringVoice( if (FAudio.FAudio_CreateMasteringVoice(
Handle, Handle,
out masteringVoice, out masteringVoice,
FAudio.FAUDIO_DEFAULT_CHANNELS, FAudio.FAUDIO_DEFAULT_CHANNELS,
FAudio.FAUDIO_DEFAULT_SAMPLERATE, FAudio.FAUDIO_DEFAULT_SAMPLERATE,
0, 0,
i, i,
IntPtr.Zero IntPtr.Zero
) != 0) ) != 0)
{ {
Logger.LogError("No mastering voice found!"); Logger.LogError("No mastering voice found!");
Handle = IntPtr.Zero; Handle = IntPtr.Zero;
FAudio.FAudio_Release(Handle); FAudio.FAudio_Release(Handle);
return; return;
} }
MasteringVoice = masteringVoice; MasteringVoice = masteringVoice;
/* Init 3D Audio */ /* Init 3D Audio */
Handle3D = new byte[FAudio.F3DAUDIO_HANDLE_BYTESIZE]; Handle3D = new byte[FAudio.F3DAUDIO_HANDLE_BYTESIZE];
FAudio.F3DAudioInitialize( FAudio.F3DAudioInitialize(
DeviceDetails.OutputFormat.dwChannelMask, DeviceDetails.OutputFormat.dwChannelMask,
SpeedOfSound, SpeedOfSound,
Handle3D Handle3D
); );
/* Init reverb */ /* Init reverb */
IntPtr reverbVoice; IntPtr reverbVoice;
IntPtr reverb; IntPtr reverb;
FAudio.FAudioCreateReverb(out reverb, 0); FAudio.FAudioCreateReverb(out reverb, 0);
IntPtr chainPtr; IntPtr chainPtr;
chainPtr = Marshal.AllocHGlobal( chainPtr = Marshal.AllocHGlobal(
Marshal.SizeOf<FAudio.FAudioEffectChain>() Marshal.SizeOf<FAudio.FAudioEffectChain>()
); );
FAudio.FAudioEffectChain* reverbChain = (FAudio.FAudioEffectChain*) chainPtr; FAudio.FAudioEffectChain* reverbChain = (FAudio.FAudioEffectChain*) chainPtr;
reverbChain->EffectCount = 1; reverbChain->EffectCount = 1;
reverbChain->pEffectDescriptors = Marshal.AllocHGlobal( reverbChain->pEffectDescriptors = Marshal.AllocHGlobal(
Marshal.SizeOf<FAudio.FAudioEffectDescriptor>() Marshal.SizeOf<FAudio.FAudioEffectDescriptor>()
); );
FAudio.FAudioEffectDescriptor* reverbDescriptor = FAudio.FAudioEffectDescriptor* reverbDescriptor =
(FAudio.FAudioEffectDescriptor*) reverbChain->pEffectDescriptors; (FAudio.FAudioEffectDescriptor*) reverbChain->pEffectDescriptors;
reverbDescriptor->InitialState = 1; reverbDescriptor->InitialState = 1;
reverbDescriptor->OutputChannels = (uint) ( reverbDescriptor->OutputChannels = (uint) (
(DeviceDetails.OutputFormat.Format.nChannels == 6) ? 6 : 1 (DeviceDetails.OutputFormat.Format.nChannels == 6) ? 6 : 1
); );
reverbDescriptor->pEffect = reverb; reverbDescriptor->pEffect = reverb;
FAudio.FAudio_CreateSubmixVoice( FAudio.FAudio_CreateSubmixVoice(
Handle, Handle,
out reverbVoice, out reverbVoice,
1, /* omnidirectional reverb */ 1, /* omnidirectional reverb */
DeviceDetails.OutputFormat.Format.nSamplesPerSec, DeviceDetails.OutputFormat.Format.nSamplesPerSec,
0, 0,
0, 0,
IntPtr.Zero, IntPtr.Zero,
chainPtr chainPtr
); );
FAudio.FAPOBase_Release(reverb); FAudio.FAPOBase_Release(reverb);
Marshal.FreeHGlobal(reverbChain->pEffectDescriptors); Marshal.FreeHGlobal(reverbChain->pEffectDescriptors);
Marshal.FreeHGlobal(chainPtr); Marshal.FreeHGlobal(chainPtr);
ReverbVoice = reverbVoice; ReverbVoice = reverbVoice;
/* Init reverb params */ /* Init reverb params */
// Defaults based on FAUDIOFX_I3DL2_PRESET_GENERIC // Defaults based on FAUDIOFX_I3DL2_PRESET_GENERIC
IntPtr reverbParamsPtr = Marshal.AllocHGlobal( IntPtr reverbParamsPtr = Marshal.AllocHGlobal(
Marshal.SizeOf<FAudio.FAudioFXReverbParameters>() Marshal.SizeOf<FAudio.FAudioFXReverbParameters>()
); );
FAudio.FAudioFXReverbParameters* reverbParams = (FAudio.FAudioFXReverbParameters*) reverbParamsPtr; FAudio.FAudioFXReverbParameters* reverbParams = (FAudio.FAudioFXReverbParameters*) reverbParamsPtr;
reverbParams->WetDryMix = 100.0f; reverbParams->WetDryMix = 100.0f;
reverbParams->ReflectionsDelay = 7; reverbParams->ReflectionsDelay = 7;
reverbParams->ReverbDelay = 11; reverbParams->ReverbDelay = 11;
reverbParams->RearDelay = FAudio.FAUDIOFX_REVERB_DEFAULT_REAR_DELAY; reverbParams->RearDelay = FAudio.FAUDIOFX_REVERB_DEFAULT_REAR_DELAY;
reverbParams->PositionLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION; reverbParams->PositionLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION;
reverbParams->PositionRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION; reverbParams->PositionRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION;
reverbParams->PositionMatrixLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX; reverbParams->PositionMatrixLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX;
reverbParams->PositionMatrixRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX; reverbParams->PositionMatrixRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX;
reverbParams->EarlyDiffusion = 15; reverbParams->EarlyDiffusion = 15;
reverbParams->LateDiffusion = 15; reverbParams->LateDiffusion = 15;
reverbParams->LowEQGain = 8; reverbParams->LowEQGain = 8;
reverbParams->LowEQCutoff = 4; reverbParams->LowEQCutoff = 4;
reverbParams->HighEQGain = 8; reverbParams->HighEQGain = 8;
reverbParams->HighEQCutoff = 6; reverbParams->HighEQCutoff = 6;
reverbParams->RoomFilterFreq = 5000f; reverbParams->RoomFilterFreq = 5000f;
reverbParams->RoomFilterMain = -10f; reverbParams->RoomFilterMain = -10f;
reverbParams->RoomFilterHF = -1f; reverbParams->RoomFilterHF = -1f;
reverbParams->ReflectionsGain = -26.0200005f; reverbParams->ReflectionsGain = -26.0200005f;
reverbParams->ReverbGain = 10.0f; reverbParams->ReverbGain = 10.0f;
reverbParams->DecayTime = 1.49000001f; reverbParams->DecayTime = 1.49000001f;
reverbParams->Density = 100.0f; reverbParams->Density = 100.0f;
reverbParams->RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE; reverbParams->RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE;
FAudio.FAudioVoice_SetEffectParameters( FAudio.FAudioVoice_SetEffectParameters(
ReverbVoice, ReverbVoice,
0, 0,
reverbParamsPtr, reverbParamsPtr,
(uint) Marshal.SizeOf<FAudio.FAudioFXReverbParameters>(), (uint) Marshal.SizeOf<FAudio.FAudioFXReverbParameters>(),
0 0
); );
Marshal.FreeHGlobal(reverbParamsPtr); Marshal.FreeHGlobal(reverbParamsPtr);
/* Init reverb sends */ /* Init reverb sends */
ReverbSends = new FAudio.FAudioVoiceSends ReverbSends = new FAudio.FAudioVoiceSends
{ {
SendCount = 2, SendCount = 2,
pSends = Marshal.AllocHGlobal( pSends = Marshal.AllocHGlobal(
2 * Marshal.SizeOf<FAudio.FAudioSendDescriptor>() 2 * Marshal.SizeOf<FAudio.FAudioSendDescriptor>()
) )
}; };
FAudio.FAudioSendDescriptor* sendDesc = (FAudio.FAudioSendDescriptor*) ReverbSends.pSends; FAudio.FAudioSendDescriptor* sendDesc = (FAudio.FAudioSendDescriptor*) ReverbSends.pSends;
sendDesc[0].Flags = 0; sendDesc[0].Flags = 0;
sendDesc[0].pOutputVoice = MasteringVoice; sendDesc[0].pOutputVoice = MasteringVoice;
sendDesc[1].Flags = 0; sendDesc[1].Flags = 0;
sendDesc[1].pOutputVoice = ReverbVoice; sendDesc[1].pOutputVoice = ReverbVoice;
} }
public void Update() public void Update()
{ {
for (var i = streamingSounds.Count - 1; i >= 0; i--) for (var i = streamingSounds.Count - 1; i >= 0; i--)
{ {
var weakReference = streamingSounds[i]; var weakReference = streamingSounds[i];
if (weakReference.TryGetTarget(out var streamingSound)) if (weakReference.TryGetTarget(out var streamingSound))
{ {
streamingSound.Update(); streamingSound.Update();
} }
else else
{ {
streamingSounds.RemoveAt(i); streamingSounds.RemoveAt(i);
} }
} }
} }
internal void AddDynamicSoundInstance(StreamingSound instance) internal void AddDynamicSoundInstance(StreamingSound instance)
{ {
streamingSounds.Add(new WeakReference<StreamingSound>(instance)); streamingSounds.Add(new WeakReference<StreamingSound>(instance));
} }
internal void AddResourceReference(WeakReference<AudioResource> resourceReference) internal void AddResourceReference(WeakReference<AudioResource> resourceReference)
{ {
lock (resources) lock (resources)
{ {
resources.Add(resourceReference); resources.Add(resourceReference);
} }
} }
internal void RemoveResourceReference(WeakReference<AudioResource> resourceReference) internal void RemoveResourceReference(WeakReference<AudioResource> resourceReference)
{ {
lock (resources) lock (resources)
{ {
resources.Remove(resourceReference); resources.Remove(resourceReference);
} }
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)
{ {
if (disposing) if (disposing)
{ {
for (var i = streamingSounds.Count - 1; i >= 0; i--) for (var i = streamingSounds.Count - 1; i >= 0; i--)
{ {
var weakReference = streamingSounds[i]; var weakReference = streamingSounds[i];
if (weakReference.TryGetTarget(out var streamingSound)) if (weakReference.TryGetTarget(out var streamingSound))
{ {
streamingSound.Dispose(); streamingSound.Dispose();
} }
} }
streamingSounds.Clear(); streamingSounds.Clear();
} }
FAudio.FAudioVoice_DestroyVoice(ReverbVoice); FAudio.FAudioVoice_DestroyVoice(ReverbVoice);
FAudio.FAudioVoice_DestroyVoice(MasteringVoice); FAudio.FAudioVoice_DestroyVoice(MasteringVoice);
FAudio.FAudio_Release(Handle); FAudio.FAudio_Release(Handle);
IsDisposed = true; IsDisposed = true;
} }
} }
// TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
~AudioDevice() ~AudioDevice()
{ {
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false); Dispose(disposing: false);
} }
public void Dispose() public void Dispose()
{ {
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true); Dispose(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
} }
} }

View File

@ -1,12 +1,12 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using MoonWorks.Math; using MoonWorks.Math;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class AudioEmitter : AudioResource public class AudioEmitter : AudioResource
{ {
internal FAudio.F3DAUDIO_EMITTER emitterData; internal FAudio.F3DAUDIO_EMITTER emitterData;
public float DopplerScale public float DopplerScale
{ {
@ -107,17 +107,17 @@ namespace MoonWorks.Audio
GCHandleType.Pinned GCHandleType.Pinned
); );
public AudioEmitter(AudioDevice device) : base(device) public AudioEmitter(AudioDevice device) : base(device)
{ {
emitterData = new FAudio.F3DAUDIO_EMITTER(); emitterData = new FAudio.F3DAUDIO_EMITTER();
DopplerScale = 1f; DopplerScale = 1f;
Forward = Vector3.Forward; Forward = Vector3.Forward;
Position = Vector3.Zero; Position = Vector3.Zero;
Up = Vector3.Up; Up = Vector3.Up;
Velocity = Vector3.Zero; Velocity = Vector3.Zero;
/* Unexposed variables, defaults based on XNA behavior */ /* Unexposed variables, defaults based on XNA behavior */
emitterData.pCone = IntPtr.Zero; emitterData.pCone = IntPtr.Zero;
emitterData.ChannelCount = 1; emitterData.ChannelCount = 1;
emitterData.ChannelRadius = 1.0f; emitterData.ChannelRadius = 1.0f;
@ -128,8 +128,8 @@ namespace MoonWorks.Audio
emitterData.pLPFReverbCurve = IntPtr.Zero; emitterData.pLPFReverbCurve = IntPtr.Zero;
emitterData.pReverbCurve = IntPtr.Zero; emitterData.pReverbCurve = IntPtr.Zero;
emitterData.CurveDistanceScaler = 1.0f; emitterData.CurveDistanceScaler = 1.0f;
} }
protected override void Destroy() { } protected override void Destroy() { }
} }
} }

View File

@ -1,11 +1,11 @@
using System; using System;
using MoonWorks.Math; using MoonWorks.Math;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class AudioListener : AudioResource public class AudioListener : AudioResource
{ {
internal FAudio.F3DAUDIO_LISTENER listenerData; internal FAudio.F3DAUDIO_LISTENER listenerData;
public Vector3 Forward public Vector3 Forward
{ {
@ -80,18 +80,18 @@ namespace MoonWorks.Audio
} }
} }
public AudioListener(AudioDevice device) : base(device) public AudioListener(AudioDevice device) : base(device)
{ {
listenerData = new FAudio.F3DAUDIO_LISTENER(); listenerData = new FAudio.F3DAUDIO_LISTENER();
Forward = Vector3.Forward; Forward = Vector3.Forward;
Position = Vector3.Zero; Position = Vector3.Zero;
Up = Vector3.Up; Up = Vector3.Up;
Velocity = Vector3.Zero; Velocity = Vector3.Zero;
/* Unexposed variables, defaults based on XNA behavior */ /* Unexposed variables, defaults based on XNA behavior */
listenerData.pCone = IntPtr.Zero; listenerData.pCone = IntPtr.Zero;
} }
protected override void Destroy() { } protected override void Destroy() { }
} }
} }

View File

@ -1,52 +1,52 @@
using System; using System;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public abstract class AudioResource : IDisposable public abstract class AudioResource : IDisposable
{ {
public AudioDevice Device { get; } public AudioDevice Device { get; }
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
private WeakReference<AudioResource> selfReference; private WeakReference<AudioResource> selfReference;
public AudioResource(AudioDevice device) public AudioResource(AudioDevice device)
{ {
Device = device; Device = device;
selfReference = new WeakReference<AudioResource>(this); selfReference = new WeakReference<AudioResource>(this);
Device.AddResourceReference(selfReference); Device.AddResourceReference(selfReference);
} }
protected abstract void Destroy(); protected abstract void Destroy();
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)
{ {
Destroy(); Destroy();
if (selfReference != null) if (selfReference != null)
{ {
Device.RemoveResourceReference(selfReference); Device.RemoveResourceReference(selfReference);
selfReference = null; selfReference = null;
} }
IsDisposed = true; IsDisposed = true;
} }
} }
~AudioResource() ~AudioResource()
{ {
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false); Dispose(disposing: false);
} }
public void Dispose() public void Dispose()
{ {
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true); Dispose(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
} }
} }

View File

@ -1,271 +1,271 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using MoonWorks.Math; using MoonWorks.Math;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public abstract class SoundInstance : AudioResource public abstract class SoundInstance : AudioResource
{ {
internal IntPtr Handle { get; } internal IntPtr Handle { get; }
internal FAudio.FAudioWaveFormatEx Format { get; } internal FAudio.FAudioWaveFormatEx Format { get; }
public bool Loop { get; } public bool Loop { get; }
protected FAudio.F3DAUDIO_DSP_SETTINGS dspSettings; protected FAudio.F3DAUDIO_DSP_SETTINGS dspSettings;
protected bool is3D; protected bool is3D;
public abstract SoundState State { get; protected set; } public abstract SoundState State { get; protected set; }
private float _pan = 0; private float _pan = 0;
public float Pan public float Pan
{ {
get => _pan; get => _pan;
set set
{ {
_pan = value; _pan = value;
if (_pan < -1f) if (_pan < -1f)
{ {
_pan = -1f; _pan = -1f;
} }
if (_pan > 1f) if (_pan > 1f)
{ {
_pan = 1f; _pan = 1f;
} }
if (is3D) { return; } if (is3D) { return; }
SetPanMatrixCoefficients(); SetPanMatrixCoefficients();
FAudio.FAudioVoice_SetOutputMatrix( FAudio.FAudioVoice_SetOutputMatrix(
Handle, Handle,
Device.MasteringVoice, Device.MasteringVoice,
dspSettings.SrcChannelCount, dspSettings.SrcChannelCount,
dspSettings.DstChannelCount, dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients, dspSettings.pMatrixCoefficients,
0 0
); );
} }
} }
private float _pitch = 1; private float _pitch = 1;
public float Pitch public float Pitch
{ {
get => _pitch; get => _pitch;
set set
{ {
_pitch = MathHelper.Clamp(value, -1f, 1f); _pitch = MathHelper.Clamp(value, -1f, 1f);
UpdatePitch(); UpdatePitch();
} }
} }
private float _volume = 1; private float _volume = 1;
public float Volume public float Volume
{ {
get => _volume; get => _volume;
set set
{ {
_volume = value; _volume = value;
FAudio.FAudioVoice_SetVolume(Handle, _volume, 0); FAudio.FAudioVoice_SetVolume(Handle, _volume, 0);
} }
} }
private float _reverb; private float _reverb;
public unsafe float Reverb public unsafe float Reverb
{ {
get => _reverb; get => _reverb;
set set
{ {
_reverb = value; _reverb = value;
float* outputMatrix = (float*) dspSettings.pMatrixCoefficients; float* outputMatrix = (float*) dspSettings.pMatrixCoefficients;
outputMatrix[0] = _reverb; outputMatrix[0] = _reverb;
if (dspSettings.SrcChannelCount == 2) if (dspSettings.SrcChannelCount == 2)
{ {
outputMatrix[1] = _reverb; outputMatrix[1] = _reverb;
} }
FAudio.FAudioVoice_SetOutputMatrix( FAudio.FAudioVoice_SetOutputMatrix(
Handle, Handle,
Device.ReverbVoice, Device.ReverbVoice,
dspSettings.SrcChannelCount, dspSettings.SrcChannelCount,
1, 1,
dspSettings.pMatrixCoefficients, dspSettings.pMatrixCoefficients,
0 0
); );
} }
} }
private float _lowPassFilter; private float _lowPassFilter;
public float LowPassFilter public float LowPassFilter
{ {
get => _lowPassFilter; get => _lowPassFilter;
set set
{ {
_lowPassFilter = value; _lowPassFilter = value;
FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters
{ {
Type = FAudio.FAudioFilterType.FAudioLowPassFilter, Type = FAudio.FAudioFilterType.FAudioLowPassFilter,
Frequency = _lowPassFilter, Frequency = _lowPassFilter,
OneOverQ = 1f OneOverQ = 1f
}; };
FAudio.FAudioVoice_SetFilterParameters( FAudio.FAudioVoice_SetFilterParameters(
Handle, Handle,
ref p, ref p,
0 0
); );
} }
} }
private float _highPassFilter; private float _highPassFilter;
public float HighPassFilter public float HighPassFilter
{ {
get => _highPassFilter; get => _highPassFilter;
set set
{ {
_highPassFilter = value; _highPassFilter = value;
FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters
{ {
Type = FAudio.FAudioFilterType.FAudioHighPassFilter, Type = FAudio.FAudioFilterType.FAudioHighPassFilter,
Frequency = _highPassFilter, Frequency = _highPassFilter,
OneOverQ = 1f OneOverQ = 1f
}; };
FAudio.FAudioVoice_SetFilterParameters( FAudio.FAudioVoice_SetFilterParameters(
Handle, Handle,
ref p, ref p,
0 0
); );
} }
} }
private float _bandPassFilter; private float _bandPassFilter;
public float BandPassFilter public float BandPassFilter
{ {
get => _bandPassFilter; get => _bandPassFilter;
set set
{ {
_bandPassFilter = value; _bandPassFilter = value;
FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters
{ {
Type = FAudio.FAudioFilterType.FAudioBandPassFilter, Type = FAudio.FAudioFilterType.FAudioBandPassFilter,
Frequency = _bandPassFilter, Frequency = _bandPassFilter,
OneOverQ = 1f OneOverQ = 1f
}; };
FAudio.FAudioVoice_SetFilterParameters( FAudio.FAudioVoice_SetFilterParameters(
Handle, Handle,
ref p, ref p,
0 0
); );
} }
} }
public SoundInstance( public SoundInstance(
AudioDevice device, AudioDevice device,
ushort channels, ushort channels,
uint samplesPerSecond, uint samplesPerSecond,
bool is3D, bool is3D,
bool loop bool loop
) : base(device) ) : base(device)
{ {
var blockAlign = (ushort)(4 * channels); var blockAlign = (ushort) (4 * channels);
var format = new FAudio.FAudioWaveFormatEx var format = new FAudio.FAudioWaveFormatEx
{ {
wFormatTag = 3, wFormatTag = 3,
wBitsPerSample = 32, wBitsPerSample = 32,
nChannels = channels, nChannels = channels,
nBlockAlign = blockAlign, nBlockAlign = blockAlign,
nSamplesPerSec = samplesPerSecond, nSamplesPerSec = samplesPerSecond,
nAvgBytesPerSec = blockAlign * samplesPerSecond nAvgBytesPerSec = blockAlign * samplesPerSecond
}; };
Format = format; Format = format;
FAudio.FAudio_CreateSourceVoice( FAudio.FAudio_CreateSourceVoice(
Device.Handle, Device.Handle,
out var handle, out var handle,
ref format, ref format,
FAudio.FAUDIO_VOICE_USEFILTER, FAudio.FAUDIO_VOICE_USEFILTER,
FAudio.FAUDIO_DEFAULT_FREQ_RATIO, FAudio.FAUDIO_DEFAULT_FREQ_RATIO,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero IntPtr.Zero
); );
if (handle == IntPtr.Zero) if (handle == IntPtr.Zero)
{ {
Logger.LogError("SoundInstance failed to initialize!"); Logger.LogError("SoundInstance failed to initialize!");
return; return;
} }
Handle = handle; Handle = handle;
this.is3D = is3D; this.is3D = is3D;
InitDSPSettings(Format.nChannels); InitDSPSettings(Format.nChannels);
FAudio.FAudioVoice_SetOutputVoices( FAudio.FAudioVoice_SetOutputVoices(
handle, handle,
ref Device.ReverbSends ref Device.ReverbSends
); );
Loop = loop; Loop = loop;
State = SoundState.Stopped; State = SoundState.Stopped;
} }
public void Apply3D(AudioListener listener, AudioEmitter emitter) public void Apply3D(AudioListener listener, AudioEmitter emitter)
{ {
is3D = true; is3D = true;
emitter.emitterData.CurveDistanceScaler = Device.CurveDistanceScalar; emitter.emitterData.CurveDistanceScaler = Device.CurveDistanceScalar;
emitter.emitterData.ChannelCount = dspSettings.SrcChannelCount; emitter.emitterData.ChannelCount = dspSettings.SrcChannelCount;
FAudio.F3DAudioCalculate( FAudio.F3DAudioCalculate(
Device.Handle3D, Device.Handle3D,
ref listener.listenerData, ref listener.listenerData,
ref emitter.emitterData, ref emitter.emitterData,
FAudio.F3DAUDIO_CALCULATE_MATRIX | FAudio.F3DAUDIO_CALCULATE_DOPPLER, FAudio.F3DAUDIO_CALCULATE_MATRIX | FAudio.F3DAUDIO_CALCULATE_DOPPLER,
ref dspSettings ref dspSettings
); );
UpdatePitch(); UpdatePitch();
FAudio.FAudioVoice_SetOutputMatrix( FAudio.FAudioVoice_SetOutputMatrix(
Handle, Handle,
Device.MasteringVoice, Device.MasteringVoice,
dspSettings.SrcChannelCount, dspSettings.SrcChannelCount,
dspSettings.DstChannelCount, dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients, dspSettings.pMatrixCoefficients,
0 0
); );
} }
public abstract void Play(); public abstract void Play();
public abstract void Pause(); public abstract void Pause();
public abstract void Stop(bool immediate); public abstract void Stop(bool immediate);
private void InitDSPSettings(uint srcChannels) private void InitDSPSettings(uint srcChannels)
{ {
dspSettings = new FAudio.F3DAUDIO_DSP_SETTINGS(); dspSettings = new FAudio.F3DAUDIO_DSP_SETTINGS();
dspSettings.DopplerFactor = 1f; dspSettings.DopplerFactor = 1f;
dspSettings.SrcChannelCount = srcChannels; dspSettings.SrcChannelCount = srcChannels;
dspSettings.DstChannelCount = Device.DeviceDetails.OutputFormat.Format.nChannels; dspSettings.DstChannelCount = Device.DeviceDetails.OutputFormat.Format.nChannels;
int memsize = ( int memsize = (
4 * 4 *
(int) dspSettings.SrcChannelCount * (int) dspSettings.SrcChannelCount *
(int) dspSettings.DstChannelCount (int) dspSettings.DstChannelCount
); );
dspSettings.pMatrixCoefficients = Marshal.AllocHGlobal(memsize); dspSettings.pMatrixCoefficients = Marshal.AllocHGlobal(memsize);
unsafe unsafe
{ {
byte* memPtr = (byte*) dspSettings.pMatrixCoefficients; byte* memPtr = (byte*) dspSettings.pMatrixCoefficients;
for (int i = 0; i < memsize; i += 1) for (int i = 0; i < memsize; i += 1)
{ {
memPtr[i] = 0; memPtr[i] = 0;
} }
} }
SetPanMatrixCoefficients(); SetPanMatrixCoefficients();
} }
private void UpdatePitch() private void UpdatePitch()
{ {
@ -287,10 +287,10 @@ namespace MoonWorks.Audio
); );
} }
// Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs // Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs
private unsafe void SetPanMatrixCoefficients() private unsafe void SetPanMatrixCoefficients()
{ {
/* Two major things to notice: /* Two major things to notice:
* 1. The spec assumes any speaker count >= 2 has Front Left/Right. * 1. The spec assumes any speaker count >= 2 has Front Left/Right.
* 2. Stereo panning is WAY more complicated than you think. * 2. Stereo panning is WAY more complicated than you think.
* The main thing is that hard panning does NOT eliminate an * The main thing is that hard panning does NOT eliminate an
@ -307,7 +307,7 @@ namespace MoonWorks.Audio
else else
{ {
outputMatrix[0] = (_pan > 0.0f) ? (1.0f - _pan) : 1.0f; outputMatrix[0] = (_pan > 0.0f) ? (1.0f - _pan) : 1.0f;
outputMatrix[1] = (_pan < 0.0f) ? (1.0f + _pan) : 1.0f; outputMatrix[1] = (_pan < 0.0f) ? (1.0f + _pan) : 1.0f;
} }
} }
else else
@ -339,14 +339,14 @@ namespace MoonWorks.Audio
} }
} }
} }
} }
protected override void Destroy() protected override void Destroy()
{ {
Stop(true); Stop(true);
FAudio.FAudioVoice_DestroyVoice(Handle); FAudio.FAudioVoice_DestroyVoice(Handle);
Marshal.FreeHGlobal(dspSettings.pMatrixCoefficients); Marshal.FreeHGlobal(dspSettings.pMatrixCoefficients);
} }
} }
} }

View File

@ -1,9 +1,9 @@
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public enum SoundState public enum SoundState
{ {
Playing, Playing,
Paused, Paused,
Stopped Stopped
} }
} }

View File

@ -1,82 +1,82 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class StaticSound : AudioResource public class StaticSound : AudioResource
{ {
internal FAudio.FAudioBuffer Handle; internal FAudio.FAudioBuffer Handle;
public ushort Channels { get; } public ushort Channels { get; }
public uint SamplesPerSecond { get; } public uint SamplesPerSecond { get; }
public uint LoopStart { get; set; } = 0; public uint LoopStart { get; set; } = 0;
public uint LoopLength { get; set; } = 0; public uint LoopLength { get; set; } = 0;
public static StaticSound LoadOgg(AudioDevice device, string filePath) public static StaticSound LoadOgg(AudioDevice device, string filePath)
{ {
var filePointer = FAudio.stb_vorbis_open_filename(filePath, out var error, IntPtr.Zero); var filePointer = FAudio.stb_vorbis_open_filename(filePath, out var error, IntPtr.Zero);
if (error != 0) if (error != 0)
{ {
throw new AudioLoadException("Error loading file!"); throw new AudioLoadException("Error loading file!");
} }
var info = FAudio.stb_vorbis_get_info(filePointer); var info = FAudio.stb_vorbis_get_info(filePointer);
var bufferSize = FAudio.stb_vorbis_stream_length_in_samples(filePointer) * info.channels; var bufferSize = FAudio.stb_vorbis_stream_length_in_samples(filePointer) * info.channels;
var buffer = new float[bufferSize]; var buffer = new float[bufferSize];
FAudio.stb_vorbis_get_samples_float_interleaved( FAudio.stb_vorbis_get_samples_float_interleaved(
filePointer, filePointer,
info.channels, info.channels,
buffer, buffer,
(int) bufferSize (int) bufferSize
); );
FAudio.stb_vorbis_close(filePointer); FAudio.stb_vorbis_close(filePointer);
return new StaticSound( return new StaticSound(
device, device,
(ushort) info.channels, (ushort) info.channels,
info.sample_rate, info.sample_rate,
buffer, buffer,
0, 0,
(uint) buffer.Length (uint) buffer.Length
); );
} }
public StaticSound( public StaticSound(
AudioDevice device, AudioDevice device,
ushort channels, ushort channels,
uint samplesPerSecond, uint samplesPerSecond,
float[] buffer, float[] buffer,
uint bufferOffset, /* in floats */ uint bufferOffset, /* in floats */
uint bufferLength /* in floats */ uint bufferLength /* in floats */
) : base(device) ) : base(device)
{ {
Channels = channels; Channels = channels;
SamplesPerSecond = samplesPerSecond; SamplesPerSecond = samplesPerSecond;
var bufferLengthInBytes = (int) (bufferLength * sizeof(float)); var bufferLengthInBytes = (int) (bufferLength * sizeof(float));
Handle = new FAudio.FAudioBuffer(); Handle = new FAudio.FAudioBuffer();
Handle.Flags = FAudio.FAUDIO_END_OF_STREAM; Handle.Flags = FAudio.FAUDIO_END_OF_STREAM;
Handle.pContext = IntPtr.Zero; Handle.pContext = IntPtr.Zero;
Handle.AudioBytes = (uint) bufferLengthInBytes; Handle.AudioBytes = (uint) bufferLengthInBytes;
Handle.pAudioData = Marshal.AllocHGlobal(bufferLengthInBytes); Handle.pAudioData = Marshal.AllocHGlobal(bufferLengthInBytes);
Marshal.Copy(buffer, (int) bufferOffset, Handle.pAudioData, (int) bufferLength); Marshal.Copy(buffer, (int) bufferOffset, Handle.pAudioData, (int) bufferLength);
Handle.PlayBegin = 0; Handle.PlayBegin = 0;
Handle.PlayLength = 0; Handle.PlayLength = 0;
LoopStart = 0; LoopStart = 0;
LoopLength = 0; LoopLength = 0;
} }
public StaticSoundInstance CreateInstance(bool loop = false) public StaticSoundInstance CreateInstance(bool loop = false)
{ {
return new StaticSoundInstance(Device, this, false, loop); return new StaticSoundInstance(Device, this, false, loop);
} }
protected override void Destroy() protected override void Destroy()
{ {
Marshal.FreeHGlobal(Handle.pAudioData); Marshal.FreeHGlobal(Handle.pAudioData);
} }
} }
} }

View File

@ -1,96 +1,96 @@
using System; using System;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class StaticSoundInstance : SoundInstance public class StaticSoundInstance : SoundInstance
{ {
public StaticSound Parent { get; } public StaticSound Parent { get; }
private SoundState _state = SoundState.Stopped; private SoundState _state = SoundState.Stopped;
public override SoundState State public override SoundState State
{ {
get get
{ {
FAudio.FAudioSourceVoice_GetState( FAudio.FAudioSourceVoice_GetState(
Handle, Handle,
out var state, out var state,
FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED
); );
if (state.BuffersQueued == 0) if (state.BuffersQueued == 0)
{ {
Stop(true); Stop(true);
} }
return _state; return _state;
} }
protected set protected set
{ {
_state = value; _state = value;
} }
} }
internal StaticSoundInstance( internal StaticSoundInstance(
AudioDevice device, AudioDevice device,
StaticSound parent, StaticSound parent,
bool is3D, bool is3D,
bool loop bool loop
) : base(device, parent.Channels, parent.SamplesPerSecond, is3D, loop) ) : base(device, parent.Channels, parent.SamplesPerSecond, is3D, loop)
{ {
Parent = parent; Parent = parent;
} }
public override void Play() public override void Play()
{ {
if (State == SoundState.Playing) if (State == SoundState.Playing)
{ {
return; return;
} }
if (Loop) if (Loop)
{ {
Parent.Handle.LoopCount = 255; Parent.Handle.LoopCount = 255;
Parent.Handle.LoopBegin = Parent.LoopStart; Parent.Handle.LoopBegin = Parent.LoopStart;
Parent.Handle.LoopLength = Parent.LoopLength; Parent.Handle.LoopLength = Parent.LoopLength;
} }
else else
{ {
Parent.Handle.LoopCount = 0; Parent.Handle.LoopCount = 0;
Parent.Handle.LoopBegin = 0; Parent.Handle.LoopBegin = 0;
Parent.Handle.LoopLength = 0; Parent.Handle.LoopLength = 0;
} }
FAudio.FAudioSourceVoice_SubmitSourceBuffer( FAudio.FAudioSourceVoice_SubmitSourceBuffer(
Handle, Handle,
ref Parent.Handle, ref Parent.Handle,
IntPtr.Zero IntPtr.Zero
); );
FAudio.FAudioSourceVoice_Start(Handle, 0, 0); FAudio.FAudioSourceVoice_Start(Handle, 0, 0);
State = SoundState.Playing; State = SoundState.Playing;
} }
public override void Pause() public override void Pause()
{ {
if (State == SoundState.Paused) if (State == SoundState.Paused)
{ {
FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); FAudio.FAudioSourceVoice_Stop(Handle, 0, 0);
State = SoundState.Paused; State = SoundState.Paused;
} }
} }
public override void Stop(bool immediate = true) public override void Stop(bool immediate = true)
{ {
if (immediate) if (immediate)
{ {
FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); FAudio.FAudioSourceVoice_Stop(Handle, 0, 0);
FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle); FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle);
State = SoundState.Stopped; State = SoundState.Stopped;
} }
else else
{ {
FAudio.FAudioSourceVoice_ExitLoop(Handle, 0); FAudio.FAudioSourceVoice_ExitLoop(Handle, 0);
} }
} }
} }
} }

View File

@ -1,178 +1,178 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
/// <summary> /// <summary>
/// For streaming long playback. /// For streaming long playback.
/// Can be extended to support custom decoders. /// Can be extended to support custom decoders.
/// </summary> /// </summary>
public abstract class StreamingSound : SoundInstance public abstract class StreamingSound : SoundInstance
{ {
private readonly List<IntPtr> queuedBuffers = new List<IntPtr>(); private readonly List<IntPtr> queuedBuffers = new List<IntPtr>();
private readonly List<uint> queuedSizes = new List<uint>(); private readonly List<uint> queuedSizes = new List<uint>();
private const int MINIMUM_BUFFER_CHECK = 3; private const int MINIMUM_BUFFER_CHECK = 3;
public int PendingBufferCount => queuedBuffers.Count; public int PendingBufferCount => queuedBuffers.Count;
public StreamingSound( public StreamingSound(
AudioDevice device, AudioDevice device,
ushort channels, ushort channels,
uint samplesPerSecond, uint samplesPerSecond,
bool is3D, bool is3D,
bool loop bool loop
) : base(device, channels, samplesPerSecond, is3D, loop) { } ) : base(device, channels, samplesPerSecond, is3D, loop) { }
public override void Play() public override void Play()
{ {
if (State == SoundState.Playing) if (State == SoundState.Playing)
{ {
return; return;
} }
State = SoundState.Playing; State = SoundState.Playing;
Update(); Update();
FAudio.FAudioSourceVoice_Start(Handle, 0, 0); FAudio.FAudioSourceVoice_Start(Handle, 0, 0);
} }
public override void Pause() public override void Pause()
{ {
if (State == SoundState.Playing) if (State == SoundState.Playing)
{ {
FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); FAudio.FAudioSourceVoice_Stop(Handle, 0, 0);
State = SoundState.Paused; State = SoundState.Paused;
} }
} }
public override void Stop(bool immediate = true) public override void Stop(bool immediate = true)
{ {
if (immediate) if (immediate)
{ {
FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); FAudio.FAudioSourceVoice_Stop(Handle, 0, 0);
FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle); FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle);
ClearBuffers(); ClearBuffers();
} }
State = SoundState.Stopped; State = SoundState.Stopped;
} }
internal void Update() internal void Update()
{ {
if (State != SoundState.Playing) if (State != SoundState.Playing)
{ {
return; return;
} }
FAudio.FAudioSourceVoice_GetState( FAudio.FAudioSourceVoice_GetState(
Handle, Handle,
out var state, out var state,
FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED
); );
while (PendingBufferCount > state.BuffersQueued) while (PendingBufferCount > state.BuffersQueued)
lock (queuedBuffers) lock (queuedBuffers)
{ {
Marshal.FreeHGlobal(queuedBuffers[0]); Marshal.FreeHGlobal(queuedBuffers[0]);
queuedBuffers.RemoveAt(0); queuedBuffers.RemoveAt(0);
} }
QueueBuffers(); QueueBuffers();
} }
protected void QueueBuffers() protected void QueueBuffers()
{ {
for ( for (
int i = MINIMUM_BUFFER_CHECK - PendingBufferCount; int i = MINIMUM_BUFFER_CHECK - PendingBufferCount;
i > 0; i > 0;
i -= 1 i -= 1
) )
{ {
AddBuffer(); AddBuffer();
} }
} }
protected void ClearBuffers() protected void ClearBuffers()
{ {
lock (queuedBuffers) lock (queuedBuffers)
{ {
foreach (IntPtr buf in queuedBuffers) foreach (IntPtr buf in queuedBuffers)
{ {
Marshal.FreeHGlobal(buf); Marshal.FreeHGlobal(buf);
} }
queuedBuffers.Clear(); queuedBuffers.Clear();
queuedSizes.Clear(); queuedSizes.Clear();
} }
} }
protected void AddBuffer() protected void AddBuffer()
{ {
AddBuffer( AddBuffer(
out var buffer, out var buffer,
out var bufferOffset, out var bufferOffset,
out var bufferLength, out var bufferLength,
out var reachedEnd out var reachedEnd
); );
var lengthInBytes = bufferLength * sizeof(float); var lengthInBytes = bufferLength * sizeof(float);
IntPtr next = Marshal.AllocHGlobal((int) lengthInBytes); IntPtr next = Marshal.AllocHGlobal((int) lengthInBytes);
Marshal.Copy(buffer, (int) bufferOffset, next, (int) bufferLength); Marshal.Copy(buffer, (int) bufferOffset, next, (int) bufferLength);
lock (queuedBuffers) lock (queuedBuffers)
{ {
queuedBuffers.Add(next); queuedBuffers.Add(next);
if (State != SoundState.Stopped) if (State != SoundState.Stopped)
{ {
FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer
{ {
AudioBytes = lengthInBytes, AudioBytes = lengthInBytes,
pAudioData = next, pAudioData = next,
PlayLength = ( PlayLength = (
lengthInBytes / lengthInBytes /
Format.nChannels / Format.nChannels /
(uint)(Format.wBitsPerSample / 8) (uint) (Format.wBitsPerSample / 8)
) )
}; };
FAudio.FAudioSourceVoice_SubmitSourceBuffer( FAudio.FAudioSourceVoice_SubmitSourceBuffer(
Handle, Handle,
ref buf, ref buf,
IntPtr.Zero IntPtr.Zero
); );
} }
else else
{ {
queuedSizes.Add(lengthInBytes); queuedSizes.Add(lengthInBytes);
} }
} }
/* We have reached the end of the file, what do we do? */ /* We have reached the end of the file, what do we do? */
if (reachedEnd) if (reachedEnd)
{ {
if (Loop) if (Loop)
{ {
SeekStart(); SeekStart();
} }
else else
{ {
Stop(false); Stop(false);
} }
} }
} }
protected abstract void AddBuffer( protected abstract void AddBuffer(
out float[] buffer, out float[] buffer,
out uint bufferOffset, /* in floats */ out uint bufferOffset, /* in floats */
out uint bufferLength, /* in floats */ out uint bufferLength, /* in floats */
out bool reachedEnd out bool reachedEnd
); );
protected abstract void SeekStart(); protected abstract void SeekStart();
protected override void Destroy() protected override void Destroy()
{ {
Stop(true); Stop(true);
} }
} }
} }

View File

@ -1,89 +1,91 @@
using System; using System;
using System.IO; using System.IO;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
public class StreamingSoundOgg : StreamingSound public class StreamingSoundOgg : StreamingSound
{ {
// FIXME: what should this value be? // FIXME: what should this value be?
public const int BUFFER_SIZE = 1024 * 128; public const int BUFFER_SIZE = 1024 * 128;
internal IntPtr FileHandle { get; } internal IntPtr FileHandle { get; }
internal FAudio.stb_vorbis_info Info { get; } internal FAudio.stb_vorbis_info Info { get; }
private readonly float[] buffer; private readonly float[] buffer;
public override SoundState State { get; protected set; } public override SoundState State { get; protected set; }
public static StreamingSoundOgg Load( public static StreamingSoundOgg Load(
AudioDevice device, AudioDevice device,
string filePath, string filePath,
bool is3D = false, bool is3D = false,
bool loop = false bool loop = false
) { )
var fileHandle = FAudio.stb_vorbis_open_filename(filePath, out var error, IntPtr.Zero); {
if (error != 0) var fileHandle = FAudio.stb_vorbis_open_filename(filePath, out var error, IntPtr.Zero);
{ if (error != 0)
Logger.LogError("Error opening OGG file!"); {
throw new AudioLoadException("Error opening OGG file!"); Logger.LogError("Error opening OGG file!");
} throw new AudioLoadException("Error opening OGG file!");
}
var info = FAudio.stb_vorbis_get_info(fileHandle); var info = FAudio.stb_vorbis_get_info(fileHandle);
return new StreamingSoundOgg( return new StreamingSoundOgg(
device, device,
fileHandle, fileHandle,
info, info,
is3D, is3D,
loop loop
); );
} }
internal StreamingSoundOgg( internal StreamingSoundOgg(
AudioDevice device, AudioDevice device,
IntPtr fileHandle, IntPtr fileHandle,
FAudio.stb_vorbis_info info, FAudio.stb_vorbis_info info,
bool is3D, bool is3D,
bool loop bool loop
) : base(device, (ushort) info.channels, info.sample_rate, is3D, loop) ) : base(device, (ushort) info.channels, info.sample_rate, is3D, loop)
{ {
FileHandle = fileHandle; FileHandle = fileHandle;
Info = info; Info = info;
buffer = new float[BUFFER_SIZE]; buffer = new float[BUFFER_SIZE];
device.AddDynamicSoundInstance(this); device.AddDynamicSoundInstance(this);
} }
protected override void AddBuffer( protected override void AddBuffer(
out float[] buffer, out float[] buffer,
out uint bufferOffset, out uint bufferOffset,
out uint bufferLength, out uint bufferLength,
out bool reachedEnd out bool reachedEnd
) { )
buffer = this.buffer; {
buffer = this.buffer;
/* NOTE: this function returns samples per channel, not total samples */ /* NOTE: this function returns samples per channel, not total samples */
var samples = FAudio.stb_vorbis_get_samples_float_interleaved( var samples = FAudio.stb_vorbis_get_samples_float_interleaved(
FileHandle, FileHandle,
Info.channels, Info.channels,
buffer, buffer,
buffer.Length buffer.Length
); );
var sampleCount = samples * Info.channels; var sampleCount = samples * Info.channels;
bufferOffset = 0; bufferOffset = 0;
bufferLength = (uint) sampleCount; bufferLength = (uint) sampleCount;
reachedEnd = sampleCount < buffer.Length; reachedEnd = sampleCount < buffer.Length;
} }
protected override void SeekStart() protected override void SeekStart()
{ {
FAudio.stb_vorbis_seek_start(FileHandle); FAudio.stb_vorbis_seek_start(FileHandle);
} }
protected override void Destroy() protected override void Destroy()
{ {
FAudio.stb_vorbis_close(FileHandle); FAudio.stb_vorbis_close(FileHandle);
} }
} }
} }