fix static sound loading + window title

main
cosmonaut 2021-01-19 21:33:25 -08:00
parent adf047955e
commit ec28d17a75
9 changed files with 110 additions and 44 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MoonWorks.Audio namespace MoonWorks.Audio
@ -17,6 +18,8 @@ namespace MoonWorks.Audio
private FAudio.FAudioVoiceSends reverbSends; private FAudio.FAudioVoiceSends reverbSends;
private readonly List<WeakReference<DynamicSoundInstance>> dynamicSoundInstances = new List<WeakReference<DynamicSoundInstance>>();
public unsafe AudioDevice() public unsafe AudioDevice()
{ {
FAudio.FAudioCreate(out var handle, 0, 0); FAudio.FAudioCreate(out var handle, 0, 0);
@ -177,16 +180,39 @@ namespace MoonWorks.Audio
/* Init reverb sends */ /* Init reverb sends */
reverbSends = new FAudio.FAudioVoiceSends(); reverbSends = new FAudio.FAudioVoiceSends
reverbSends.SendCount = 2; {
reverbSends.pSends = Marshal.AllocHGlobal( SendCount = 2,
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()
{
for (var i = dynamicSoundInstances.Count - 1; i >= 0; i--)
{
var weakReference = dynamicSoundInstances[i];
if (weakReference.TryGetTarget(out var dynamicSoundInstance))
{
dynamicSoundInstance.Update();
}
else
{
dynamicSoundInstances.RemoveAt(i);
}
}
}
internal void AddDynamicSoundInstance(DynamicSoundInstance instance)
{
dynamicSoundInstances.Add(new WeakReference<DynamicSoundInstance>(instance));
}
} }
} }

View File

@ -4,10 +4,13 @@ using System.IO;
namespace MoonWorks.Audio namespace MoonWorks.Audio
{ {
/// <summary> /// <summary>
/// For streaming long playback. /// For streaming long playback. Reads an OGG file.
/// </summary> /// </summary>
public class DynamicSound : Sound, IDisposable public class DynamicSound : Sound, IDisposable
{ {
internal override FAudio.FAudioWaveFormatEx Format { get; }
// 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; }
@ -15,9 +18,7 @@ namespace MoonWorks.Audio
private bool IsDisposed; private bool IsDisposed;
// FIXME: what should this value be? public DynamicSound(AudioDevice device, FileInfo fileInfo) : base(device)
public DynamicSound(FileInfo fileInfo, ushort channels, uint samplesPerSecond) : base(channels, samplesPerSecond)
{ {
FileHandle = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero); FileHandle = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero);
@ -28,6 +29,26 @@ namespace MoonWorks.Audio
} }
Info = FAudio.stb_vorbis_get_info(FileHandle); Info = FAudio.stb_vorbis_get_info(FileHandle);
var blockAlign = (ushort)(4 * Info.channels);
Format = new FAudio.FAudioWaveFormatEx
{
wFormatTag = 3,
wBitsPerSample = 32,
nChannels = (ushort) Info.channels,
nBlockAlign = blockAlign,
nSamplesPerSec = Info.sample_rate,
nAvgBytesPerSec = blockAlign * Info.sample_rate,
cbSize = 0
};
}
public DynamicSoundInstance CreateInstance()
{
var instance = new DynamicSoundInstance(Device, this, false);
Device.AddDynamicSoundInstance(instance);
return instance;
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View File

@ -16,7 +16,7 @@ namespace MoonWorks.Audio
public override SoundState State { get; protected set; } public override SoundState State { get; protected set; }
public DynamicSoundInstance( internal DynamicSoundInstance(
AudioDevice device, AudioDevice device,
DynamicSound parent, DynamicSound parent,
bool is3D bool is3D
@ -26,6 +26,8 @@ namespace MoonWorks.Audio
queuedSizes = new List<uint>(); queuedSizes = new List<uint>();
buffer = new float[DynamicSound.BUFFER_SIZE]; buffer = new float[DynamicSound.BUFFER_SIZE];
State = SoundState.Stopped;
} }
public void Play() public void Play()
@ -60,7 +62,7 @@ namespace MoonWorks.Audio
ClearBuffers(); ClearBuffers();
} }
private void Update() internal void Update()
{ {
if (State != SoundState.Playing) if (State != SoundState.Playing)
{ {
@ -117,7 +119,7 @@ namespace MoonWorks.Audio
buffer.Length buffer.Length
); );
IntPtr next = Marshal.AllocHGlobal(buffer.Length); IntPtr next = Marshal.AllocHGlobal(buffer.Length * sizeof(float));
Marshal.Copy(buffer, 0, next, buffer.Length); Marshal.Copy(buffer, 0, next, buffer.Length);
lock (queuedBuffers) lock (queuedBuffers)

View File

@ -2,25 +2,12 @@ namespace MoonWorks.Audio
{ {
public abstract class Sound public abstract class Sound
{ {
internal FAudio.FAudioWaveFormatEx Format { get; } internal AudioDevice Device { get; }
internal abstract FAudio.FAudioWaveFormatEx Format { get; }
/* NOTE: we only support float decoding! WAV sucks! */ public Sound(AudioDevice device)
public Sound(
ushort channels,
uint samplesPerSecond
) {
var blockAlign = (ushort) (4 * channels);
Format = new FAudio.FAudioWaveFormatEx
{ {
wFormatTag = 3, Device = device;
wBitsPerSample = 32,
nChannels = channels,
nBlockAlign = blockAlign,
nSamplesPerSec = samplesPerSecond,
nAvgBytesPerSec = blockAlign * samplesPerSecond,
cbSize = 0
};
} }
} }
} }

View File

@ -6,13 +6,15 @@ namespace MoonWorks.Audio
{ {
public class StaticSound : Sound, IDisposable public class StaticSound : Sound, IDisposable
{ {
internal override FAudio.FAudioWaveFormatEx Format { get; }
internal FAudio.FAudioBuffer Handle; internal FAudio.FAudioBuffer Handle;
private bool IsDisposed;
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 FromOgg(FileInfo fileInfo) private bool IsDisposed;
public static StaticSound LoadOgg(AudioDevice device, FileInfo fileInfo)
{ {
var filePointer = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero); var filePointer = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero);
@ -21,12 +23,20 @@ namespace MoonWorks.Audio
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 = (uint)(info.sample_rate * info.channels); var bufferSize = FAudio.stb_vorbis_stream_length_in_samples(filePointer);
var buffer = new float[bufferSize]; var buffer = new float[bufferSize];
FAudio.stb_vorbis_get_samples_float_interleaved(
filePointer,
info.channels,
buffer,
(int) bufferSize
);
FAudio.stb_vorbis_close(filePointer); FAudio.stb_vorbis_close(filePointer);
return new StaticSound( return new StaticSound(
device,
buffer, buffer,
0, 0,
(ushort) info.channels, (ushort) info.channels,
@ -35,25 +45,42 @@ namespace MoonWorks.Audio
} }
public StaticSound( public StaticSound(
AudioDevice device,
float[] buffer, float[] buffer,
uint bufferOffset, uint bufferOffset,
ushort channels, ushort channels,
uint samplesPerSecond uint samplesPerSecond
) : base(channels, samplesPerSecond) { ) : base(device) {
var bufferLength = 4 * buffer.Length; var blockAlign = (ushort)(4 * channels);
Format = new FAudio.FAudioWaveFormatEx
{
wFormatTag = 3,
wBitsPerSample = 32,
nChannels = channels,
nBlockAlign = blockAlign,
nSamplesPerSec = samplesPerSecond,
nAvgBytesPerSec = blockAlign * samplesPerSecond
};
var bufferLengthInBytes = sizeof(float) * buffer.Length;
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) bufferLength; Handle.AudioBytes = (uint) bufferLengthInBytes;
Handle.pAudioData = Marshal.AllocHGlobal((int) bufferLength); Handle.pAudioData = Marshal.AllocHGlobal(bufferLengthInBytes);
Marshal.Copy(buffer, (int) bufferOffset, Handle.pAudioData, (int) bufferLength); Marshal.Copy(buffer, (int) bufferOffset, Handle.pAudioData, buffer.Length);
Handle.PlayBegin = 0; Handle.PlayBegin = 0;
Handle.PlayLength = ( Handle.PlayLength = 0;
Handle.AudioBytes /
(uint) Format.nChannels / LoopStart = 0;
(uint) (Format.wBitsPerSample / 8) LoopLength = 0;
); }
public StaticSoundInstance CreateInstance()
{
return new StaticSoundInstance(Device, this, false, true);
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)

View File

@ -38,6 +38,7 @@ namespace MoonWorks.Audio
) : base(device, parent, is3D) ) : base(device, parent, is3D)
{ {
Loop = loop; Loop = loop;
State = SoundState.Stopped;
} }
public void Play() public void Play()

View File

@ -82,6 +82,7 @@ namespace MoonWorks
HandleSDLEvents(); HandleSDLEvents();
Input.Update(); Input.Update();
AudioDevice.Update();
Update(timestep); Update(timestep);

View File

@ -24,7 +24,7 @@ namespace MoonWorks
ScreenMode = windowCreateInfo.ScreenMode; ScreenMode = windowCreateInfo.ScreenMode;
Handle = SDL.SDL_CreateWindow( Handle = SDL.SDL_CreateWindow(
"MoonWorks.GraphicsTest", windowCreateInfo.WindowTitle,
SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED,
SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED,
(int)windowCreateInfo.WindowWidth, (int)windowCreateInfo.WindowWidth,

View File

@ -2,6 +2,7 @@ namespace MoonWorks
{ {
public struct WindowCreateInfo public struct WindowCreateInfo
{ {
public string WindowTitle;
public uint WindowWidth; public uint WindowWidth;
public uint WindowHeight; public uint WindowHeight;
public ScreenMode ScreenMode; public ScreenMode ScreenMode;