documentation + fix some edge cases
parent
0500d94930
commit
9a854506f3
|
@ -3,6 +3,10 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
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
|
public class AudioBuffer : AudioResource
|
||||||
{
|
{
|
||||||
IntPtr BufferDataPtr;
|
IntPtr BufferDataPtr;
|
||||||
|
@ -24,11 +28,22 @@ namespace MoonWorks.Audio
|
||||||
OwnsBufferData = ownsBufferData;
|
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)
|
public AudioBuffer CreateSubBuffer(int offset, uint length)
|
||||||
{
|
{
|
||||||
return new AudioBuffer(Device, Format, BufferDataPtr + offset, length, false);
|
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)
|
public FAudio.FAudioBuffer ToFAudioBuffer(bool loop = false)
|
||||||
{
|
{
|
||||||
return new FAudio.FAudioBuffer
|
return new FAudio.FAudioBuffer
|
||||||
|
|
|
@ -4,6 +4,9 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Streamable audio in Ogg format.
|
||||||
|
/// </summary>
|
||||||
public class AudioDataOgg : AudioDataStreamable
|
public class AudioDataOgg : AudioDataStreamable
|
||||||
{
|
{
|
||||||
private IntPtr FileDataPtr = IntPtr.Zero;
|
private IntPtr FileDataPtr = IntPtr.Zero;
|
||||||
|
|
|
@ -4,6 +4,9 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Streamable audio in QOA format.
|
||||||
|
/// </summary>
|
||||||
public class AudioDataQoa : AudioDataStreamable
|
public class AudioDataQoa : AudioDataStreamable
|
||||||
{
|
{
|
||||||
private IntPtr QoaHandle = IntPtr.Zero;
|
private IntPtr QoaHandle = IntPtr.Zero;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Use this in conjunction with a StreamingVoice to play back streaming audio data.
|
||||||
|
/// </summary>
|
||||||
public abstract class AudioDataStreamable : AudioResource
|
public abstract class AudioDataStreamable : AudioResource
|
||||||
{
|
{
|
||||||
public Format Format { get; protected set; }
|
public Format Format { get; protected set; }
|
||||||
|
|
|
@ -6,9 +6,14 @@ namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
public static class AudioDataWav
|
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)
|
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
|
// WaveFormatEx data
|
||||||
ushort wFormatTag;
|
ushort wFormatTag;
|
||||||
ushort nChannels;
|
ushort nChannels;
|
||||||
|
|
|
@ -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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,8 @@
|
||||||
namespace MoonWorks.Audio
|
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 class PersistentVoice : SourceVoice, IPoolable<PersistentVoice>
|
||||||
{
|
{
|
||||||
public PersistentVoice(AudioDevice device, Format format) : base(device, format)
|
public PersistentVoice(AudioDevice device, Format format) : base(device, format)
|
||||||
|
|
|
@ -3,7 +3,9 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
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 unsafe class ReverbEffect : SubmixVoice
|
||||||
{
|
{
|
||||||
public ReverbEffect(AudioDevice audioDevice) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec)
|
public ReverbEffect(AudioDevice audioDevice) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
namespace MoonWorks.Audio
|
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 class SoundSequence : SourceVoice
|
||||||
{
|
{
|
||||||
public int NeedSoundThreshold = 0;
|
public int NeedSoundThreshold = 0;
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace MoonWorks.Audio
|
||||||
private Format format;
|
private Format format;
|
||||||
public Format Format => format;
|
public Format Format => format;
|
||||||
|
|
||||||
|
protected bool PlaybackInitiated;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of buffers queued in the voice.
|
/// The number of buffers queued in the voice.
|
||||||
/// This includes the currently playing 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()
|
protected override unsafe void Destroy()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
|
@ -3,6 +3,9 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Use in conjunction with an AudioDataStreamable object to play back streaming audio data.
|
||||||
|
/// </summary>
|
||||||
public class StreamingVoice : SourceVoice, IPoolable<StreamingVoice>
|
public class StreamingVoice : SourceVoice, IPoolable<StreamingVoice>
|
||||||
{
|
{
|
||||||
private const int BUFFER_COUNT = 3;
|
private const int BUFFER_COUNT = 3;
|
||||||
|
@ -54,6 +57,12 @@ namespace MoonWorks.Audio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
Unload();
|
||||||
|
base.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
lock (StateLock)
|
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!
|
int buffersNeeded = BUFFER_COUNT - (int) BuffersQueued; // don't get got by uint underflow!
|
||||||
for (int i = 0; i < buffersNeeded; i += 1)
|
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];
|
var buffer = buffers[nextBufferIndex];
|
||||||
nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;
|
nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;
|
||||||
|
|
|
@ -2,6 +2,9 @@ using System;
|
||||||
|
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// SourceVoices can send audio to a SubmixVoice for convenient effects processing.
|
||||||
|
/// </summary>
|
||||||
public class SubmixVoice : Voice
|
public class SubmixVoice : Voice
|
||||||
{
|
{
|
||||||
public SubmixVoice(
|
public SubmixVoice(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
namespace MoonWorks.Audio
|
namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public class TransientVoice : SourceVoice, IPoolable<TransientVoice>
|
public class TransientVoice : SourceVoice, IPoolable<TransientVoice>
|
||||||
{
|
{
|
||||||
|
@ -18,7 +19,7 @@ namespace MoonWorks.Audio
|
||||||
{
|
{
|
||||||
lock (StateLock)
|
lock (StateLock)
|
||||||
{
|
{
|
||||||
if (BuffersQueued == 0)
|
if (PlaybackInitiated && BuffersQueued == 0)
|
||||||
{
|
{
|
||||||
Return();
|
Return();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue