documentation + fix some edge cases

pull/50/head
cosmonaut 2023-08-02 18:26:27 -07:00
parent 0500d94930
commit 9a854506f3
13 changed files with 65 additions and 40 deletions

View File

@ -3,6 +3,10 @@ using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
/// <summary>
/// Contains raw audio data in the format specified by Format.
/// Submit this to a SourceVoice to play audio.
/// </summary>
public class AudioBuffer : AudioResource
{
IntPtr BufferDataPtr;
@ -24,11 +28,22 @@ namespace MoonWorks.Audio
OwnsBufferData = ownsBufferData;
}
/// <summary>
/// Create another AudioBuffer from this audio buffer.
/// It will not own the buffer data.
/// </summary>
/// <param name="offset">Offset in bytes from the top of the original buffer.</param>
/// <param name="length">Length in bytes of the new buffer.</param>
/// <returns></returns>
public AudioBuffer CreateSubBuffer(int offset, uint length)
{
return new AudioBuffer(Device, Format, BufferDataPtr + offset, length, false);
}
/// <summary>
/// Create an FAudioBuffer struct from this AudioBuffer.
/// </summary>
/// <param name="loop">Whether we should set the FAudioBuffer to loop.</param>
public FAudio.FAudioBuffer ToFAudioBuffer(bool loop = false)
{
return new FAudio.FAudioBuffer

View File

@ -4,6 +4,9 @@ using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
/// <summary>
/// Streamable audio in Ogg format.
/// </summary>
public class AudioDataOgg : AudioDataStreamable
{
private IntPtr FileDataPtr = IntPtr.Zero;

View File

@ -4,6 +4,9 @@ using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
/// <summary>
/// Streamable audio in QOA format.
/// </summary>
public class AudioDataQoa : AudioDataStreamable
{
private IntPtr QoaHandle = IntPtr.Zero;

View File

@ -1,5 +1,8 @@
namespace MoonWorks.Audio
{
/// <summary>
/// Use this in conjunction with a StreamingVoice to play back streaming audio data.
/// </summary>
public abstract class AudioDataStreamable : AudioResource
{
public Format Format { get; protected set; }

View File

@ -6,9 +6,14 @@ namespace MoonWorks.Audio
{
public static class AudioDataWav
{
// mostly borrowed from https://github.com/FNA-XNA/FNA/blob/b71b4a35ae59970ff0070dea6f8620856d8d4fec/src/Audio/SoundEffect.cs#L385
/// <summary>
/// Create an AudioBuffer containing all the WAV audio data in a file.
/// </summary>
/// <returns></returns>
public unsafe static AudioBuffer CreateBuffer(AudioDevice device, string filePath)
{
// mostly borrowed from https://github.com/FNA-XNA/FNA/blob/b71b4a35ae59970ff0070dea6f8620856d8d4fec/src/Audio/SoundEffect.cs#L385
// WaveFormatEx data
ushort wFormatTag;
ushort nChannels;

View File

@ -1,33 +0,0 @@
using System.IO;
namespace MoonWorks.Audio
{
public static class AudioUtils
{
public static Format ReadWaveFormat(string filePath, out int dataLength)
{
var fileInfo = new FileInfo(filePath);
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using BinaryReader br = new BinaryReader(fs);
fs.Position = 20;
var formatTag = br.ReadInt16();
fs.Position = 22;
var channels = br.ReadInt16();
fs.Position = 24;
var sampleRate = br.ReadInt32();
fs.Position = 34;
var bitsPerSample = br.ReadInt16();
fs.Position = 40;
dataLength = br.ReadInt32();
return new Format
{
Tag = (FormatTag) formatTag,
Channels = (ushort) channels,
SampleRate = (uint) sampleRate,
BitsPerSample = (ushort) bitsPerSample
};
}
}
}

View File

@ -1,5 +1,8 @@
namespace MoonWorks.Audio
{
/// <summary>
/// PersistentVoice should be used when you need to maintain a long-term reference to a source voice.
/// </summary>
public class PersistentVoice : SourceVoice, IPoolable<PersistentVoice>
{
public PersistentVoice(AudioDevice device, Format format) : base(device, format)

View File

@ -3,7 +3,9 @@ using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
// sound instances can send their audio to this voice to add reverb
/// <summary>
/// Use this in conjunction with SourceVoice.SetReverbEffectChain to add reverb to a voice.
/// </summary>
public unsafe class ReverbEffect : SubmixVoice
{
public ReverbEffect(AudioDevice audioDevice) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec)

View File

@ -1,6 +1,8 @@
namespace MoonWorks.Audio
{
// NOTE: all sounds played with a SoundSequence must have the same audio format!
/// <summary>
/// Plays back a series of AudioBuffers in sequence. Set the OnSoundNeeded callback to add AudioBuffers dynamically.
/// </summary>
public class SoundSequence : SourceVoice
{
public int NeedSoundThreshold = 0;

View File

@ -10,6 +10,8 @@ namespace MoonWorks.Audio
private Format format;
public Format Format => format;
protected bool PlaybackInitiated;
/// <summary>
/// The number of buffers queued in the voice.
/// This includes the currently playing voice!
@ -170,6 +172,13 @@ namespace MoonWorks.Audio
}
}
public override void Reset()
{
Stop();
PlaybackInitiated = false;
base.Reset();
}
protected override unsafe void Destroy()
{
Stop();

View File

@ -3,6 +3,9 @@ using System.Runtime.InteropServices;
namespace MoonWorks.Audio
{
/// <summary>
/// Use in conjunction with an AudioDataStreamable object to play back streaming audio data.
/// </summary>
public class StreamingVoice : SourceVoice, IPoolable<StreamingVoice>
{
private const int BUFFER_COUNT = 3;
@ -54,6 +57,12 @@ namespace MoonWorks.Audio
}
}
public override void Reset()
{
Unload();
base.Reset();
}
public override void Update()
{
lock (StateLock)
@ -67,7 +76,7 @@ namespace MoonWorks.Audio
}
}
protected void QueueBuffers()
private void QueueBuffers()
{
int buffersNeeded = BUFFER_COUNT - (int) BuffersQueued; // don't get got by uint underflow!
for (int i = 0; i < buffersNeeded; i += 1)
@ -76,7 +85,7 @@ namespace MoonWorks.Audio
}
}
protected unsafe void AddBuffer()
private unsafe void AddBuffer()
{
var buffer = buffers[nextBufferIndex];
nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;

View File

@ -2,6 +2,9 @@ using System;
namespace MoonWorks.Audio
{
/// <summary>
/// SourceVoices can send audio to a SubmixVoice for convenient effects processing.
/// </summary>
public class SubmixVoice : Voice
{
public SubmixVoice(

View File

@ -1,7 +1,8 @@
namespace MoonWorks.Audio
{
/// <summary>
/// These voices are intended for playing one-off sound effects that don't have a long term reference.
/// TransientVoice is intended for playing one-off sound effects that don't have a long term reference.
/// It will be automatically returned to the source voice pool once it is done playing back.
/// </summary>
public class TransientVoice : SourceVoice, IPoolable<TransientVoice>
{
@ -18,7 +19,7 @@ namespace MoonWorks.Audio
{
lock (StateLock)
{
if (BuffersQueued == 0)
if (PlaybackInitiated && BuffersQueued == 0)
{
Return();
}