Created
August 15, 2019 19:29
-
-
Save ThirdPartyNinjas/bfc1c53ec4604d60e8be169b992e3fdb to your computer and use it in GitHub Desktop.
FNA Vorbis Player
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Xna.Framework.Audio; | |
using System; | |
namespace Fenix.Audio | |
{ | |
public class Vorbis : IDisposable | |
{ | |
public int Channels { get; private set; } | |
public int SampleRate { get; private set; } | |
public float Duration { get; private set; } | |
public SoundState SoundState { get; private set; } | |
public Vorbis(string assetPath) | |
{ | |
stbVorbisData = FAudio.stb_vorbis_open_filename(assetPath, out int error, IntPtr.Zero); | |
var info = FAudio.stb_vorbis_get_info(stbVorbisData); | |
Channels = info.channels; | |
SampleRate = (int)info.sample_rate; | |
Duration = FAudio.stb_vorbis_stream_length_in_seconds(stbVorbisData); | |
SoundState = SoundState.Stopped; | |
dynamicSoundEffectInstance = new DynamicSoundEffectInstance(SampleRate, (Channels == 1) ? AudioChannels.Mono : AudioChannels.Stereo); | |
sampleReadBuffer = new float[SampleRate * Channels / 10]; | |
} | |
public void Play(int playCount = 1, Action<Vorbis> playCompletedAction = null) | |
{ | |
if(SoundState != SoundState.Stopped) | |
{ | |
// todo: log warning | |
return; | |
} | |
Reset(); | |
FillBuffer(); | |
this.playCount = playCount; | |
this.playCompletedAction = playCompletedAction; | |
dynamicSoundEffectInstance.BufferNeeded += DynamicSoundEffectInstance_BufferNeeded; | |
dynamicSoundEffectInstance.Play(); | |
SoundState = SoundState.Playing; | |
} | |
public void Pause() | |
{ | |
if (SoundState != SoundState.Playing) | |
{ | |
// todo: log warning | |
return; | |
} | |
dynamicSoundEffectInstance.Pause(); | |
SoundState = SoundState.Paused; | |
} | |
public void Resume() | |
{ | |
if (SoundState != SoundState.Paused) | |
{ | |
// todo: log warning | |
return; | |
} | |
dynamicSoundEffectInstance.Resume(); | |
SoundState = SoundState.Playing; | |
} | |
public void Stop() | |
{ | |
if (SoundState != SoundState.Playing && SoundState != SoundState.Paused) | |
{ | |
// todo: log warning | |
return; | |
} | |
dynamicSoundEffectInstance.Stop(); | |
dynamicSoundEffectInstance.BufferNeeded -= DynamicSoundEffectInstance_BufferNeeded; | |
playCompletedAction = null; | |
SoundState = SoundState.Stopped; | |
} | |
public void Reset() | |
{ | |
FAudio.stb_vorbis_seek_start(stbVorbisData); | |
} | |
public DynamicSoundEffectInstance GetInstance() | |
{ | |
return dynamicSoundEffectInstance; | |
} | |
private void DynamicSoundEffectInstance_BufferNeeded(object sender, EventArgs e) | |
{ | |
FillBuffer(); | |
} | |
private void FillBuffer() | |
{ | |
var framesRead = ReadFrames(sampleReadBuffer, SampleRate / 10); | |
if (framesRead != 0) | |
{ | |
dynamicSoundEffectInstance.SubmitFloatBufferEXT(sampleReadBuffer, 0, framesRead * Channels); | |
} | |
else if (dynamicSoundEffectInstance.PendingBufferCount == 0) | |
{ | |
if (playCount > 0) | |
playCount--; | |
if (playCount == 0) | |
{ | |
Action<Vorbis> pca = playCompletedAction; | |
Stop(); | |
pca?.Invoke(this); | |
} | |
else | |
{ | |
Reset(); | |
FillBuffer(); | |
} | |
} | |
} | |
private int ReadFrames(float[] interleavedSamples, int frameCount) | |
{ | |
return FAudio.stb_vorbis_get_samples_float_interleaved(stbVorbisData, Channels, interleavedSamples, frameCount * Channels); | |
} | |
public void Dispose() | |
{ | |
playCompletedAction = null; | |
if (stbVorbisData != IntPtr.Zero) | |
{ | |
FAudio.stb_vorbis_close(stbVorbisData); | |
stbVorbisData = IntPtr.Zero; | |
} | |
} | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (disposed) | |
return; | |
Dispose(); | |
disposed = true; | |
} | |
private bool disposed = false; | |
private IntPtr stbVorbisData = IntPtr.Zero; | |
private int playCount; | |
private DynamicSoundEffectInstance dynamicSoundEffectInstance; | |
private float[] sampleReadBuffer; | |
private Action<Vorbis> playCompletedAction = null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment