205 lines
6.1 KiB
C#

using System;
using ANX.Framework;
using ANX.Framework.Audio;
using ANX.Framework.NonXNA.Development;
using ANX.Framework.NonXNA.SoundSystem;
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 XAudioSoundEffectInstance : ISoundEffectInstance
{
#region Private
private SourceVoice source;
private float currentPitch;
private float currentPan;
private bool currentIsLooped;
private readonly XAudioSoundEffect parent;
private float[] panMatrix;
#endregion
#region Public
public bool IsLooped
{
get { return currentIsLooped; }
set
{
currentIsLooped = value;
// TODO: set real parameter
if(value)
throw new NotImplementedException("IsLooped is currently not implemented for XAudio!");
}
}
public float Pan
{
get { return currentPan; }
set
{
currentPan = MathHelper.Clamp(value, -1f, 1f);
UpdateSourcePan();
}
}
public float Pitch
{
get { return currentPitch; }
set
{
currentPitch = value;
source.SetFrequencyRatio(value);
// TODO: pitch <= 1 is working, but greater isn't
if (value > 1f)
throw new NotImplementedException("Pitch greater than 1f is currently not implemented for XAudio!");
}
}
public SoundState State { get; private set; }
public float Volume
{
get { return source.Volume; }
set { source.SetVolume(value, 0); }
}
#endregion
#region Constructor
internal XAudioSoundEffectInstance(XAudio2 device, XAudioSoundEffect setParent)
{
parent = setParent;
currentIsLooped = false;
currentPan = 0f;
currentPitch = 1f;
State = SoundState.Stopped;
source = new SourceVoice(device, setParent.WaveFormat, true);
source.SubmitSourceBuffer(setParent.AudioBuffer, setParent.DecodedPacketsInfo);
source.StreamEnd += StreamEnd;
}
#endregion
private void StreamEnd()
{
State = SoundState.Stopped;
}
#region Play
public void Play()
{
if (State == SoundState.Playing)
return;
State = SoundState.Playing;
source.Start();
}
#endregion
#region Pause
public void Pause()
{
State = SoundState.Paused;
throw new NotImplementedException();
}
#endregion
#region Stop
public void Stop(bool immediate)
{
if (State == SoundState.Stopped)
return;
if (immediate == false)
return;
State = SoundState.Stopped;
source.Stop();
}
#endregion
#region Resume
public void Resume()
{
State = SoundState.Playing;
throw new NotImplementedException();
}
#endregion
#region UpdateSourcePan (TODO)
private void UpdateSourcePan()
{
var sourceChannelCount = parent.WaveFormat.Channels;
var destinationChannelCount = Creator.MasteringVoice.VoiceDetails.InputChannelCount;
InitializePanMatrix(destinationChannelCount);
var leftPanValue = 1f - currentPan;
var rightPanValue = 1f + currentPan;
panMatrix[0] = leftPanValue;
panMatrix[1] = rightPanValue;
// TODO: get the channel mask which is strangely only available on Windows8
//switch (Creator.MasteringVoice.ChannelMask)
//{
// case (int)Speakers.Quad:
// panMatrix[2] = leftPanValue;
// panMatrix[3] = rightPanValue;
// break;
// case (int)Speakers.FourPointOne:
// panMatrix[3] = leftPanValue;
// panMatrix[4] = rightPanValue;
// break;
// case (int)Speakers.FivePointOne:
// case (int)Speakers.SevenPointOne:
// case (int)Speakers.FivePointOneSurround:
// panMatrix[4] = leftPanValue;
// panMatrix[5] = rightPanValue;
// break;
// case (int)Speakers.SevenPointOneSurround:
// panMatrix[4] = panMatrix[6] = leftPanValue;
// panMatrix[5] = panMatrix[7] = rightPanValue;
// break;
//}
source.SetOutputMatrix(sourceChannelCount, destinationChannelCount, panMatrix);
}
#endregion
#region InitializePanMatrix
private void InitializePanMatrix(int size)
{
if (panMatrix == null || panMatrix.Length < size)
panMatrix = new float[Math.Max(size, 8)];
for (var index = 0; index < panMatrix.Length; index++)
panMatrix[index] = 1f;
}
#endregion
#region Apply3D (TODO)
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
{
throw new NotImplementedException();
}
#endregion
#region Dispose
public void Dispose()
{
if (source != null)
{
source.StreamEnd -= StreamEnd;
source.DestroyVoice();
source.Dispose();
}
source = null;
}
#endregion
}
}