From ef734ddcd37f0c86d4bcc49da6f44bcad08c38b4 Mon Sep 17 00:00:00 2001 From: "SND\\AstrorEnales_cp" Date: Sat, 29 Sep 2012 22:01:15 +0000 Subject: [PATCH] Implemented the MediaPlayer and MediaQueue classes as preparation for native Song playback. Also added the FrameworkDispatcher calls in the Game class. Checking for possible fire and forget sound instances to be disposed in the FrameworkDispatcher update chain. --- ANX.Framework/ANX.Framework.csproj | 1 + ANX.Framework/Audio/AudioEngine.cs | 42 ++- ANX.Framework/Audio/SoundEffect.cs | 103 +++--- ANX.Framework/Audio/SoundEffectInstance.cs | 9 +- .../XactParser/XactGeneralSettingsRpcCurve.cs | 22 +- .../XactGeneralSettingsRpcCurvePoint.cs | 24 +- .../XactParser/XactGeneralSettingsVariable.cs | 32 +- ANX.Framework/FrameworkDispatcher.cs | 3 + ANX.Framework/Game.cs | 5 + ANX.Framework/Media/MediaPlayer.cs | 314 +++++++++--------- ANX.Framework/Media/MediaQueue.cs | 161 ++++++--- ANX.Framework/Media/Song.cs | 85 +++-- ANX.Framework/Media/VisualizationData.cs | 38 ++- ANX.Framework/NonXNA/AddInSystemFactory.cs | 1 + ANX.Framework/NonXNA/SoundSystem/ISong.cs | 19 ++ .../NonXNA/SoundSystem/ISoundSystemCreator.cs | 36 +- ANX.Framework/Properties/AssemblyInfo.cs | 6 +- .../GraphicsDeviceWindowsGL3.cs | 20 +- Samples/WpfEditor/MainWindow.xaml.cs | 28 +- Samples/WpfEditor/WpfEditor.csproj | 4 + .../ANX.SoundSystem.OpenAL/Creator.cs | 144 ++++---- .../OpenALSoundEffectInstance.cs | 145 ++++---- .../ANX.SoundSystem.PsVita/Creator.cs | 9 +- .../ANX.SoundSystem.Windows.XAudio/Creator.cs | 12 +- .../XAudioSoundEffectInstance.cs | 14 +- 25 files changed, 638 insertions(+), 639 deletions(-) create mode 100644 ANX.Framework/NonXNA/SoundSystem/ISong.cs diff --git a/ANX.Framework/ANX.Framework.csproj b/ANX.Framework/ANX.Framework.csproj index 4a863414..29384d5b 100644 --- a/ANX.Framework/ANX.Framework.csproj +++ b/ANX.Framework/ANX.Framework.csproj @@ -446,6 +446,7 @@ + diff --git a/ANX.Framework/Audio/AudioEngine.cs b/ANX.Framework/Audio/AudioEngine.cs index 98c4c0bf..dbdd688c 100644 --- a/ANX.Framework/Audio/AudioEngine.cs +++ b/ANX.Framework/Audio/AudioEngine.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; +using System.Linq; using ANX.Framework.Audio.XactParser; using ANX.Framework.NonXNA; using ANX.Framework.NonXNA.Development; @@ -74,32 +75,29 @@ namespace ANX.Framework.Audio #region GetCategory public AudioCategory GetCategory(string name) { - for (int index = 0; index < generalSettings.Categories.Length; index++) - if (generalSettings.Categories[index].Name == name) - return generalSettings.Categories[index]; + foreach (AudioCategory category in generalSettings.Categories.Where(category => category.Name == name)) + return category; - return new AudioCategory(name); + return new AudioCategory(name); } - #endregion + #endregion #region GetGlobalVariable public float GetGlobalVariable(string name) - { - foreach (var variable in generalSettings.Variables) - if (variable.Name == name) - return variable.StartingValue; + { + foreach (var variable in generalSettings.Variables.Where(variable => variable.Name == name)) + return variable.StartingValue; return 0f; } #endregion #region SetGlobalVariable - public void SetGlobalVariable(string name, float value) - { - foreach (var variable in generalSettings.Variables) - if (variable.Name == name) - variable.StartingValue = MathHelper.Clamp(value, variable.MinValue, variable.MaxValue); - } + public void SetGlobalVariable(string name, float value) + { + foreach (var variable in generalSettings.Variables.Where(variable => variable.Name == name)) + variable.StartingValue = MathHelper.Clamp(value, variable.MinValue, variable.MaxValue); + } #endregion #region Update (TODO) @@ -112,14 +110,14 @@ namespace ANX.Framework.Audio #region Dispose protected virtual void Dispose(bool disposing) { - if (IsDisposed == false) - { - if (Disposing != null) - Disposing(this, EventArgs.Empty); + if (IsDisposed) + return; - IsDisposed = true; - generalSettings = null; - } + if (Disposing != null) + Disposing(this, EventArgs.Empty); + + IsDisposed = true; + generalSettings = null; } public void Dispose() diff --git a/ANX.Framework/Audio/SoundEffect.cs b/ANX.Framework/Audio/SoundEffect.cs index f0f131e9..ee3d367d 100644 --- a/ANX.Framework/Audio/SoundEffect.cs +++ b/ANX.Framework/Audio/SoundEffect.cs @@ -17,61 +17,29 @@ namespace ANX.Framework.Audio public sealed class SoundEffect : IDisposable { #region Static - #region DistanceScale - public static float DistanceScale - { - get - { - return GetCreator().DistanceScale; - } - set - { - GetCreator().DistanceScale = value; - } - } - #endregion + public static float DistanceScale + { + get { return GetCreator().DistanceScale; } + set { GetCreator().DistanceScale = value; } + } - #region DopplerScale - public static float DopplerScale - { - get - { - return GetCreator().DopplerScale; - } - set - { - GetCreator().DopplerScale = value; - } - } - #endregion + public static float DopplerScale + { + get { return GetCreator().DopplerScale; } + set { GetCreator().DopplerScale = value; } + } - #region MasterVolume - public static float MasterVolume - { - get - { - return GetCreator().MasterVolume; - } - set - { - GetCreator().MasterVolume = value; - } - } - #endregion + public static float MasterVolume + { + get { return GetCreator().MasterVolume; } + set { GetCreator().MasterVolume = value; } + } - #region SpeedOfSound - public static float SpeedOfSound - { - get - { - return GetCreator().SpeedOfSound; - } - set - { - GetCreator().SpeedOfSound = value; - } - } - #endregion + public static float SpeedOfSound + { + get { return GetCreator().SpeedOfSound; } + set { GetCreator().SpeedOfSound = value; } + } #endregion #region Private @@ -131,11 +99,13 @@ namespace ANX.Framework.Audio { } - public SoundEffect(byte[] buffer, int offset, int count, int sampleRate, AudioChannels channels, int loopStart, int loopLength) + public SoundEffect(byte[] buffer, int offset, int count, int sampleRate, AudioChannels channels, int loopStart, + int loopLength) : 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() @@ -204,9 +174,7 @@ namespace ANX.Framework.Audio children.Add(new WeakReference(newInstance)); lock (fireAndForgetInstances) - { fireAndForgetInstances.Add(newInstance); - } newInstance.Play(); } @@ -220,8 +188,27 @@ namespace ANX.Framework.Audio } #endregion - #region Dispose - public void Dispose() + #region RecycleStoppedFireAndForgetInstances + internal static void RecycleStoppedFireAndForgetInstances() + { + lock (fireAndForgetInstances) + { + var instancesToDispose = new List(); + foreach (SoundEffectInstance current in fireAndForgetInstances) + if (current.State == SoundState.Stopped) + instancesToDispose.Add(current); + + foreach (SoundEffectInstance current in instancesToDispose) + { + current.Dispose(); + fireAndForgetInstances.Remove(current); + } + } + } + #endregion + + #region Dispose + public void Dispose() { if (IsDisposed) return; diff --git a/ANX.Framework/Audio/SoundEffectInstance.cs b/ANX.Framework/Audio/SoundEffectInstance.cs index 9afce232..656de509 100644 --- a/ANX.Framework/Audio/SoundEffectInstance.cs +++ b/ANX.Framework/Audio/SoundEffectInstance.cs @@ -16,13 +16,8 @@ namespace ANX.Framework.Audio { #region Private private ISoundEffectInstance nativeInstance; - - internal bool IsFireAndForget - { - get; - private set; - } - #endregion + internal bool IsFireAndForget { get; private set; } + #endregion #region Public public bool IsDisposed { get; private set; } diff --git a/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurve.cs b/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurve.cs index 00f5073c..3cdd3865 100644 --- a/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurve.cs +++ b/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurve.cs @@ -10,26 +10,14 @@ namespace ANX.Framework.Audio.XactParser internal class XactGeneralSettingsRpcCurve { // what variable this curve involves - public ushort VariableIndex - { - get; - private set; - } + public ushort VariableIndex { get; private set; } - // which parameter the curve affects refer to the above constants - public short Parameters - { - get; - private set; - } + // which parameter the curve affects refer to the above constants + public short Parameters { get; private set; } - public XactGeneralSettingsRpcCurvePoint[] Points - { - get; - private set; - } + public XactGeneralSettingsRpcCurvePoint[] Points { get; private set; } - public XactGeneralSettingsRpcCurve(BinaryReader reader) + public XactGeneralSettingsRpcCurve(BinaryReader reader) { VariableIndex = reader.ReadUInt16(); byte numberOfCurvePoints = reader.ReadByte(); diff --git a/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurvePoint.cs b/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurvePoint.cs index 65a98885..45f76648 100644 --- a/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurvePoint.cs +++ b/ANX.Framework/Audio/XactParser/XactGeneralSettingsRpcCurvePoint.cs @@ -17,29 +17,15 @@ namespace ANX.Framework.Audio.XactParser SinCos = 0x03, } - public float X - { - get; - private set; - } + public float X { get; private set; } + public float Y { get; private set; } + public CurveType Type { get; private set; } - public float Y - { - get; - private set; - } - - public CurveType Type - { - get; - private set; - } - - public XactGeneralSettingsRpcCurvePoint(BinaryReader reader) + public XactGeneralSettingsRpcCurvePoint(BinaryReader reader) { X = reader.ReadSingle(); Y = reader.ReadSingle(); - Type = (XactGeneralSettingsRpcCurvePoint.CurveType)reader.ReadByte(); + Type = (CurveType)reader.ReadByte(); } } } diff --git a/ANX.Framework/Audio/XactParser/XactGeneralSettingsVariable.cs b/ANX.Framework/Audio/XactParser/XactGeneralSettingsVariable.cs index 3dc12b87..8490e47e 100644 --- a/ANX.Framework/Audio/XactParser/XactGeneralSettingsVariable.cs +++ b/ANX.Framework/Audio/XactParser/XactGeneralSettingsVariable.cs @@ -17,35 +17,15 @@ namespace ANX.Framework.Audio.XactParser Reserved = 0x08, } - public VariableFlags Flags - { - get; - private set; - } - - public float StartingValue - { - get; - set; - } - - public float MinValue - { - get; - private set; - } - - public float MaxValue - { - get; - private set; - } - - public string Name; + public VariableFlags Flags { get; private set; } + public float StartingValue { get; set; } + public float MinValue { get; private set; } + public float MaxValue { get; private set; } + public string Name; public XactGeneralSettingsVariable(BinaryReader reader) { - Flags = (XactGeneralSettingsVariable.VariableFlags)reader.ReadByte(); + Flags = (VariableFlags)reader.ReadByte(); StartingValue = reader.ReadSingle(); MinValue = reader.ReadSingle(); MaxValue = reader.ReadSingle(); diff --git a/ANX.Framework/FrameworkDispatcher.cs b/ANX.Framework/FrameworkDispatcher.cs index 112b14fb..6295a38c 100644 --- a/ANX.Framework/FrameworkDispatcher.cs +++ b/ANX.Framework/FrameworkDispatcher.cs @@ -1,4 +1,5 @@ using System; +using ANX.Framework.Audio; using ANX.Framework.NonXNA.Development; // This file is part of the ANX.Framework created by the @@ -18,6 +19,8 @@ namespace ANX.Framework { if (OnUpdate != null) OnUpdate(); + + SoundEffect.RecycleStoppedFireAndForgetInstances(); } } } diff --git a/ANX.Framework/Game.cs b/ANX.Framework/Game.cs index 3f3183ce..b15de804 100644 --- a/ANX.Framework/Game.cs +++ b/ANX.Framework/Game.cs @@ -6,6 +6,7 @@ using ANX.Framework.Graphics; using ANX.Framework.NonXNA; using ANX.Framework.NonXNA.Development; using ANX.Framework.NonXNA.PlatformSystem; +using ANX.Framework.NonXNA.SoundSystem; #endregion // Using Statements @@ -78,6 +79,8 @@ namespace ANX.Framework AddSystemCreator(); AddSystemCreator(); + FrameworkDispatcher.Update(); + CreateGameHost(); Logger.Info("creating ContentManager"); @@ -151,6 +154,8 @@ namespace ANX.Framework updateable.Update(gameTime); } } + + FrameworkDispatcher.Update(); } protected virtual void Draw(GameTime gameTime) diff --git a/ANX.Framework/Media/MediaPlayer.cs b/ANX.Framework/Media/MediaPlayer.cs index e83c4baa..e3afdd24 100644 --- a/ANX.Framework/Media/MediaPlayer.cs +++ b/ANX.Framework/Media/MediaPlayer.cs @@ -1,4 +1,5 @@ using System; +using ANX.Framework.NonXNA.Development; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. @@ -6,189 +7,170 @@ using System; namespace ANX.Framework.Media { - public static class MediaPlayer - { - #region Events - public static event EventHandler ActiveSongChanged; - public static event EventHandler MediaStateChanged; - #endregion + [PercentageComplete(100)] + [TestState(TestStateAttribute.TestState.Untested)] + [Developer("AstrorEnales")] + public static class MediaPlayer + { + #region Events + public static event EventHandler ActiveSongChanged; + public static event EventHandler MediaStateChanged; + #endregion - #region Public - #region IsShuffled (TODO) - public static bool IsShuffled - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - #endregion + private static bool isRepeating; + private static float volume; + private static MediaState currentState; + internal static float VolumeToUse + { + get { return IsMuted ? 0f : volume; } + } - #region IsRepeating (TODO) - public static bool IsRepeating - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - #endregion + #region Public + public static bool IsShuffled { get; set; } - #region Volume (TODO) - public static float Volume - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - #endregion + public static bool IsRepeating + { + get { return isRepeating; } + set { isRepeating = value; } + } - #region IsMuted (TODO) - public static bool IsMuted - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - #endregion + public static float Volume + { + get { return volume; } + set { volume = MathHelper.Clamp(value, 0f, 1f); } + } - #region IsVisualizationEnabled (TODO) - public static bool IsVisualizationEnabled - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - #endregion + public static bool IsVisualizationEnabled { get; set; } + public static bool IsMuted { get; set; } + public static MediaQueue Queue { get; private set; } + public static MediaState State + { + get { return currentState; } + private set + { + if (currentState == value) + return; - public static MediaQueue Queue - { - get; - private set; - } + currentState = value; + MediaStateChanged(null, EventArgs.Empty); + } + } - #region State (TODO) - public static MediaState State - { - get - { - throw new NotImplementedException(); - } - } - #endregion + public static TimeSpan PlayPosition + { + get + { + return Queue.ActiveSong == null + ? TimeSpan.Zero : Queue.ActiveSong.NativeSong.PlayPosition; + } + } - #region PlayPosition (TODO) - public static TimeSpan PlayPosition - { - get - { - throw new NotImplementedException(); - } - } - #endregion + public static bool GameHasControl + { + get { return true; } + } + #endregion - #region GameHasControl (TODO) - public static bool GameHasControl - { - get - { - throw new NotImplementedException(); - } - } - #endregion - #endregion + #region Constructor + static MediaPlayer() + { + currentState = MediaState.Stopped; + volume = 1f; + isRepeating = false; + IsMuted = false; + IsVisualizationEnabled = false; + IsShuffled = false; + Queue = new MediaQueue(); + FrameworkDispatcher.OnUpdate += Tick; + } + #endregion - #region Constructor - static MediaPlayer() - { - Queue = new MediaQueue(); - } - #endregion + #region Play + public static void Play(Song song) + { + Queue.Play(song); + } - #region Play - public static void Play(Song song) - { - Queue.Play(song); - } - #endregion + public static void Play(SongCollection songCollection) + { + Queue.Play(songCollection); + } - #region Play - public static void Play(SongCollection songCollection) - { - Queue.Play(songCollection); - } - #endregion + public static void Play(SongCollection songCollection, int index) + { + Queue.Play(songCollection, index); + } + #endregion - #region Play (TODO) - public static void Play(SongCollection songCollection, int index) - { - throw new NotImplementedException(); - } - #endregion + #region Pause + public static void Pause() + { + if (Queue.ActiveSong != null) + Queue.ActiveSong.Pause(); + } + #endregion - #region Pause (TODO) - public static void Pause() - { - throw new NotImplementedException(); - } - #endregion + #region Resume + public static void Resume() + { + if (Queue.ActiveSong != null) + Queue.ActiveSong.Resume(); + } + #endregion - #region Resume (TODO) - public static void Resume() - { - throw new NotImplementedException(); - } - #endregion + #region Stop + public static void Stop() + { + Queue.Stop(); + } + #endregion - #region Stop (TODO) - public static void Stop() - { - throw new NotImplementedException(); - } - #endregion + #region MoveNext + public static void MoveNext() + { + Queue.MoveNext(false); + } + #endregion - #region MoveNext - public static void MoveNext() - { - Queue.MoveNext(); - } - #endregion + #region MovePrevious + public static void MovePrevious() + { + Queue.MovePrevious(); + } + #endregion - #region MovePrevious - public static void MovePrevious() - { - Queue.MovePrevious(); - } - #endregion + #region Tick + private static void Tick() + { + if (Queue.ActiveSong == null) + { + State = MediaState.Stopped; + return; + } - #region GetVisualizationData (TODO) - public static void GetVisualizationData(VisualizationData data) - { - throw new NotImplementedException(); - } - #endregion - } + State = Queue.ActiveSong.State; + if (Queue.ActiveSong.State != MediaState.Stopped) + return; + + if (Queue.MoveNext(isRepeating)) + State = MediaState.Playing; + + ActiveSongChanged(null, EventArgs.Empty); + } + #endregion + + #region GetVisualizationData + public static void GetVisualizationData(VisualizationData visualizationData) + { + if (visualizationData == null) + throw new ArgumentNullException("visualizationData"); + + if (IsVisualizationEnabled == false) + return; + + if(Queue.ActiveSong != null) + Queue.ActiveSong.NativeSong.GetVisualizationData(visualizationData); + } + #endregion + } } diff --git a/ANX.Framework/Media/MediaQueue.cs b/ANX.Framework/Media/MediaQueue.cs index b6f85ef5..b919bbc0 100644 --- a/ANX.Framework/Media/MediaQueue.cs +++ b/ANX.Framework/Media/MediaQueue.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using ANX.Framework.NonXNA.Development; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. @@ -7,57 +8,53 @@ using System.Collections.Generic; namespace ANX.Framework.Media { + [PercentageComplete(100)] + [TestState(TestStateAttribute.TestState.Untested)] + [Developer("AstrorEnales")] public sealed class MediaQueue { - #region Private - private List queue; - #endregion + private readonly List queue; #region Public - public int Count - { - get - { - return queue.Count; - } - } + public int Count + { + get { return queue.Count; } + } - public int ActiveSongIndex - { - get; - set; - } + public int ActiveSongIndex { get; set; } - public Song ActiveSong - { - get - { - return queue[ActiveSongIndex]; - } - } + public Song ActiveSong + { + get { return queue.Count <= 0 ? null : queue[ActiveSongIndex]; } + } - public Song this[int index] - { - get - { - return queue[index]; - } - } - #endregion + public Song this[int index] + { + get { return queue[index]; } + } + #endregion #region Constructor internal MediaQueue() { queue = new List(); } + + ~MediaQueue() + { + queue.Clear(); + } #endregion - internal void Play(Song song) + #region Play + internal void Play(Song song) { if (song == null) throw new ArgumentNullException("song"); + Clear(); queue.Add(song); + ActiveSong.Play(); } internal void Play(SongCollection songCollection) @@ -65,29 +62,93 @@ namespace ANX.Framework.Media if (songCollection == null) throw new ArgumentNullException("songCollection"); - queue.AddRange(songCollection); + Clear(); + queue.AddRange(songCollection); + // TODO: check if the shuffle is calculated after each finished song or like this! + if (MediaPlayer.IsShuffled) + Shuffle(); + ActiveSong.Play(); } - internal void MoveNext() - { - if (Count > 0) - { - if (ActiveSongIndex < Count - 1) - ActiveSongIndex++; - else - ActiveSongIndex = 0; - } - } + internal void Play(SongCollection songCollection, int index) + { + if (songCollection == null) + throw new ArgumentNullException("songCollection"); - internal void MovePrevious() + Clear(); + ActiveSongIndex = index; + queue.AddRange(songCollection); + // TODO: check if the shuffle is calculated after each finished song or like this! + if (MediaPlayer.IsShuffled) + Shuffle(); + ActiveSong.Play(); + } + #endregion + + private void Clear() + { + Stop(); + ActiveSongIndex = 0; + queue.Clear(); + } + + internal void Stop() + { + if(ActiveSong != null) + ActiveSong.Stop(); + } + + private void Shuffle() + { + var rand = new Random(); + int n = queue.Count; + while (n > 1) + { + int k = rand.Next(n); + n--; + Song value = queue[k]; + queue[k] = queue[n]; + queue[n] = value; + } + } + + #region MoveNext + internal bool MoveNext(bool stopIfEnded) { - if (Count > 0) - { - if (ActiveSongIndex > 0) - ActiveSongIndex--; - else - ActiveSongIndex = Count - 1; - } + if (Count <= 0) + return false; + + ActiveSong.Stop(); + + if (ActiveSongIndex < Count - 1) + ActiveSongIndex++; + else + { + ActiveSongIndex = 0; + if (stopIfEnded) + return false; + } + + ActiveSong.Play(); + return true; } + #endregion + + #region MovePrevious + internal void MovePrevious() + { + if (Count <= 0) + return; + + ActiveSong.Stop(); + + if (ActiveSongIndex > 0) + ActiveSongIndex--; + else + ActiveSongIndex = Count - 1; + + ActiveSong.Play(); + } + #endregion } } diff --git a/ANX.Framework/Media/Song.cs b/ANX.Framework/Media/Song.cs index 907d553d..99ca374c 100644 --- a/ANX.Framework/Media/Song.cs +++ b/ANX.Framework/Media/Song.cs @@ -1,4 +1,7 @@ using System; +using ANX.Framework.NonXNA; +using ANX.Framework.NonXNA.SoundSystem; +using ANX.Framework.NonXNA.Development; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. @@ -6,29 +9,23 @@ using System; namespace ANX.Framework.Media { + [PercentageComplete(50)] + [Developer("AstrorEnales")] public sealed class Song : IEquatable, IDisposable { - public bool IsDisposed - { - get; - private set; - } + internal ISong NativeSong { get; private set; } + internal MediaState State { get { return NativeSong.State; } } - public string Name - { - get; - private set; - } + #region Public + public bool IsDisposed { get; private set; } + public string Name { get; private set; } - public bool IsRated - { - get - { - return Rating > 0; - } - } + public bool IsRated + { + get { return Rating > 0; } + } - public Artist Artist + public Artist Artist { get { @@ -54,10 +51,7 @@ namespace ANX.Framework.Media public TimeSpan Duration { - get - { - throw new NotImplementedException(); - } + get { return NativeSong.Duration; } } public int Rating @@ -90,11 +84,13 @@ namespace ANX.Framework.Media { throw new NotImplementedException(); } - } + } + #endregion #region Constructor - internal Song(string setName) + internal Song(string setName, Uri uri) { + NativeSong = AddInSystemFactory.Instance.GetDefaultCreator().CreateSong(this, uri); Name = setName; IsDisposed = false; } @@ -105,9 +101,9 @@ namespace ANX.Framework.Media } #endregion - public Song FromUri(string name, Uri uri) + public static Song FromUri(string name, Uri uri) { - throw new NotImplementedException(); + return new Song(name, uri); } public bool Equals(Song other) @@ -125,13 +121,36 @@ namespace ANX.Framework.Media public void Dispose() { - if (IsDisposed == false) - { - IsDisposed = true; - throw new NotImplementedException(); - } + if (IsDisposed) + return; + + IsDisposed = true; + + if(NativeSong != null) + NativeSong.Dispose(); + NativeSong = null; } + internal void Play() + { + NativeSong.Play(); + } + + internal void Stop() + { + NativeSong.Stop(); + } + + internal void Pause() + { + NativeSong.Pause(); + } + + internal void Resume() + { + NativeSong.Resume(); + } + #region ToString public override string ToString() { @@ -149,12 +168,12 @@ namespace ANX.Framework.Media #region Operator overloading public static bool operator ==(Song first, Song second) { - return first.Equals(second); + return first != null && first.Equals(second); } public static bool operator !=(Song first, Song second) { - return first.Equals(second) == false; + return first == null || first.Equals(second) == false; } #endregion } diff --git a/ANX.Framework/Media/VisualizationData.cs b/ANX.Framework/Media/VisualizationData.cs index 975d1793..b6ac2d36 100644 --- a/ANX.Framework/Media/VisualizationData.cs +++ b/ANX.Framework/Media/VisualizationData.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.ObjectModel; // This file is part of the ANX.Framework created by the @@ -7,22 +6,25 @@ using System.Collections.ObjectModel; namespace ANX.Framework.Media { - public class VisualizationData - { - public ReadOnlyCollection Frequencies - { - get - { - throw new NotImplementedException(); - } - } + public class VisualizationData + { + internal readonly float[] FrequencyData; + internal readonly float[] SampleData; - public ReadOnlyCollection Samples - { - get - { - throw new NotImplementedException(); - } - } - } + public ReadOnlyCollection Frequencies + { + get { return new ReadOnlyCollection(FrequencyData); } + } + + public ReadOnlyCollection Samples + { + get { return new ReadOnlyCollection(SampleData); } + } + + public VisualizationData() + { + FrequencyData = new float[256]; + SampleData = new float[256]; + } + } } diff --git a/ANX.Framework/NonXNA/AddInSystemFactory.cs b/ANX.Framework/NonXNA/AddInSystemFactory.cs index 251480dd..9b874fc4 100644 --- a/ANX.Framework/NonXNA/AddInSystemFactory.cs +++ b/ANX.Framework/NonXNA/AddInSystemFactory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using ANX.Framework.NonXNA.PlatformSystem; using ANX.Framework.NonXNA.Reflection; +using ANX.Framework.NonXNA.SoundSystem; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. diff --git a/ANX.Framework/NonXNA/SoundSystem/ISong.cs b/ANX.Framework/NonXNA/SoundSystem/ISong.cs new file mode 100644 index 00000000..dbf0e1e5 --- /dev/null +++ b/ANX.Framework/NonXNA/SoundSystem/ISong.cs @@ -0,0 +1,19 @@ +using System; +using ANX.Framework.Media; + +namespace ANX.Framework.NonXNA.SoundSystem +{ + public interface ISong : IDisposable + { + TimeSpan Duration { get; } + TimeSpan PlayPosition { get; } + MediaState State { get; } + + void Play(); + void Stop(); + void Pause(); + void Resume(); + void Update(); + void GetVisualizationData(VisualizationData data); + } +} diff --git a/ANX.Framework/NonXNA/SoundSystem/ISoundSystemCreator.cs b/ANX.Framework/NonXNA/SoundSystem/ISoundSystemCreator.cs index dd1494cc..6d09b291 100644 --- a/ANX.Framework/NonXNA/SoundSystem/ISoundSystemCreator.cs +++ b/ANX.Framework/NonXNA/SoundSystem/ISoundSystemCreator.cs @@ -1,41 +1,23 @@ +using System; using System.IO; using ANX.Framework.Audio; -using ANX.Framework.NonXNA.SoundSystem; using System.Collections.ObjectModel; +using ANX.Framework.Media; // 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.Framework.NonXNA +namespace ANX.Framework.NonXNA.SoundSystem { public interface ISoundSystemCreator : ICreator { - float DistanceScale - { - get; - set; - } + float DistanceScale { get; set; } + float DopplerScale { get; set; } + float MasterVolume { get; set; } + float SpeedOfSound { get; set; } - float DopplerScale - { - get; - set; - } - - float MasterVolume - { - get; - set; - } - - float SpeedOfSound - { - get; - set; - } - - IAudioListener CreateAudioListener(); + IAudioListener CreateAudioListener(); IAudioEmitter CreateAudioEmitter(); @@ -52,5 +34,7 @@ namespace ANX.Framework.NonXNA ReadOnlyCollection GetAllMicrophones(); int GetDefaultMicrophone(ReadOnlyCollection allMicrophones); + + ISong CreateSong(Song parentSong, Uri uri); } } diff --git a/ANX.Framework/Properties/AssemblyInfo.cs b/ANX.Framework/Properties/AssemblyInfo.cs index 87ae3161..b073041e 100644 --- a/ANX.Framework/Properties/AssemblyInfo.cs +++ b/ANX.Framework/Properties/AssemblyInfo.cs @@ -39,17 +39,17 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("ANX.RenderSystem.Windows.Metro")] [assembly: InternalsVisibleTo("ANX.RenderSystem.GL3")] [assembly: InternalsVisibleTo("ANX.RenderSystem.Windows.PsVita")] -[assembly: InternalsVisibleTo("ANX.Framework.Windows.Kinect")] -[assembly: InternalsVisibleTo("ANX.Framework.Windows.XInput")] -[assembly: InternalsVisibleTo("ANX.Framework.Windows.XAudio")] [assembly: InternalsVisibleTo("ANX.InputSystem.Recording")] [assembly: InternalsVisibleTo("ANX.InputDevices.PsVita")] [assembly: InternalsVisibleTo("ANX.InputDevices.Test")] +[assembly: InternalsVisibleTo("ANX.InputDevices.Windows.Kinect")] [assembly: InternalsVisibleTo("ANX.InputDevices.Windows.XInput")] [assembly: InternalsVisibleTo("ANX.InputDevices.Windows.ModernUI")] [assembly: InternalsVisibleTo("ANX.PlatformSystem.Windows")] [assembly: InternalsVisibleTo("ANX.PlatformSystem.Linux")] [assembly: InternalsVisibleTo("ANX.PlatformSystem.Metro")] [assembly: InternalsVisibleTo("ANX.PlatformSystem.PsVita")] +[assembly: InternalsVisibleTo("ANX.SoundSystem.Windows.XAudio")] +[assembly: InternalsVisibleTo("ANX.SoundSystem.Windows.OpenAL")] [assembly: InternalsVisibleTo("ANX.Tools.XNBInspector")] [assembly: InternalsVisibleTo("ANX.Framework.Content.Pipeline")] \ No newline at end of file diff --git a/RenderSystems/ANX.Framework.GL3/GraphicsDeviceWindowsGL3.cs b/RenderSystems/ANX.Framework.GL3/GraphicsDeviceWindowsGL3.cs index 50d46f71..334a850f 100644 --- a/RenderSystems/ANX.Framework.GL3/GraphicsDeviceWindowsGL3.cs +++ b/RenderSystems/ANX.Framework.GL3/GraphicsDeviceWindowsGL3.cs @@ -42,25 +42,17 @@ namespace ANX.RenderSystem.GL3 { get { - return (Current == null || Current.nativeContext == null) ? false : Current.nativeContext.IsCurrent; + return (Current != null && Current.nativeContext != null) && Current.nativeContext.IsCurrent; } } #endregion #region Public - #region VSync - public bool VSync - { - get - { - return nativeContext.VSync; - } - set - { - nativeContext.VSync = value; - } - } - #endregion + public bool VSync + { + get { return nativeContext.VSync; } + set { nativeContext.VSync = value; } + } #endregion #region Constructor diff --git a/Samples/WpfEditor/MainWindow.xaml.cs b/Samples/WpfEditor/MainWindow.xaml.cs index bf4aa73b..e7fd0bbe 100644 --- a/Samples/WpfEditor/MainWindow.xaml.cs +++ b/Samples/WpfEditor/MainWindow.xaml.cs @@ -1,10 +1,10 @@ +using System; +using System.Threading; using System.Windows; +using System.Windows.Threading; using ANX.Framework; using ANX.Framework.Graphics; -using System.Windows.Interop; -using System; -using System.Windows.Threading; -using System.Threading; +using ANX.Framework.NonXNA; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. @@ -12,13 +12,18 @@ using System.Threading; namespace WpfEditor { - public partial class MainWindow : Window + public partial class MainWindow { private GraphicsDevice device; + private readonly ThreadStart emptyThreadStart; public MainWindow() { InitializeComponent(); + emptyThreadStart = delegate { }; + + //AddInSystemFactory.Instance.SetPreferredSystem(AddInType.RenderSystem, "OpenGL3"); + AddInSystemFactory.Instance.SetPreferredSystem(AddInType.RenderSystem, "DirectX10"); } protected override void OnActivated(EventArgs e) @@ -30,10 +35,7 @@ namespace WpfEditor while (IsVisible) { if (Application.Current != null) - { - Application.Current.Dispatcher.Invoke( - DispatcherPriority.Background, new ThreadStart(delegate { })); - } + Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, emptyThreadStart); Tick(); } @@ -41,13 +43,11 @@ namespace WpfEditor public void Initialize() { - device = new GraphicsDevice( - GraphicsAdapter.DefaultAdapter, - GraphicsProfile.HiDef, + device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.HiDef, new PresentationParameters { - BackBufferWidth = (int)GamePanel.Width, - BackBufferHeight = (int)GamePanel.Height, + BackBufferWidth = GamePanel.Width, + BackBufferHeight = GamePanel.Height, BackBufferFormat = SurfaceFormat.Color, DeviceWindowHandle = GamePanel.Handle, PresentationInterval = PresentInterval.Default, diff --git a/Samples/WpfEditor/WpfEditor.csproj b/Samples/WpfEditor/WpfEditor.csproj index 646b1420..2e00831c 100644 --- a/Samples/WpfEditor/WpfEditor.csproj +++ b/Samples/WpfEditor/WpfEditor.csproj @@ -107,6 +107,10 @@ {49066074-3B7B-4A55-B122-6BD33AB73558} ANX.InputSystem.Standard + + {EB8258E0-6741-4DB9-B756-1EBDF67B1ED6} + ANX.RenderSystem.GL3 + {5BE49183-2F6F-4527-AC90-D816911FCF90} ANX.RenderSystem.Windows.DX10 diff --git a/SoundSystems/ANX.SoundSystem.OpenAL/Creator.cs b/SoundSystems/ANX.SoundSystem.OpenAL/Creator.cs index d5c6410a..23acfef4 100644 --- a/SoundSystems/ANX.SoundSystem.OpenAL/Creator.cs +++ b/SoundSystems/ANX.SoundSystem.OpenAL/Creator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.ObjectModel; using System.IO; using ANX.Framework.Audio; +using ANX.Framework.Media; using ANX.Framework.NonXNA; using ANX.Framework.NonXNA.SoundSystem; using OpenTK; @@ -15,24 +16,21 @@ namespace ANX.SoundSystem.OpenAL { public class Creator : ISoundSystemCreator { + private float currentDistanceScale; + private float currentMasterVolume; + #region Public - public string Name - { - get - { - return "OpenAL"; - } - } + public string Name + { + get { return "OpenAL"; } + } - public int Priority - { - get - { - return 100; - } - } + public int Priority + { + get { return 100; } + } - public bool IsSupported + public bool IsSupported { get { @@ -43,80 +41,60 @@ namespace ANX.SoundSystem.OpenAL } } - public float DistanceScale - { - get - { - return 1f; - //throw new NotImplementedException(); - } - set - { - //throw new NotImplementedException(); - } - } + public float DistanceScale + { + get { return currentDistanceScale; } + set + { + currentDistanceScale = value; + // TODO: set actual property + } + } - public float DopplerScale - { - get - { - return AL.Get(ALGetFloat.DopplerFactor); - } - set - { - AL.DopplerFactor(value); - } - } + public float DopplerScale + { + get { return AL.Get(ALGetFloat.DopplerFactor); } + set { AL.DopplerFactor(value); } + } - public float MasterVolume - { - get - { - return 1f; - //throw new NotImplementedException(); - } - set - { - //throw new NotImplementedException(); - } - } + public float MasterVolume + { + get { return currentMasterVolume; } + set + { + currentMasterVolume = value; + // TODO: set actual property + } + } - public float SpeedOfSound - { - get - { - return AL.Get(ALGetFloat.SpeedOfSound); - } - set - { - AL.SpeedOfSound(value); - } - } - #endregion + public float SpeedOfSound + { + get { return AL.Get(ALGetFloat.SpeedOfSound); } + set { AL.SpeedOfSound(value); } + } + #endregion public Creator() { + currentDistanceScale = 1f; + currentMasterVolume = 1f; Init(); } - private void Init() - { - IntPtr deviceHandle; - ContextHandle context = Alc.GetCurrentContext(); - if (context.Handle != IntPtr.Zero) - { - deviceHandle = Alc.GetContextsDevice(context); - } - else - { - deviceHandle = Alc.OpenDevice(Alc.GetString(IntPtr.Zero, AlcGetString.DefaultDeviceSpecifier)); - context = Alc.CreateContext(deviceHandle, new int[0]); - } + private static void Init() + { + ContextHandle context = Alc.GetCurrentContext(); + if (context.Handle == IntPtr.Zero) + { + string deviceName = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultDeviceSpecifier); + IntPtr deviceHandle = Alc.OpenDevice(deviceName); + context = Alc.CreateContext(deviceHandle, new int[0]); + } - bool isNowCurrent = Alc.MakeContextCurrent(context); - } + Alc.MakeContextCurrent(context); + } - #region CreateSoundEffectInstance + #region CreateSoundEffectInstance public ISoundEffectInstance CreateSoundEffectInstance(ISoundEffect nativeSoundEffect) { PreventSystemChange(); @@ -179,9 +157,15 @@ namespace ANX.SoundSystem.OpenAL PreventSystemChange(); throw new NotImplementedException(); } - #endregion + #endregion - private void PreventSystemChange() + public ISong CreateSong(Song parentSong, Uri uri) + { + PreventSystemChange(); + throw new NotImplementedException(); + } + + private static void PreventSystemChange() { AddInSystemFactory.Instance.PreventSystemChange(AddInType.SoundSystem); } diff --git a/SoundSystems/ANX.SoundSystem.OpenAL/OpenALSoundEffectInstance.cs b/SoundSystems/ANX.SoundSystem.OpenAL/OpenALSoundEffectInstance.cs index 980f49a2..1a9da989 100644 --- a/SoundSystems/ANX.SoundSystem.OpenAL/OpenALSoundEffectInstance.cs +++ b/SoundSystems/ANX.SoundSystem.OpenAL/OpenALSoundEffectInstance.cs @@ -12,87 +12,69 @@ namespace ANX.SoundSystem.OpenAL public class OpenALSoundEffectInstance : ISoundEffectInstance { #region Private - private OpenALSoundEffect parent; - + private readonly OpenALSoundEffect parent; + private float currentPan; private int handle; #endregion #region Public - public bool IsLooped - { - get - { - bool result; - AL.GetSource(handle, ALSourceb.Looping, out result); - return result; - } - set - { - AL.Source(handle, ALSourceb.Looping, value); - } - } + public bool IsLooped + { + get + { + bool result; + AL.GetSource(handle, ALSourceb.Looping, out result); + return result; + } + set { AL.Source(handle, ALSourceb.Looping, value); } + } - public float Pan - { - get - { - return 0f; - //throw new NotImplementedException(); - } - set - { - //throw new NotImplementedException(); - } - } + public float Pan + { + get { return currentPan; } + set + { + currentPan = value; + // TODO: set actual parameter + } + } - public float Pitch - { - get - { - float result; - AL.GetSource(handle, ALSourcef.Pitch, out result); - return result; - } - set - { - AL.Source(handle, ALSourcef.Pitch, value); - } - } + public float Pitch + { + get + { + float result; + AL.GetSource(handle, ALSourcef.Pitch, out result); + return result; + } + set { AL.Source(handle, ALSourcef.Pitch, value); } + } - public SoundState State - { - get; - private set; - } + public SoundState State { get; private set; } - public float Volume - { - get - { - float result; - AL.GetSource(handle, ALSourcef.Gain, out result); - return result; - } - set - { - AL.Source(handle, ALSourcef.Gain, value); - } - } - #endregion + public float Volume + { + get + { + float result; + AL.GetSource(handle, ALSourcef.Gain, out result); + return result; + } + set { AL.Source(handle, ALSourcef.Gain, value); } + } + #endregion #region Constructor internal OpenALSoundEffectInstance(OpenALSoundEffect setParent) { parent = setParent; - State = SoundState.Stopped; - handle = AL.GenSource(); AL.Source(handle, ALSourcei.Buffer, parent.bufferHandle); IsLooped = false; Pitch = 1f; Volume = 1f; - // TODO: Pan = 0f; + Pan = 0f; ALError error = AL.GetError(); if (error != ALError.NoError) @@ -103,47 +85,44 @@ namespace ANX.SoundSystem.OpenAL #region Play public void Play() { - if (State != SoundState.Playing) - { - State = SoundState.Playing; - AL.SourcePlay(handle); - } + if (State == SoundState.Playing) + return; + + State = SoundState.Playing; + AL.SourcePlay(handle); } #endregion #region Pause public void Pause() { - if (State != SoundState.Paused) - { - State = SoundState.Paused; - AL.SourcePause(handle); - } + if (State == SoundState.Paused) + return; + + State = SoundState.Paused; + AL.SourcePause(handle); } #endregion #region Stop public void Stop(bool immediate) { - if (State == SoundState.Stopped) + if (State == SoundState.Stopped || immediate == false) return; - if (immediate) - { - State = SoundState.Stopped; - AL.SourceStop(handle); - } + State = SoundState.Stopped; + AL.SourceStop(handle); } #endregion #region Resume public void Resume() { - if (State != SoundState.Playing) - { - State = SoundState.Playing; - AL.SourcePlay(handle); - } + if (State == SoundState.Playing) + return; + + State = SoundState.Playing; + AL.SourcePlay(handle); } #endregion diff --git a/SoundSystems/ANX.SoundSystem.PsVita/Creator.cs b/SoundSystems/ANX.SoundSystem.PsVita/Creator.cs index b0314083..a50ee60a 100644 --- a/SoundSystems/ANX.SoundSystem.PsVita/Creator.cs +++ b/SoundSystems/ANX.SoundSystem.PsVita/Creator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.ObjectModel; using System.IO; using ANX.Framework.Audio; +using ANX.Framework.Media; using ANX.Framework.NonXNA; using ANX.Framework.NonXNA.SoundSystem; @@ -163,6 +164,12 @@ namespace ANX.SoundSystem.PsVita { throw new NotImplementedException(); } - #endregion + #endregion + + public ISong CreateSong(Song parentSong, Uri uri) + { + AddInSystemFactory.Instance.PreventSystemChange(AddInType.SoundSystem); + throw new NotImplementedException(); + } } } diff --git a/SoundSystems/ANX.SoundSystem.Windows.XAudio/Creator.cs b/SoundSystems/ANX.SoundSystem.Windows.XAudio/Creator.cs index 9622562a..dd4a9da6 100644 --- a/SoundSystems/ANX.SoundSystem.Windows.XAudio/Creator.cs +++ b/SoundSystems/ANX.SoundSystem.Windows.XAudio/Creator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.ObjectModel; using System.IO; using ANX.Framework.Audio; +using ANX.Framework.Media; using ANX.Framework.NonXNA; using ANX.Framework.NonXNA.SoundSystem; using SharpDX.XAudio2; @@ -86,7 +87,10 @@ namespace ANX.SoundSystem.Windows.XAudio ~Creator() { if (MasteringVoice != null) + { + MasteringVoice.DestroyVoice(); MasteringVoice.Dispose(); + } if (device != null) device.Dispose(); @@ -149,9 +153,15 @@ namespace ANX.SoundSystem.Windows.XAudio throw new NotImplementedException(); } + public ISong CreateSong(Song parentSong, Uri uri) + { + PreventSystemChange(); + throw new NotImplementedException(); + } + private static void PreventSystemChange() { AddInSystemFactory.Instance.PreventSystemChange(AddInType.SoundSystem); } - } + } } diff --git a/SoundSystems/ANX.SoundSystem.Windows.XAudio/XAudioSoundEffectInstance.cs b/SoundSystems/ANX.SoundSystem.Windows.XAudio/XAudioSoundEffectInstance.cs index ba2ccb0b..b227be95 100644 --- a/SoundSystems/ANX.SoundSystem.Windows.XAudio/XAudioSoundEffectInstance.cs +++ b/SoundSystems/ANX.SoundSystem.Windows.XAudio/XAudioSoundEffectInstance.cs @@ -74,11 +74,17 @@ namespace ANX.SoundSystem.Windows.XAudio currentPan = 0f; currentPitch = 1f; State = SoundState.Stopped; - source = new SourceVoice(device, setParent.WaveFormat); + 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() { @@ -94,6 +100,7 @@ namespace ANX.SoundSystem.Windows.XAudio public void Pause() { State = SoundState.Paused; + throw new NotImplementedException(); } #endregion @@ -115,6 +122,7 @@ namespace ANX.SoundSystem.Windows.XAudio public void Resume() { State = SoundState.Playing; + throw new NotImplementedException(); } #endregion @@ -182,7 +190,11 @@ namespace ANX.SoundSystem.Windows.XAudio public void Dispose() { if (source != null) + { + source.StreamEnd -= StreamEnd; + source.DestroyVoice(); source.Dispose(); + } source = null; } #endregion