Implemented Xact general settings parsing for the AudioEngine

This commit is contained in:
SND\AstrorEnales_cp 2012-08-26 20:17:41 +00:00
parent 15629e7f47
commit c955ca882a
15 changed files with 509 additions and 36 deletions

View File

@ -54,6 +54,10 @@
<Compile Include="Audio\SoundEffectInstance.cs" />
<Compile Include="Audio\SoundState.cs" />
<Compile Include="Audio\WaveBank.cs" />
<Compile Include="Audio\XactParser\XactGeneralSettings.cs" />
<Compile Include="Audio\XactParser\XactGeneralSettingsRpcCurve.cs" />
<Compile Include="Audio\XactParser\XactGeneralSettingsRpcCurvePoint.cs" />
<Compile Include="Audio\XactParser\XactGeneralSettingsVariable.cs" />
<Compile Include="BoundingBox.cs" />
<Compile Include="BoundingFrustum.cs" />
<Compile Include="BoundingSphere.cs" />

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
@ -8,45 +9,143 @@ namespace ANX.Framework.Audio
{
public struct AudioCategory : IEquatable<AudioCategory>
{
#region Public
public string Name
#region Internal helper enums
internal enum InstanceBehaviour
{
get
{
throw new NotImplementedException();
}
// behaviour flags (reside in upper 5 bits of the byte)
FailToPlay = 0x00,
Queue = 0x01,
ReplaceLowestPriority = 0x04,
ReplaceOldest = 0x02,
ReplaceQuietest = 0x03,
}
internal enum InstanceCrossFading
{
// cross fade type flags (reside in lower 3 bits of byte)
XFadeLinear = 0x00,
XFadeLog = 0x01,
XFadeEqlPow = 0x02,
}
internal enum Visibility
{
BgMusic = 0x01,
Public = 0x02,
Private = 0x00,
}
#endregion
#region Pause
#region Public
/// <summary>
/// Maximum number of instances (if 0xFF, then there is no limit)
/// </summary>
internal byte MaxNumberOfInstances
{
get;
private set;
}
internal float FadeInSeconds
{
get;
private set;
}
internal float FadeOutSeconds
{
get;
private set;
}
internal InstanceBehaviour Behaviour
{
get;
private set;
}
internal InstanceCrossFading CrossFading
{
get;
private set;
}
internal byte Volume
{
get;
private set;
}
internal Visibility CategoryVisibility
{
get;
private set;
}
public string Name
{
get;
internal set;
}
#endregion
#region Constructor
internal AudioCategory(BinaryReader reader)
: this()
{
MaxNumberOfInstances = reader.ReadByte();
// fixed point (1000 = 1.000) of fade (in seconds)
FadeInSeconds = reader.ReadUInt16() / 1000f;
FadeOutSeconds = reader.ReadUInt16() / 1000f;
byte behaviourFlags = reader.ReadByte();
Behaviour = (InstanceBehaviour)(behaviourFlags >> 3);
CrossFading = (InstanceCrossFading)(behaviourFlags & 7);
// unknown, seems to be 0xFFFF for Default and 0x0000 for everyone else
reader.ReadUInt16();
Volume = reader.ReadByte();
CategoryVisibility = (Visibility)reader.ReadByte();
}
internal AudioCategory(string setName)
: this()
{
Name = setName;
}
#endregion
#region Pause (TODO)
public void Pause()
{
throw new NotImplementedException();
}
#endregion
#region Resume
#region Resume (TODO)
public void Resume()
{
throw new NotImplementedException();
}
#endregion
#region SetVolume
public void SetVolume(float volume)
{
throw new NotImplementedException();
}
#endregion
#region Stop
#region Stop (TODO)
public void Stop(AudioStopOptions options)
{
throw new NotImplementedException();
}
#endregion
#region GetHashCode
#region SetVolume (TODO)
public void SetVolume(float volume)
{
throw new NotImplementedException();
}
#endregion
#region GetHashCode (TODO)
public override int GetHashCode()
{
throw new NotImplementedException();
@ -78,7 +177,7 @@ namespace ANX.Framework.Audio
}
#endregion
#region Equality
#region Equality (TODO)
public static bool operator ==(AudioCategory lhs, AudioCategory rhs)
{
throw new NotImplementedException();

View File

@ -1,5 +1,9 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using ANX.Framework.Audio.XactParser;
using System.Collections.Generic;
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.
@ -13,10 +17,14 @@ namespace ANX.Framework.Audio
public const int ContentVersion = 0x27;
#endregion
#region Private
private XactGeneralSettings generalSettings;
#endregion
#region Events
public event EventHandler<EventArgs> Disposing;
#endregion
#region Public
public bool IsDisposed
{
@ -26,22 +34,32 @@ namespace ANX.Framework.Audio
public ReadOnlyCollection<RendererDetail> RendererDetails
{
get
{
throw new NotImplementedException();
}
get;
private set;
}
#endregion
#region Constructor
#region Constructor (TODO)
public AudioEngine(string settingsFile)
{
throw new NotImplementedException();
// TODO: get renderer details
RendererDetails = new ReadOnlyCollection<RendererDetail>(new List<RendererDetail>());
Stream loadingStream = AddInSystemFactory.DefaultPlatformCreator.OpenReadFilestream(settingsFile);
generalSettings = new XactGeneralSettings(loadingStream);
loadingStream.Dispose();
}
public AudioEngine(string settingsFile, TimeSpan lookAheadTime, string rendererId)
{
throw new NotImplementedException();
// TODO: get renderer details
RendererDetails = new ReadOnlyCollection<RendererDetail>(new List<RendererDetail>());
// TODO: lookAheadTime and rendererId
Stream loadingStream = AddInSystemFactory.DefaultPlatformCreator.OpenReadFilestream(settingsFile);
generalSettings = new XactGeneralSettings(loadingStream);
loadingStream.Dispose();
}
~AudioEngine()
@ -53,25 +71,35 @@ namespace ANX.Framework.Audio
#region GetCategory
public AudioCategory GetCategory(string name)
{
throw new NotImplementedException();
for (int index = 0; index < generalSettings.Categories.Length; index++)
if (generalSettings.Categories[index].Name == name)
return generalSettings.Categories[index];
return new AudioCategory(name);
}
#endregion
#region GetGlobalVariable
public float GetGlobalVariable(string name)
{
throw new NotImplementedException();
foreach (var variable in generalSettings.Variables)
if (variable.Name == name)
return variable.StartingValue;
return 0f;
}
#endregion
#region SetGlobalVariable
public void SetGlobalVariable(string name, float value)
{
throw new NotImplementedException();
foreach (var variable in generalSettings.Variables)
if (variable.Name == name)
variable.StartingValue = MathHelper.Clamp(value, variable.MinValue, variable.MaxValue);
}
#endregion
#region Update
#region Update (TODO)
public void Update()
{
throw new NotImplementedException();
@ -83,8 +111,11 @@ namespace ANX.Framework.Audio
{
if (IsDisposed == false)
{
if (Disposing != null)
Disposing(this, EventArgs.Empty);
IsDisposed = true;
throw new NotImplementedException();
generalSettings = null;
}
}

View File

@ -0,0 +1,140 @@
using System;
using System.IO;
// 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.Audio.XactParser
{
/// <summary>
/// http://code.google.com/p/monoxna/source/browse/wiki/XnaFrameworkAudio.wiki?r=347
/// </summary>
internal class XactGeneralSettings
{
public class InvalidMagicException : Exception { }
public class InvalidVersionException : Exception { }
#region Public
public AudioCategory[] Categories
{
get;
private set;
}
public XactGeneralSettingsVariable[] Variables
{
get;
private set;
}
public XactGeneralSettingsRpcCurve[] Curves
{
get;
private set;
}
#endregion
#region Constructor
public XactGeneralSettings(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
ValidateMagic(reader);
ValidateVersion(reader);
// unknown, but seems to be 0x002A across all files
reader.ReadUInt16();
// unknown, maybe something to do with the last modified values
reader.ReadUInt16();
DateTime lastModifiedDate = DateTime.FromFileTime(reader.ReadInt64());
// unknown, seems to stay 0x03
reader.ReadByte();
Categories = new AudioCategory[reader.ReadUInt16()];
Variables = new XactGeneralSettingsVariable[reader.ReadUInt16()];
// unknown, seems to always be 0x16
reader.ReadUInt16();
// unknown, seems to always be 0x16
reader.ReadUInt16();
Curves = new XactGeneralSettingsRpcCurve[reader.ReadUInt16()];
ushort dspEffectPresetsCount = reader.ReadUInt16();
ushort dspEffectParametersCount = reader.ReadUInt16();
int firstCategorySettingsPosition = reader.ReadInt32();
int firstVariableSettingsPosition = reader.ReadInt32();
// unknown
stream.Seek(16, SeekOrigin.Current);
int positionOfFirstCategoryName = reader.ReadInt32();
int positionOfFirstVariableName = reader.ReadInt32();
int positionOfFirstRpcCurve = reader.ReadInt32();
int positionOfFirstDspEffectPreset = reader.ReadInt32();
int positionOfFirstDspEffectParameters = reader.ReadInt32();
stream.Seek(firstCategorySettingsPosition, SeekOrigin.Begin);
for (int categoryIndex = 0; categoryIndex < Categories.Length; categoryIndex++)
Categories[categoryIndex] = new AudioCategory(reader);
stream.Seek(firstVariableSettingsPosition, SeekOrigin.Begin);
for (int variableIndex = 0; variableIndex < Variables.Length; variableIndex++)
Variables[variableIndex] = new XactGeneralSettingsVariable(reader);
if (positionOfFirstRpcCurve > -1)
{
stream.Seek(positionOfFirstRpcCurve, SeekOrigin.Begin);
for (int curveIndex = 0; curveIndex < Curves.Length; curveIndex++)
Curves[curveIndex] = new XactGeneralSettingsRpcCurve(reader);
}
stream.Seek(positionOfFirstCategoryName, SeekOrigin.Begin);
string[] names = ParseNames(Categories.Length, reader);
for (int categoryIndex = 0; categoryIndex < Categories.Length; categoryIndex++)
Categories[categoryIndex].Name = names[categoryIndex];
stream.Seek(positionOfFirstVariableName, SeekOrigin.Begin);
names = ParseNames(Variables.Length, reader);
for (int variableIndex = 0; variableIndex < Variables.Length; variableIndex++)
Variables[variableIndex].Name = names[variableIndex];
}
#endregion
#region ValidateMagic
private static void ValidateMagic(BinaryReader reader)
{
char[] magicChars = reader.ReadChars(4);
if (magicChars[0] != 'X' || magicChars[1] != 'G' || magicChars[2] != 'S' || magicChars[3] != 'F')
throw new InvalidMagicException();
}
#endregion
#region ValidateVersion
private static void ValidateVersion(BinaryReader reader)
{
ushort version = reader.ReadUInt16();
if (version != 47 && version != 46 && version != 45)
throw new InvalidVersionException();
}
#endregion
#region ParseNames
private static string[] ParseNames(int count, BinaryReader reader)
{
string[] result = new string[count];
for (int index = 0; index < count; index++)
{
result[index] = "";
char readChar = '\0';
while ((readChar = (char)reader.ReadByte()) != '\0')
result[index] += readChar;
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.IO;
// 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.Audio.XactParser
{
internal class XactGeneralSettingsRpcCurve
{
// what variable this curve involves
public ushort VariableIndex
{
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 XactGeneralSettingsRpcCurve(BinaryReader reader)
{
VariableIndex = reader.ReadUInt16();
byte numberOfCurvePoints = reader.ReadByte();
Parameters = reader.ReadInt16();
Points = new XactGeneralSettingsRpcCurvePoint[numberOfCurvePoints];
for (int pointIndex = 0; pointIndex < numberOfCurvePoints; pointIndex++)
Points[pointIndex] = new XactGeneralSettingsRpcCurvePoint(reader);
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.IO;
// 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.Audio.XactParser
{
internal class XactGeneralSettingsRpcCurvePoint
{
public enum CurveType
{
Linear = 0x00,
Fast = 0x01,
Slow = 0x02,
SinCos = 0x03,
}
public float X
{
get;
private set;
}
public float Y
{
get;
private set;
}
public CurveType Type
{
get;
private set;
}
public XactGeneralSettingsRpcCurvePoint(BinaryReader reader)
{
X = reader.ReadSingle();
Y = reader.ReadSingle();
Type = (XactGeneralSettingsRpcCurvePoint.CurveType)reader.ReadByte();
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.IO;
// 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.Audio.XactParser
{
internal class XactGeneralSettingsVariable
{
public enum VariableFlags
{
Public = 0x01,
ReadOnly = 0x02,
CueInstance = 0x04,
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 XactGeneralSettingsVariable(BinaryReader reader)
{
Flags = (XactGeneralSettingsVariable.VariableFlags)reader.ReadByte();
StartingValue = reader.ReadSingle();
MinValue = reader.ReadSingle();
MaxValue = reader.ReadSingle();
}
}
}

View File

@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using ANX.Framework.Media;
using ANX.Framework.Storage;
@ -12,13 +12,14 @@ namespace ANX.Framework.NonXNA.PlatformSystem
public interface IPlatformSystemCreator : ICreator
{
GameHost CreateGameHost(Game game);
INativeStorageDevice CreateStorageDevice(StorageDevice device,
PlayerIndex player, int sizeInBytes, int directoryCount);
INativeStorageDevice CreateStorageDevice(StorageDevice device, PlayerIndex player, int sizeInBytes, int directoryCount);
INativeStorageContainer CreateStorageContainer(StorageContainer container);
INativeTitleContainer CreateTitleContainer();
INativeGameTimer CreateGameTimer();
INativeContentManager CreateContentManager();
Stream OpenReadFilestream(string filepath);
INativeMediaLibrary CreateMediaPlayer();
IList<MediaSource> GetAvailableMediaSources();
}

View File

@ -14,8 +14,7 @@ namespace ANX.Framework
static TitleContainer()
{
nativeImplementation =
AddInSystemFactory.DefaultPlatformCreator.CreateTitleContainer();
nativeImplementation = AddInSystemFactory.DefaultPlatformCreator.CreateTitleContainer();
}
public static Stream OpenStream(string name)

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using ANX.Framework;
using ANX.Framework.Media;
using ANX.Framework.NonXNA;
@ -102,5 +103,12 @@ namespace ANX.PlatformSystem.Linux
throw new NotImplementedException();
}
#endregion
#region OpenReadFilestream
public Stream OpenReadFilestream(string filepath)
{
return File.OpenRead(filepath);
}
#endregion
}
}

View File

@ -3,6 +3,9 @@ using ANX.Framework;
using ANX.Framework.NonXNA;
using ANX.Framework.NonXNA.PlatformSystem;
using ANX.Framework.Storage;
using System.IO;
using ANX.Framework.Media;
using System.Collections.Generic;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
@ -97,5 +100,22 @@ namespace ANX.PlatformSystem.Metro
return new MetroContentManager();
}
#endregion
#region IPlatformSystemCreator Member
public Stream OpenReadFilestream(string filepath)
{
throw new NotImplementedException();
}
public INativeMediaLibrary CreateMediaPlayer()
{
throw new NotImplementedException();
}
public IList<MediaSource> GetAvailableMediaSources()
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using ANX.Framework;
using ANX.Framework.Media;
using ANX.Framework.NonXNA;
@ -105,5 +106,12 @@ namespace ANX.PlatformSystem.PsVita
throw new NotImplementedException();
}
#endregion
#region OpenReadFilestream
public Stream OpenReadFilestream(string filepath)
{
return File.OpenRead(filepath);
}
#endregion
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using ANX.Framework;
using ANX.Framework.Media;
using ANX.Framework.NonXNA;
@ -102,5 +103,12 @@ namespace ANX.PlatformSystem.Windows
throw new NotImplementedException();
}
#endregion
#region OpenReadFilestream
public Stream OpenReadFilestream(string filepath)
{
return File.OpenRead(filepath);
}
#endregion
}
}

View File

@ -70,6 +70,12 @@
<Compile Include="OpenALSoundEffectInstance.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SupportedPlatformsImpl.cs" />
<Compile Include="Wave\ALaw.cs" />
<Compile Include="Wave\MsAdpcm.cs" />
<Compile Include="Wave\MuLaw.cs" />
<Compile Include="Wave\WaveFile.cs" />
<Compile Include="Wave\WaveFormat.cs" />
<Compile Include="Wave\WaveInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ANX.Framework\ANX.Framework_Linux.csproj">

View File

@ -71,6 +71,12 @@
<Compile Include="OpenALSoundEffectInstance.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SupportedPlatformsImpl.cs" />
<Compile Include="Wave\ALaw.cs" />
<Compile Include="Wave\MsAdpcm.cs" />
<Compile Include="Wave\MuLaw.cs" />
<Compile Include="Wave\WaveFile.cs" />
<Compile Include="Wave\WaveFormat.cs" />
<Compile Include="Wave\WaveInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ANX.Framework\ANX.Framework_PSVita.csproj">