public AudioEngine(string settingsFile) { if (String.IsNullOrEmpty(settingsFile)) { throw new ArgumentNullException("settingsFile"); } using (Stream stream = TitleContainer.OpenStream(settingsFile)) using (BinaryReader reader = new BinaryReader(stream)) { // Check the file header. Should be 'XGSF' if (reader.ReadUInt32() != 0x46534758) { throw new ArgumentException("XGSF format not recognized!"); } // Check the Content and Tool versions if (reader.ReadUInt16() != ContentVersion) { throw new ArgumentException("XGSF Content version!"); } if (reader.ReadUInt16() != 42) { throw new ArgumentException("XGSF Tool version!"); } // Unknown value reader.ReadUInt16(); // Last Modified, Unused reader.ReadUInt64(); // XACT Version, Unused reader.ReadByte(); // Number of AudioCategories ushort numCategories = reader.ReadUInt16(); // Number of XACT Variables ushort numVariables = reader.ReadUInt16(); // KEY#1 Length /*ushort numKeyOne =*/ reader.ReadUInt16(); // KEY#2 Length /*ushort numKeyTwo =*/ reader.ReadUInt16(); // Number of RPC Variables ushort numRPCs = reader.ReadUInt16(); // Number of DSP Presets/Parameters ushort numDSPPresets = reader.ReadUInt16(); ushort numDSPParameters = reader.ReadUInt16(); // Category Offset in XGS File uint categoryOffset = reader.ReadUInt32(); // Variable Offset in XGS File uint variableOffset = reader.ReadUInt32(); // KEY#1 Offset /*uint keyOneOffset =*/ reader.ReadUInt32(); // Category Name Index Offset, unused reader.ReadUInt32(); // KEY#2 Offset /*uint keyTwoOffset =*/ reader.ReadUInt32(); // Variable Name Index Offset, unused reader.ReadUInt32(); // Category Name Offset in XGS File uint categoryNameOffset = reader.ReadUInt32(); // Variable Name Offset in XGS File uint variableNameOffset = reader.ReadUInt32(); // RPC Variable Offset in XGS File uint rpcOffset = reader.ReadUInt32(); // DSP Preset/Parameter Offsets in XGS File uint dspPresetOffset = reader.ReadUInt32(); uint dspParameterOffset = reader.ReadUInt32(); /* Unknown table #1 * reader.BaseStream.Seek(keyOneOffset, SeekOrigin.Begin); * for (int i = 0; i < numKeyOne; i += 1) * { * // Appears to consistently be 16 shorts? * System.Console.WriteLine(reader.ReadInt16()); * } * /* OhGodNo * 1, -1, 4, -1, * 3, -1, -1, 7, * -1, 2, 5, -1, * 6, 0, -1, -1 * * Naddachance * 1, -1, 4, -1, * 5, -1, -1, -1, * -1, 2, -1, -1, * 3, 0, -1, -1 * * TFA * 1, -1, -1, -1, * -1, -1, -1, -1, * -1, 2, -1, -1, * -1, -0, -1, -1 */ /* Unknown table #2 * reader.BaseStream.Seek(keyTwoOffset, SeekOrigin.Begin); * for (int i = 0; i < numKeyTwo; i += 1) * { * // Appears to be between 16-20 shorts? * System.Console.WriteLine(reader.ReadInt16()); * } * /* OhGodNo * 2, 7, 1, -1, * -1, 10, 19, -1, * 11, 3, -1, -1, * 8, -1, 14, 5, * 12, 0, 4, 6 * * Naddachance * 2, 3, -1, -1, * 9, -1, 7, -1, * 10, 0, 1, 5, * -1, -1, -1, -1 * * TFA * 2, 3, -1, -1, * -1, -1, -1, -1, * -1, 0, 1, 5, * -1, -1, -1, -1 */ // Obtain the Audio Category Names reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin); string[] categoryNames = new string[numCategories]; for (int i = 0; i < numCategories; i += 1) { List <char> builtString = new List <char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator categoryNames[i] = new string(builtString.ToArray()); } // Obtain the Audio Categories reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin); INTERNAL_categories = new List <AudioCategory>(); for (int i = 0; i < numCategories; i += 1) { // Maximum instances byte maxInstances = reader.ReadByte(); // Fade In/Out ushort fadeInMS = reader.ReadUInt16(); ushort fadeOutMS = reader.ReadUInt16(); // Instance Behavior Flags byte instanceFlags = reader.ReadByte(); int fadeType = instanceFlags & 0x07; int maxBehavior = instanceFlags >> 3; // Parent Category short parent = reader.ReadInt16(); // Volume float volume = XACTCalculator.CalculateAmplitudeRatio( XACTCalculator.ParseDecibel( reader.ReadByte() ) ); // Visibility Flags, unused reader.ReadByte(); // Add to the engine list and the parent category INTERNAL_categories.Add( new AudioCategory( categoryNames[i], volume, maxInstances, maxBehavior, fadeInMS, fadeOutMS, fadeType ) ); if (parent != -1) { INTERNAL_categories[parent].subCategories.Add( INTERNAL_categories[i] ); } } // Obtain the Variable Names reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin); string[] variableNames = new string[numVariables]; for (int i = 0; i < numVariables; i += 1) { List <char> builtString = new List <char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator variableNames[i] = new string(builtString.ToArray()); } // Obtain the Variables reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin); INTERNAL_variables = new List <Variable>(); for (int i = 0; i < numVariables; i += 1) { // Variable Accessibility (See Variable constructor) byte varFlags = reader.ReadByte(); // Variable Value, Boundaries float initialValue = reader.ReadSingle(); float minValue = reader.ReadSingle(); float maxValue = reader.ReadSingle(); // Add to the engine list INTERNAL_variables.Add( new Variable( variableNames[i], (varFlags & 0x01) != 0, (varFlags & 0x02) != 0, (varFlags & 0x04) == 0, (varFlags & 0x08) != 0, initialValue, minValue, maxValue ) ); } // Obtain the RPC Curves reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin); INTERNAL_RPCs = new Dictionary <long, RPC>(); for (int i = 0; i < numRPCs; i += 1) { // RPC "Code", used by the SoundBanks long rpcCode = reader.BaseStream.Position; // RPC Variable ushort rpcVariable = reader.ReadUInt16(); // Number of RPC Curve Points byte numPoints = reader.ReadByte(); // RPC Parameter ushort rpcParameter = reader.ReadUInt16(); // RPC Curve Points RPCPoint[] rpcPoints = new RPCPoint[numPoints]; for (byte j = 0; j < numPoints; j += 1) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); byte type = reader.ReadByte(); rpcPoints[j] = new RPCPoint( x, y, (RPCPointType)type ); } // Add to the engine list INTERNAL_RPCs.Add( rpcCode, new RPC( INTERNAL_variables[rpcVariable].Name, rpcParameter, rpcPoints ) ); } // Obtain the DSP Parameters reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin); INTERNAL_dspParameters = new List <DSPParameter>(); for (int i = 0; i < numDSPParameters; i += 1) { // Effect Parameter Type byte type = reader.ReadByte(); // Effect value, boundaries float value = reader.ReadSingle(); float minVal = reader.ReadSingle(); float maxVal = reader.ReadSingle(); // Unknown value reader.ReadUInt16(); // Add to Parameter list INTERNAL_dspParameters.Add( new DSPParameter( type, value, minVal, maxVal ) ); } // Obtain the DSP Presets reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin); INTERNAL_dspPresets = new Dictionary <long, DSPPreset>(); int total = 0; for (int i = 0; i < numDSPPresets; i += 1) { // DSP "Code", used by the SoundBanks long dspCode = reader.BaseStream.Position; // Preset Accessibility bool global = (reader.ReadByte() == 1); // Number of preset parameters uint numParams = reader.ReadUInt32(); // Obtain DSP Parameters DSPParameter[] parameters = new DSPParameter[numParams]; for (uint j = 0; j < numParams; j += 1) { parameters[j] = INTERNAL_dspParameters[total]; total += 1; } // Add to DSP Preset list INTERNAL_dspPresets.Add( dspCode, new DSPPreset( global, parameters ) ); } } // Create the WaveBank Dictionary INTERNAL_waveBanks = new Dictionary <string, WaveBank>(); // Finally. IsDisposed = false; }
public AudioEngine(string settingsFile) { if (String.IsNullOrEmpty(settingsFile)) { throw new ArgumentNullException("settingsFile"); } using (Stream stream = TitleContainer.OpenStream(settingsFile)) using (BinaryReader reader = new BinaryReader(stream)) { // Check the file header. Should be 'XGSF' if (reader.ReadUInt32() != 0x46534758) { throw new ArgumentException("XGSF format not recognized!"); } // Check the Content and Tool versions if (reader.ReadUInt16() != ContentVersion) { throw new ArgumentException("XGSF Content version!"); } if (reader.ReadUInt16() != 42) { throw new ArgumentException("XGSF Tool version!"); } // Unknown value reader.ReadUInt16(); // Last Modified, Unused reader.ReadUInt64(); // XACT Version, Unused reader.ReadByte(); // Number of AudioCategories ushort numCategories = reader.ReadUInt16(); // Number of XACT Variables ushort numVariables = reader.ReadUInt16(); // KEY#1 Length /*ushort numKeyOne =*/ reader.ReadUInt16(); // KEY#2 Length /*ushort numKeyTwo =*/ reader.ReadUInt16(); // Number of RPC Variables ushort numRPCs = reader.ReadUInt16(); // Number of DSP Presets/Parameters ushort numDSPPresets = reader.ReadUInt16(); ushort numDSPParameters = reader.ReadUInt16(); // Category Offset in XGS File uint categoryOffset = reader.ReadUInt32(); // Variable Offset in XGS File uint variableOffset = reader.ReadUInt32(); // KEY#1 Offset /*uint keyOneOffset =*/ reader.ReadUInt32(); // Category Name Index Offset, unused reader.ReadUInt32(); // KEY#2 Offset /*uint keyTwoOffset =*/ reader.ReadUInt32(); // Variable Name Index Offset, unused reader.ReadUInt32(); // Category Name Offset in XGS File uint categoryNameOffset = reader.ReadUInt32(); // Variable Name Offset in XGS File uint variableNameOffset = reader.ReadUInt32(); // RPC Variable Offset in XGS File uint rpcOffset = reader.ReadUInt32(); // DSP Preset/Parameter Offsets in XGS File uint dspPresetOffset = reader.ReadUInt32(); uint dspParameterOffset = reader.ReadUInt32(); /* Unknown table #1 reader.BaseStream.Seek(keyOneOffset, SeekOrigin.Begin); for (int i = 0; i < numKeyOne; i += 1) { // Appears to consistently be 16 shorts? System.Console.WriteLine(reader.ReadInt16()); } /* OhGodNo * 1, -1, 4, -1, * 3, -1, -1, 7, * -1, 2, 5, -1, * 6, 0, -1, -1 * * Naddachance * 1, -1, 4, -1, * 5, -1, -1, -1, * -1, 2, -1, -1, * 3, 0, -1, -1 * * TFA * 1, -1, -1, -1, * -1, -1, -1, -1, * -1, 2, -1, -1, * -1, -0, -1, -1 */ /* Unknown table #2 reader.BaseStream.Seek(keyTwoOffset, SeekOrigin.Begin); for (int i = 0; i < numKeyTwo; i += 1) { // Appears to be between 16-20 shorts? System.Console.WriteLine(reader.ReadInt16()); } /* OhGodNo * 2, 7, 1, -1, * -1, 10, 19, -1, * 11, 3, -1, -1, * 8, -1, 14, 5, * 12, 0, 4, 6 * * Naddachance * 2, 3, -1, -1, * 9, -1, 7, -1, * 10, 0, 1, 5, * -1, -1, -1, -1 * * TFA * 2, 3, -1, -1, * -1, -1, -1, -1, * -1, 0, 1, 5, * -1, -1, -1, -1 */ // Obtain the Audio Category Names reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin); string[] categoryNames = new string[numCategories]; for (int i = 0; i < numCategories; i += 1) { List<char> builtString = new List<char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator categoryNames[i] = new string(builtString.ToArray()); } // Obtain the Audio Categories reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin); INTERNAL_categories = new List<AudioCategory>(); for (int i = 0; i < numCategories; i += 1) { // Maximum instances byte maxInstances = reader.ReadByte(); // Fade In/Out ushort fadeInMS = reader.ReadUInt16(); ushort fadeOutMS = reader.ReadUInt16(); // Instance Behavior Flags byte instanceFlags = reader.ReadByte(); int fadeType = instanceFlags & 0x07; int maxBehavior = instanceFlags >> 3; // Unknown value reader.ReadUInt16(); // Volume float volume = XACTCalculator.CalculateVolume(reader.ReadByte()); // Visibility Flags, unused reader.ReadByte(); // Add to the engine list INTERNAL_categories.Add( new AudioCategory( categoryNames[i], volume, maxInstances, maxBehavior, fadeInMS, fadeOutMS, fadeType ) ); } // Obtain the Variable Names reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin); string[] variableNames = new string[numVariables]; for (int i = 0; i < numVariables; i += 1) { List<char> builtString = new List<char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator variableNames[i] = new string(builtString.ToArray()); } // Obtain the Variables reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin); INTERNAL_variables = new List<Variable>(); for (int i = 0; i < numVariables; i += 1) { // Variable Accessibility (See Variable constructor) byte varFlags = reader.ReadByte(); // Variable Value, Boundaries float initialValue = reader.ReadSingle(); float minValue = reader.ReadSingle(); float maxValue = reader.ReadSingle(); // Add to the engine list INTERNAL_variables.Add( new Variable( variableNames[i], (varFlags & 0x01) != 0, (varFlags & 0x02) != 0, (varFlags & 0x04) == 0, (varFlags & 0x08) != 0, initialValue, minValue, maxValue ) ); } // Obtain the RPC Curves reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin); INTERNAL_RPCs = new Dictionary<long, RPC>(); for (int i = 0; i < numRPCs; i += 1) { // RPC "Code", used by the SoundBanks long rpcCode = reader.BaseStream.Position; // RPC Variable ushort rpcVariable = reader.ReadUInt16(); // Number of RPC Curve Points byte numPoints = reader.ReadByte(); // RPC Parameter ushort rpcParameter = reader.ReadUInt16(); // RPC Curve Points RPCPoint[] rpcPoints = new RPCPoint[numPoints]; for (byte j = 0; j < numPoints; j += 1) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); byte type = reader.ReadByte(); rpcPoints[j] = new RPCPoint( x, y, (RPCPointType) type ); } // Add to the engine list INTERNAL_RPCs.Add( rpcCode, new RPC( INTERNAL_variables[rpcVariable].Name, rpcParameter, rpcPoints ) ); } // Obtain the DSP Parameters reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin); INTERNAL_dspParameters = new List<DSPParameter>(); for (int i = 0; i < numDSPParameters; i += 1) { // Effect Parameter Type byte type = reader.ReadByte(); // Effect value, boundaries float value = reader.ReadSingle(); float minVal = reader.ReadSingle(); float maxVal = reader.ReadSingle(); // Unknown value reader.ReadUInt16(); // Add to Parameter list INTERNAL_dspParameters.Add( new DSPParameter( type, value, minVal, maxVal ) ); } // Obtain the DSP Presets reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin); INTERNAL_dspPresets = new Dictionary<long, DSPPreset>(); int total = 0; for (int i = 0; i < numDSPPresets; i += 1) { // DSP "Code", used by the SoundBanks long dspCode = reader.BaseStream.Position; // Preset Accessibility bool global = (reader.ReadByte() == 1); // Number of preset parameters uint numParams = reader.ReadUInt32(); // Obtain DSP Parameters DSPParameter[] parameters = new DSPParameter[numParams]; for (uint j = 0; j < numParams; j += 1) { parameters[j] = INTERNAL_dspParameters[total]; total += 1; } // Add to DSP Preset list INTERNAL_dspPresets.Add( dspCode, new DSPPreset( global, parameters ) ); } } // Create the WaveBank Dictionary INTERNAL_waveBanks = new Dictionary<string, WaveBank>(); // Finally. IsDisposed = false; }
public RPC( string rpcVariable, ushort rpcParameter, RPCPoint[] rpcPoints ) { Variable = rpcVariable; Parameter = (RPCParameter) rpcParameter; Points = rpcPoints; }
public AudioEngine(string settingsFile) { if (String.IsNullOrEmpty(settingsFile)) { throw new ArgumentNullException("settingsFile"); } using (Stream stream = TitleContainer.OpenStream(settingsFile)) using (BinaryReader reader = new BinaryReader(stream)) { // Check the file header. Should be 'XGFS' if (reader.ReadUInt32() != 0x46534758) { throw new ArgumentException("XGFS format not recognized!"); } // Check the Content and Tool versions if (reader.ReadUInt16() != ContentVersion) { throw new ArgumentException("XGFS Content version!"); } if (reader.ReadUInt16() != 42) { throw new ArgumentException("XGFS Tool version!"); } // Unknown value reader.ReadUInt16(); // Last Modified, Unused reader.ReadUInt64(); // Unknown value reader.ReadByte(); // Number of AudioCategories ushort numCategories = reader.ReadUInt16(); // Number of XACT Variables ushort numVariables = reader.ReadUInt16(); // Unknown value, KEY#1 Length? reader.ReadUInt16(); // Unknown value, KEY#2 Length? reader.ReadUInt16(); // Number of RPC Variables ushort numRPCs = reader.ReadUInt16(); // Number of DSP Presets/Parameters ushort numDSPPresets = reader.ReadUInt16(); ushort numDSPParameters = reader.ReadUInt16(); // Category Offset in XGS File uint categoryOffset = reader.ReadUInt32(); // Variable Offset in XGS File uint variableOffset = reader.ReadUInt32(); // Unknown value, KEY#1 Offset? reader.ReadUInt32(); // Category Name Index Offset, unused reader.ReadUInt32(); // Unknown value, KEY#2 Offset? reader.ReadUInt32(); // Variable Name Index Offset, unused reader.ReadUInt32(); // Category Name Offset in XGS File uint categoryNameOffset = reader.ReadUInt32(); // Variable Name Offset in XGS File uint variableNameOffset = reader.ReadUInt32(); // RPC Variable Offset in XGS File uint rpcOffset = reader.ReadUInt32(); // DSP Preset/Parameter Offsets in XGS File uint dspPresetOffset = reader.ReadUInt32(); uint dspParameterOffset = reader.ReadUInt32(); // Obtain the Audio Category Names reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin); string[] categoryNames = new string[numCategories]; for (int i = 0; i < numCategories; i += 1) { List <char> builtString = new List <char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator categoryNames[i] = new string(builtString.ToArray()); } // Obtain the Audio Categories reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin); INTERNAL_categories = new List <AudioCategory>(); for (int i = 0; i < numCategories; i += 1) { // Maximum instances byte maxInstances = reader.ReadByte(); // Fade In/Out ushort fadeInMS = reader.ReadUInt16(); ushort fadeOutMS = reader.ReadUInt16(); // Instance Behavior Flags int maxBehavior = reader.ReadByte() & 0x0F; // FIXME: What? // Unknown value reader.ReadUInt16(); // Volume float volume = XACTCalculator.CalculateVolume(reader.ReadByte()); // Visibility Flags, unused reader.ReadByte(); // Add to the engine list INTERNAL_categories.Add( new AudioCategory( categoryNames[i], volume, maxInstances, maxBehavior, fadeInMS, fadeOutMS ) ); } // Obtain the Variable Names reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin); string[] variableNames = new string[numVariables]; for (int i = 0; i < numVariables; i += 1) { List <char> builtString = new List <char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator variableNames[i] = new string(builtString.ToArray()); } // Obtain the Variables reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin); INTERNAL_variables = new List <Variable>(); for (int i = 0; i < numVariables; i += 1) { // Variable Accessibility (See Variable constructor) byte varFlags = reader.ReadByte(); // Variable Value, Boundaries float initialValue = reader.ReadSingle(); float minValue = reader.ReadSingle(); float maxValue = reader.ReadSingle(); // Add to the engine list INTERNAL_variables.Add( new Variable( variableNames[i], (varFlags & 0x01) != 0, (varFlags & 0x02) != 0, (varFlags & 0x04) == 0, (varFlags & 0x08) != 0, initialValue, minValue, maxValue ) ); } // Append built-in properties to Variable list bool hasVolume = false; foreach (Variable curVar in INTERNAL_variables) { if (curVar.Name.Equals("Volume")) { hasVolume = true; } } if (!hasVolume) { INTERNAL_variables.Add( new Variable( "Volume", true, false, false, false, 1.0f, 0.0f, 1.0f ) ); } // Obtain the RPC Curves reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin); INTERNAL_RPCs = new Dictionary <long, RPC>(); for (int i = 0; i < numRPCs; i += 1) { // RPC "Code", used by the SoundBanks long rpcCode = reader.BaseStream.Position; // RPC Variable ushort rpcVariable = reader.ReadUInt16(); // Number of RPC Curve Points byte numPoints = reader.ReadByte(); // RPC Parameter ushort rpcParameter = reader.ReadUInt16(); // RPC Curve Points RPCPoint[] rpcPoints = new RPCPoint[numPoints]; for (byte j = 0; j < numPoints; j += 1) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); byte type = reader.ReadByte(); rpcPoints[j] = new RPCPoint( x, y, (RPCPointType)type ); } // Add to the engine list INTERNAL_RPCs.Add( rpcCode, new RPC( INTERNAL_variables[rpcVariable].Name, rpcParameter, rpcPoints ) ); } // Obtain the DSP Parameters reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin); INTERNAL_dspParameters = new List <DSPParameter>(); for (int i = 0; i < numDSPParameters; i += 1) { // Effect Parameter Type byte type = reader.ReadByte(); // Effect value, boundaries float value = reader.ReadSingle(); float minVal = reader.ReadSingle(); float maxVal = reader.ReadSingle(); // Unknown value reader.ReadUInt16(); // Add to Parameter list INTERNAL_dspParameters.Add( new DSPParameter( type, value, minVal, maxVal ) ); } // Obtain the DSP Presets reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin); INTERNAL_dspPresets = new Dictionary <long, DSPPreset>(); int total = 0; for (int i = 0; i < numDSPPresets; i += 1) { // DSP "Code", used by the SoundBanks long dspCode = reader.BaseStream.Position; // Preset Accessibility bool global = (reader.ReadByte() == 1); // Number of preset parameters uint numParams = reader.ReadUInt32(); // Obtain DSP Parameters DSPParameter[] parameters = new DSPParameter[numParams]; for (uint j = 0; j < numParams; j += 1) { parameters[j] = INTERNAL_dspParameters[total]; total += 1; } // Add to DSP Preset list // FIXME: Did XNA4 PC ever go past Reverb? INTERNAL_dspPresets.Add( dspCode, new DSPPreset( "Reverb", global, parameters ) ); } } // Create the WaveBank Dictionary INTERNAL_waveBanks = new Dictionary <string, WaveBank>(); // Finally. IsDisposed = false; }
public AudioEngine(string settingsFile) { if (String.IsNullOrEmpty(settingsFile)) { throw new ArgumentNullException("settingsFile"); } using (Stream stream = TitleContainer.OpenStream(settingsFile)) using (BinaryReader reader = new BinaryReader(stream)) { // Check the file header. Should be 'XGFS' if (reader.ReadUInt32() != 0x46534758) { throw new ArgumentException("XGFS format not recognized!"); } // Check the Content and Tool versions if (reader.ReadUInt16() != ContentVersion) { throw new ArgumentException("XGFS Content version!"); } if (reader.ReadUInt16() != 42) { throw new ArgumentException("XGFS Tool version!"); } // Unknown value reader.ReadUInt16(); // Last Modified, Unused reader.ReadUInt64(); // Unknown value reader.ReadByte(); // Number of AudioCategories ushort numCategories = reader.ReadUInt16(); // Number of XACT Variables ushort numVariables = reader.ReadUInt16(); // Unknown value, KEY#1 Length? reader.ReadUInt16(); // Unknown value, KEY#2 Length? reader.ReadUInt16(); // Number of RPC Variables ushort numRPCs = reader.ReadUInt16(); // Number of DSP Presets/Parameters ushort numDSPPresets = reader.ReadUInt16(); ushort numDSPParameters = reader.ReadUInt16(); // Category Offset in XGS File uint categoryOffset = reader.ReadUInt32(); // Variable Offset in XGS File uint variableOffset = reader.ReadUInt32(); // Unknown value, KEY#1 Offset? reader.ReadUInt32(); // Category Name Index Offset, unused reader.ReadUInt32(); // Unknown value, KEY#2 Offset? reader.ReadUInt32(); // Variable Name Index Offset, unused reader.ReadUInt32(); // Category Name Offset in XGS File uint categoryNameOffset = reader.ReadUInt32(); // Variable Name Offset in XGS File uint variableNameOffset = reader.ReadUInt32(); // RPC Variable Offset in XGS File uint rpcOffset = reader.ReadUInt32(); // DSP Preset/Parameter Offsets in XGS File uint dspPresetOffset = reader.ReadUInt32(); uint dspParameterOffset = reader.ReadUInt32(); // Obtain the Audio Category Names reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin); string[] categoryNames = new string[numCategories]; for (int i = 0; i < numCategories; i += 1) { List<char> builtString = new List<char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator categoryNames[i] = new string(builtString.ToArray()); } // Obtain the Audio Categories reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin); INTERNAL_categories = new List<AudioCategory>(); for (int i = 0; i < numCategories; i += 1) { // Maximum instances byte maxInstances = reader.ReadByte(); // Fade In/Out ushort fadeInMS = reader.ReadUInt16(); ushort fadeOutMS = reader.ReadUInt16(); // Instance Behavior Flags int maxBehavior = reader.ReadByte() & 0x0F; // FIXME: What? // Unknown value reader.ReadUInt16(); // Volume float volume = XACTCalculator.CalculateVolume(reader.ReadByte()); // Visibility Flags, unused reader.ReadByte(); // Add to the engine list INTERNAL_categories.Add( new AudioCategory( categoryNames[i], volume, maxInstances, maxBehavior, fadeInMS, fadeOutMS ) ); } // Obtain the Variable Names reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin); string[] variableNames = new string[numVariables]; for (int i = 0; i < numVariables; i += 1) { List<char> builtString = new List<char>(); while (reader.PeekChar() != 0) { builtString.Add(reader.ReadChar()); } reader.ReadChar(); // Null terminator variableNames[i] = new string(builtString.ToArray()); } // Obtain the Variables reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin); INTERNAL_variables = new List<Variable>(); for (int i = 0; i < numVariables; i += 1) { // Variable Accessibility (See Variable constructor) byte varFlags = reader.ReadByte(); // Variable Value, Boundaries float initialValue = reader.ReadSingle(); float minValue = reader.ReadSingle(); float maxValue = reader.ReadSingle(); // Add to the engine list INTERNAL_variables.Add( new Variable( variableNames[i], (varFlags & 0x01) != 0, (varFlags & 0x02) != 0, (varFlags & 0x04) == 0, (varFlags & 0x08) != 0, initialValue, minValue, maxValue ) ); } // Append built-in properties to Variable list bool hasVolume = false; foreach (Variable curVar in INTERNAL_variables) { if (curVar.Name.Equals("Volume")) { hasVolume = true; } } if (!hasVolume) { INTERNAL_variables.Add( new Variable( "Volume", true, false, false, false, 1.0f, 0.0f, 1.0f ) ); } // Obtain the RPC Curves reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin); INTERNAL_RPCs = new Dictionary<long, RPC>(); for (int i = 0; i < numRPCs; i += 1) { // RPC "Code", used by the SoundBanks long rpcCode = reader.BaseStream.Position; // RPC Variable ushort rpcVariable = reader.ReadUInt16(); // Number of RPC Curve Points byte numPoints = reader.ReadByte(); // RPC Parameter ushort rpcParameter = reader.ReadUInt16(); // RPC Curve Points RPCPoint[] rpcPoints = new RPCPoint[numPoints]; for (byte j = 0; j < numPoints; j += 1) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); byte type = reader.ReadByte(); rpcPoints[j] = new RPCPoint( x, y, (RPCPointType) type ); } // Add to the engine list INTERNAL_RPCs.Add( rpcCode, new RPC( INTERNAL_variables[rpcVariable].Name, rpcParameter, rpcPoints ) ); } // Obtain the DSP Parameters reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin); INTERNAL_dspParameters = new List<DSPParameter>(); for (int i = 0; i < numDSPParameters; i += 1) { // Effect Parameter Type byte type = reader.ReadByte(); // Effect value, boundaries float value = reader.ReadSingle(); float minVal = reader.ReadSingle(); float maxVal = reader.ReadSingle(); // Unknown value reader.ReadUInt16(); // Add to Parameter list INTERNAL_dspParameters.Add( new DSPParameter( type, value, minVal, maxVal ) ); } // Obtain the DSP Presets reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin); INTERNAL_dspPresets = new Dictionary<long, DSPPreset>(); int total = 0; for (int i = 0; i < numDSPPresets; i += 1) { // DSP "Code", used by the SoundBanks long dspCode = reader.BaseStream.Position; // Preset Accessibility bool global = (reader.ReadByte() == 1); // Number of preset parameters uint numParams = reader.ReadUInt32(); // Obtain DSP Parameters DSPParameter[] parameters = new DSPParameter[numParams]; for (uint j = 0; j < numParams; j += 1) { parameters[j] = INTERNAL_dspParameters[total]; total += 1; } // Add to DSP Preset list INTERNAL_dspPresets.Add( dspCode, new DSPPreset( global, parameters ) ); } } // Create the WaveBank Dictionary INTERNAL_waveBanks = new Dictionary<string, WaveBank>(); // Finally. IsDisposed = false; }