Fixed issue #994 in XAudio and working on XAudio properties

This commit is contained in:
SND\AstrorEnales_cp 2012-09-29 18:37:18 +00:00 committed by Konstantin Koch
parent a07d5c69b6
commit c5145397bf
8 changed files with 342 additions and 385 deletions

View File

@ -75,9 +75,9 @@ namespace ANX.Framework.Audio
#endregion
#region Private
private static List<SoundEffectInstance> fireAndForgetInstances;
private List<WeakReference> children;
internal ISoundEffect nativeSoundEffect;
private static readonly List<SoundEffectInstance> fireAndForgetInstances;
private readonly List<WeakReference> children;
internal ISoundEffect NativeSoundEffect;
#endregion
#region Public
@ -85,7 +85,7 @@ namespace ANX.Framework.Audio
{
get
{
return nativeSoundEffect.Duration;
return NativeSoundEffect.Duration;
}
}
@ -123,7 +123,7 @@ namespace ANX.Framework.Audio
: this()
{
var creator = GetCreator();
nativeSoundEffect = creator.CreateSoundEffect(this, stream);
NativeSoundEffect = creator.CreateSoundEffect(this, stream);
}
public SoundEffect(byte[] buffer, int sampleRate, AudioChannels channels)
@ -135,7 +135,7 @@ namespace ANX.Framework.Audio
: this()
{
var creator = GetCreator();
nativeSoundEffect = creator.CreateSoundEffect(this, buffer, offset, count, sampleRate, channels, loopStart, loopLength);
NativeSoundEffect = creator.CreateSoundEffect(this, buffer, offset, count, sampleRate, channels, loopStart, loopLength);
}
~SoundEffect()
@ -168,16 +168,15 @@ namespace ANX.Framework.Audio
#region GetSampleDuration
public static TimeSpan GetSampleDuration(int sizeInBytes, int sampleRate, AudioChannels channels)
{
float sizeMulBlockAlign = sizeInBytes / ((int)channels * 2);
return TimeSpan.FromMilliseconds((double)(sizeMulBlockAlign * 1000f / (float)sampleRate));
float sizeMulBlockAlign = (float)sizeInBytes / ((int)channels * 2);
return TimeSpan.FromMilliseconds(sizeMulBlockAlign * 1000f / sampleRate);
}
#endregion
#region GetSampleSizeInBytes
public static int GetSampleSizeInBytes(TimeSpan duration, int sampleRate,
AudioChannels channels)
public static int GetSampleSizeInBytes(TimeSpan duration, int sampleRate, AudioChannels channels)
{
int timeMulSamples = (int)(duration.TotalMilliseconds * (double)((float)sampleRate / 1000f));
int timeMulSamples = (int)(duration.TotalMilliseconds * (sampleRate / 1000f));
return (timeMulSamples + timeMulSamples % (int)channels) * ((int)channels * 2);
}
#endregion
@ -195,12 +194,12 @@ namespace ANX.Framework.Audio
try
{
SoundEffectInstance newInstance = new SoundEffectInstance(this, true)
{
Volume = volume,
Pitch = pitch,
Pan = pan,
};
var newInstance = new SoundEffectInstance(this, true)
{
Volume = volume,
Pitch = pitch,
Pan = pan,
};
children.Add(new WeakReference(newInstance));
@ -228,26 +227,22 @@ namespace ANX.Framework.Audio
return;
IsDisposed = true;
nativeSoundEffect.Dispose();
nativeSoundEffect = null;
NativeSoundEffect.Dispose();
NativeSoundEffect = null;
List<WeakReference> weakRefs = new List<WeakReference>(children);
var weakRefs = new List<WeakReference>(children);
lock (fireAndForgetInstances)
{
foreach (WeakReference current in weakRefs)
{
SoundEffectInstance soundInstance =
current.Target as SoundEffectInstance;
var soundInstance = current.Target as SoundEffectInstance;
if (soundInstance == null)
continue;
if (soundInstance != null)
{
if (soundInstance.IsFireAndForget)
{
fireAndForgetInstances.Remove(soundInstance);
}
soundInstance.Dispose();
}
if (soundInstance.IsFireAndForget)
fireAndForgetInstances.Remove(soundInstance);
soundInstance.Dispose();
}
}

View File

@ -15,8 +15,6 @@ namespace ANX.Framework.Audio
public class SoundEffectInstance : IDisposable
{
#region Private
private SoundEffect parent;
private ISoundEffectInstance nativeInstance;
internal bool IsFireAndForget
@ -27,93 +25,47 @@ namespace ANX.Framework.Audio
#endregion
#region Public
#region IsDisposed
public bool IsDisposed
{
get;
private set;
}
#endregion
public bool IsDisposed { get; private set; }
#region IsLooped
public virtual bool IsLooped
{
get
{
return nativeInstance.IsLooped;
}
set
{
nativeInstance.IsLooped = value;
}
}
#endregion
public virtual bool IsLooped
{
get { return nativeInstance.IsLooped; }
set { nativeInstance.IsLooped = value; }
}
#region Pan
public float Pan
{
get
{
return nativeInstance.Pan;
}
set
{
nativeInstance.Pan = value;
}
}
#endregion
public float Pan
{
get { return nativeInstance.Pan; }
set { nativeInstance.Pan = value; }
}
#region Pitch
public float Pitch
{
get
{
return nativeInstance.Pitch;
}
set
{
nativeInstance.Pitch = value;
}
}
#endregion
public float Pitch
{
get { return nativeInstance.Pitch; }
set { nativeInstance.Pitch = value; }
}
#region State
public SoundState State
{
get
{
return nativeInstance.State;
}
}
#endregion
public SoundState State
{
get { return nativeInstance.State; }
}
#region Volume
public float Volume
{
get
{
return nativeInstance.Volume;
}
set
{
nativeInstance.Volume = value;
}
}
#endregion
public float Volume
{
get { return nativeInstance.Volume; }
set { nativeInstance.Volume = value; }
}
#endregion
#region Constructor
protected SoundEffectInstance()
{
}
protected SoundEffectInstance()
{
}
internal SoundEffectInstance(SoundEffect setParent, bool setIsFireAndForget)
internal SoundEffectInstance(SoundEffect setParent, bool setIsFireAndForget)
{
parent = setParent;
IsFireAndForget = setIsFireAndForget;
nativeInstance = GetCreator().CreateSoundEffectInstance(
setParent.nativeSoundEffect);
nativeInstance = GetCreator().CreateSoundEffectInstance(setParent.NativeSoundEffect);
}
~SoundEffectInstance()
@ -132,7 +84,7 @@ namespace ANX.Framework.Audio
#region Apply3D
public void Apply3D(AudioListener listener, AudioEmitter emitter)
{
Apply3D(new AudioListener[] { listener }, emitter);
Apply3D(new[] { listener }, emitter);
}
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)

View File

@ -91,6 +91,10 @@
<Project>{068EB2E9-963C-4E1B-8831-E25011F11FFE}</Project>
<Name>ANX.PlatformSystem.Windows</Name>
</ProjectReference>
<ProjectReference Include="..\..\RenderSystems\ANX.RenderSystem.Windows.DX10\ANX.RenderSystem.Windows.DX10.csproj">
<Project>{5BE49183-2F6F-4527-AC90-D816911FCF90}</Project>
<Name>ANX.RenderSystem.Windows.DX10</Name>
</ProjectReference>
<ProjectReference Include="..\..\SoundSystems\ANX.SoundSystem.OpenAL\ANX.SoundSystem.OpenAL.csproj">
<Project>{14EF49AB-6D3F-458D-9D5C-D120B86EDD7A}</Project>
<Name>ANX.SoundSystem.OpenAL</Name>

View File

@ -1,4 +1,3 @@
using System;
using ANX.Framework;
using ANX.Framework.Audio;
@ -8,51 +7,45 @@ using ANX.Framework.Audio;
namespace AudioSample
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SoundEffect sound;
public class Game1 : Game
{
private GraphicsDeviceManager graphics;
private SoundEffect sound;
private float timer;
private float duration;
float timer;
float duration;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "SampleContent";
}
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "SampleContent";
}
protected override void LoadContent()
{
sound = Content.Load<SoundEffect>("Sounds\\testsound");
timer = duration = (float)sound.Duration.TotalSeconds;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void UnloadContent()
{
}
protected override void LoadContent()
{
sound = Content.Load<SoundEffect>("Sounds\\testsound");
timer = duration = (float)sound.Duration.TotalSeconds;
}
protected override void Update(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timer >= duration)
{
timer -= duration;
sound.Play(1f, 1f, 0f);
}
protected override void UnloadContent()
{
}
base.Update(gameTime);
}
protected override void Update(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timer >= duration)
{
timer -= duration;
sound.Play();
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}

View File

@ -11,8 +11,8 @@ namespace AudioSample
{
static void Main(string[] args)
{
AddInSystemFactory.Instance.SetPreferredSystem(AddInType.SoundSystem, "OpenAL");
//AddInSystemFactory.Instance.SetPreferredSystem(AddInType.SoundSystem, "XAudio");
//AddInSystemFactory.Instance.SetPreferredSystem(AddInType.SoundSystem, "OpenAL");
AddInSystemFactory.Instance.SetPreferredSystem(AddInType.SoundSystem, "XAudio");
using (Game1 game = new Game1())
{

View File

@ -13,120 +13,98 @@ using SharpDX.XAudio2;
namespace ANX.SoundSystem.Windows.XAudio
{
public class Creator : ISoundSystemCreator
{
{
private XAudio2 device;
private MasteringVoice masteringVoice;
private float distanceScale;
private float dopplerScale;
private float speedOfSound;
internal static MasteringVoice MasteringVoice { get; private set; }
#region Public
#region Name
public string Name
{
get { return "XAudio"; }
}
#endregion
#region Priority
public int Priority
{
get { return 10; }
}
#endregion
#region IsSupported
public bool IsSupported
{
get
{
//TODO: this is just a very basic version of test for support
return OSInformation.IsWindows;
}
}
#endregion
public bool IsSupported
{
get { return OSInformation.IsWindows; }
}
public float DistanceScale
{
get
{
return 1f;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
public float DistanceScale
{
get { return distanceScale; }
set
{
distanceScale = value;
// TODO: actually set the parameter to XAudio
}
}
public float DopplerScale
{
get
{
return 1f;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
{
get { return dopplerScale; }
set
{
dopplerScale = value;
// TODO: actually set the parameter to XAudio
}
}
public float MasterVolume
{
get
{
return masteringVoice.Volume;
//throw new NotImplementedException();
}
set
{
masteringVoice.SetVolume(value, 0);
//throw new NotImplementedException();
}
}
public float MasterVolume
{
get { return MasteringVoice.Volume; }
set { MasteringVoice.SetVolume(value, 0); }
}
public float SpeedOfSound
public float SpeedOfSound
{
get
{
return 1f;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
get { return speedOfSound; }
set
{
speedOfSound = value;
// TODO: actually set the parameter to XAudio
}
}
#endregion
#region Constructor
public Creator()
{
{
distanceScale = 1f;
dopplerScale = 1f;
speedOfSound = 343.5f;
device = new XAudio2();
masteringVoice = new MasteringVoice(device);
}
MasteringVoice = new MasteringVoice(device, XAudio2.DefaultChannels, XAudio2.DefaultSampleRate);
}
~Creator()
{
if (masteringVoice != null)
{
masteringVoice.Dispose();
masteringVoice = null;
}
~Creator()
{
if (MasteringVoice != null)
MasteringVoice.Dispose();
if (device != null)
{
device.Dispose();
device = null;
}
}
#endregion
if (device != null)
device.Dispose();
MasteringVoice = null;
device = null;
}
#endregion
public IAudioListener CreateAudioListener()
{
{
PreventSystemChange();
throw new NotImplementedException();
}
public IAudioEmitter CreateAudioEmitter()
{
{
PreventSystemChange();
throw new NotImplementedException();
}
@ -154,21 +132,24 @@ namespace ANX.SoundSystem.Windows.XAudio
#endregion
public IMicrophone CreateMicrophone(Microphone managedMicrophone)
{
{
PreventSystemChange();
throw new NotImplementedException();
}
public ReadOnlyCollection<Microphone> GetAllMicrophones()
{
{
PreventSystemChange();
throw new NotImplementedException();
}
public int GetDefaultMicrophone(ReadOnlyCollection<Microphone> allMicrophones)
{
{
PreventSystemChange();
throw new NotImplementedException();
}
private void PreventSystemChange()
private static void PreventSystemChange()
{
AddInSystemFactory.Instance.PreventSystemChange(AddInType.SoundSystem);
}

View File

@ -2,8 +2,8 @@
using System.IO;
using ANX.Framework.Audio;
using ANX.Framework.NonXNA.SoundSystem;
using SharpDX.XAudio2;
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.
@ -14,38 +14,35 @@ namespace ANX.SoundSystem.Windows.XAudio
public class XAudioSoundEffect : ISoundEffect
{
#region Private
internal SoundEffect parent;
internal SoundEffect Parent;
private TimeSpan duration;
internal WaveFormat waveFormat;
internal AudioBuffer audioBuffer;
internal WaveFormat WaveFormat;
internal AudioBuffer AudioBuffer;
internal uint[] DecodedPacketsInfo;
#endregion
#region Public
public TimeSpan Duration
{
get
{
return duration;
}
}
#endregion
public TimeSpan Duration
{
get { return duration; }
}
#endregion
#region Constructor
internal XAudioSoundEffect(SoundEffect setParent, Stream stream)
{
parent = setParent;
Parent = setParent;
CreateFromStream(stream);
}
internal XAudioSoundEffect(SoundEffect setParent, byte[] buffer, int offset, int count, int sampleRate,
AudioChannels channels, int loopStart, int loopLength)
{
parent = setParent;
Parent = setParent;
using (MemoryStream stream = new MemoryStream())
using (var stream = new MemoryStream())
{
BinaryWriter writer = new BinaryWriter(stream);
var writer = new BinaryWriter(stream);
writer.Write(buffer, offset, count);
stream.Position = 0;
CreateFromStream(stream);
@ -62,16 +59,16 @@ namespace ANX.SoundSystem.Windows.XAudio
private void CreateFromStream(Stream stream)
{
var soundStream = new SoundStream(stream);
waveFormat = soundStream.Format;
audioBuffer = new AudioBuffer
WaveFormat = soundStream.Format;
AudioBuffer = new AudioBuffer
{
Stream = soundStream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = BufferFlags.EndOfStream
};
float sizeMulBlockAlign = soundStream.Length / (waveFormat.Channels * 2);
duration = TimeSpan.FromMilliseconds((double)(sizeMulBlockAlign * 1000f / (float)waveFormat.SampleRate));
float sizeMulBlockAlign = (float)soundStream.Length / (WaveFormat.Channels * 2);
duration = TimeSpan.FromMilliseconds(sizeMulBlockAlign * 1000f / WaveFormat.SampleRate);
DecodedPacketsInfo = soundStream.DecodedPacketsInfo;
@ -82,8 +79,8 @@ namespace ANX.SoundSystem.Windows.XAudio
#region Dispose
public void Dispose()
{
waveFormat = null;
audioBuffer = null;
WaveFormat = null;
AudioBuffer = null;
}
#endregion
}

View File

@ -1,4 +1,5 @@
using System;
using ANX.Framework;
using ANX.Framework.Audio;
using ANX.Framework.NonXNA.SoundSystem;
using SharpDX.XAudio2;
@ -9,147 +10,181 @@ using SharpDX.XAudio2;
namespace ANX.SoundSystem.Windows.XAudio
{
public class XAudioSoundEffectInstance : ISoundEffectInstance
{
#region Private
private XAudioSoundEffect parent;
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
private SourceVoice source;
#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!");
}
}
#region Public
public bool IsLooped
{
get
{
return false;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
}
public float Pan
{
get { return currentPan; }
set
{
currentPan = MathHelper.Clamp(value, -1f, 1f);
UpdateSourcePan();
}
}
public float Pan
{
get
{
return 0f;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
}
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 float Pitch
{
get
{
return 1f;
//throw new NotImplementedException();
}
set
{
//throw new NotImplementedException();
}
}
public SoundState State { get; private set; }
public SoundState State
{
get;
private set;
}
public float Volume
{
get { return source.Volume; }
set { source.SetVolume(value, 0); }
}
#endregion
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);
source.SubmitSourceBuffer(setParent.AudioBuffer, setParent.DecodedPacketsInfo);
}
#endregion
#region Constructor
internal XAudioSoundEffectInstance(XAudio2 device, XAudioSoundEffect setParent)
{
parent = setParent;
#region Play
public void Play()
{
if (State == SoundState.Playing)
return;
State = SoundState.Stopped;
State = SoundState.Playing;
source.Start();
}
#endregion
var sourceVoice = new SourceVoice(device, setParent.waveFormat);
sourceVoice.SubmitSourceBuffer(setParent.audioBuffer, setParent.DecodedPacketsInfo);
sourceVoice.Start();
}
#endregion
#region Pause
public void Pause()
{
State = SoundState.Paused;
}
#endregion
#region Play
public void Play()
{
if (State != SoundState.Playing)
{
State = SoundState.Playing;
source.Start();
}
}
#endregion
#region Stop
public void Stop(bool immediate)
{
if (State == SoundState.Stopped)
return;
#region Pause
public void Pause()
{
if (State != SoundState.Paused)
{
State = SoundState.Paused;
}
}
#endregion
if (immediate == false)
return;
#region Stop
public void Stop(bool immediate)
{
if (State == SoundState.Stopped)
return;
State = SoundState.Stopped;
source.Stop();
}
#endregion
if (immediate)
{
State = SoundState.Stopped;
source.Stop();
}
}
#endregion
#region Resume
public void Resume()
{
State = SoundState.Playing;
}
#endregion
#region Resume
public void Resume()
{
if (State != SoundState.Playing)
{
State = SoundState.Playing;
}
}
#endregion
#region UpdateSourcePan (TODO)
private void UpdateSourcePan()
{
var sourceChannelCount = parent.WaveFormat.Channels;
var destinationChannelCount = Creator.MasteringVoice.VoiceDetails.InputChannelCount;
InitializePanMatrix(destinationChannelCount);
#region Apply3D (TODO)
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
{
throw new NotImplementedException();
}
#endregion
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;
#region Dispose
public void Dispose()
{
if (source != null)
{
source.Dispose();
source = null;
}
}
#endregion
}
// 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.Dispose();
source = null;
}
#endregion
}
}