188 lines
5.3 KiB
C#
188 lines
5.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using ANX.Framework.Audio;
|
|
using ANX.Framework.Media;
|
|
using ANX.Framework.NonXNA.Development;
|
|
using ANX.Framework.NonXNA.SoundSystem;
|
|
using SharpDX;
|
|
using SharpDX.Multimedia;
|
|
using SharpDX.XAudio2;
|
|
|
|
// This file is part of the ANX.Framework created by the
|
|
// "ANX.Framework developer group" and released under the Ms-PL license.
|
|
// For details see: http://anxframework.codeplex.com/license
|
|
|
|
namespace ANX.SoundSystem.Windows.XAudio
|
|
{
|
|
[Developer("AstrorEnales")]
|
|
public class XAudioSong : ISong
|
|
{
|
|
#if !WINDOWSMETRO
|
|
private FileStream oggFileStream;
|
|
private XAudioOggInputStream oggStream;
|
|
#endif
|
|
private SourceVoice source;
|
|
private readonly AudioBuffer[] buffers = new AudioBuffer[2];
|
|
private int nextBufferIndex;
|
|
private XAudio2 device;
|
|
private string filepath;
|
|
private bool isInitialized;
|
|
|
|
public TimeSpan Duration { get; private set; }
|
|
public TimeSpan PlayPosition { get; private set; }
|
|
public MediaState State { get; private set; }
|
|
|
|
public XAudioSong(XAudio2 device, Uri uri)
|
|
{
|
|
filepath = Uri.UnescapeDataString(uri.AbsolutePath);
|
|
this.device = device;
|
|
// TODO: duration
|
|
}
|
|
|
|
public XAudioSong(XAudio2 device, string filepath, int duration)
|
|
{
|
|
this.filepath = filepath;
|
|
this.device = device;
|
|
Duration = new TimeSpan(0, 0, 0, 0, duration);
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
if (Path.GetExtension(filepath).ToLower() != ".ogg")
|
|
throw new NotImplementedException("Currently only ogg playback is implemented!");
|
|
|
|
isInitialized = true;
|
|
PlayPosition = TimeSpan.Zero;
|
|
State = MediaState.Stopped;
|
|
|
|
//TODO: Provide a Metro implementation.
|
|
#if !WINDOWSMETRO
|
|
oggFileStream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
oggStream = new XAudioOggInputStream(oggFileStream);
|
|
var format = new WaveFormat(oggStream.SampleRate, 16, oggStream.Channels);
|
|
source = new SourceVoice(device, format, true);
|
|
source.BufferEnd += StreamBuffer;
|
|
|
|
for (int index = 0; index < buffers.Length; index++)
|
|
buffers[index] = new AudioBuffer { Stream = new DataStream(XAudioOggInputStream.BufferLength, false, true) };
|
|
#endif
|
|
}
|
|
|
|
private void StreamBuffer(IntPtr handle)
|
|
{
|
|
if (Stream() == false)
|
|
Stop();
|
|
}
|
|
|
|
public void Play()
|
|
{
|
|
if (isInitialized == false)
|
|
Init();
|
|
|
|
if (State == MediaState.Playing)
|
|
return;
|
|
|
|
if (State == MediaState.Stopped)
|
|
{
|
|
Rewind();
|
|
|
|
for (int index = 0; index < buffers.Length; index++)
|
|
if (Stream() == false)
|
|
return;
|
|
}
|
|
|
|
source.Start();
|
|
State = MediaState.Playing;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
if (State == MediaState.Stopped)
|
|
return;
|
|
|
|
State = MediaState.Stopped;
|
|
source.Stop();
|
|
source.FlushSourceBuffers();
|
|
}
|
|
|
|
public void Pause()
|
|
{
|
|
if (State == MediaState.Paused)
|
|
return;
|
|
|
|
State = MediaState.Paused;
|
|
source.Stop();
|
|
}
|
|
|
|
public void Resume()
|
|
{
|
|
Play();
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
}
|
|
|
|
public void GetVisualizationData(VisualizationData data)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
internal void Rewind()
|
|
{
|
|
PlayPosition = TimeSpan.Zero;
|
|
#if !WINDOWSMETRO
|
|
oggFileStream.Position = 0;
|
|
oggStream = new XAudioOggInputStream(oggFileStream);
|
|
#endif
|
|
}
|
|
|
|
internal bool Stream()
|
|
{
|
|
#if !WINDOWSMETRO
|
|
AudioBuffer currentBuffer = buffers[nextBufferIndex];
|
|
currentBuffer.Stream.Position = 0;
|
|
int size = oggStream.Read(currentBuffer.Stream);
|
|
if (size <= 0)
|
|
return false;
|
|
|
|
var channels = (AudioChannels)oggStream.Channels;
|
|
PlayPosition = PlayPosition.Add(SoundEffect.GetSampleDuration(size, oggStream.SampleRate, channels));
|
|
currentBuffer.PlayLength = size / 4;
|
|
source.SubmitSourceBuffer(currentBuffer, null);
|
|
nextBufferIndex = (nextBufferIndex + 1) % buffers.Length;
|
|
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
#if !WINDOWSMETRO
|
|
if (oggFileStream != null)
|
|
{
|
|
oggFileStream.Close();
|
|
oggFileStream.Dispose();
|
|
oggFileStream = null;
|
|
}
|
|
|
|
if (oggStream != null)
|
|
{
|
|
oggStream = null;
|
|
}
|
|
#endif
|
|
|
|
if (source != null)
|
|
{
|
|
source.FlushSourceBuffers();
|
|
source.DestroyVoice();
|
|
source.Dispose();
|
|
}
|
|
|
|
source = null;
|
|
}
|
|
}
|
|
}
|