public CueData(XACTSound sound) { Sounds = new XACTSound[1]; Probabilities = new float[1, 2]; Sounds[0] = sound; Category = sound.Category; Probabilities[0, 0] = 1.0f; Probabilities[0, 1] = 0.0f; IsUserControlled = false; // Assume we can have max instances, for now. InstanceLimit = 255; MaxCueBehavior = MaxInstanceBehavior.ReplaceOldest; }
public CueData( XACTSound[] sounds, float[,] probabilities, string controlVariable ) { Sounds = sounds; Category = Sounds[0].Category; // FIXME: Assumption! Probabilities = probabilities; IsUserControlled = !String.IsNullOrEmpty(controlVariable); UserControlVariable = controlVariable; // Assume we can have max instances, for now. InstanceLimit = 255; MaxCueBehavior = MaxInstanceBehavior.ReplaceOldest; }
private bool INTERNAL_calculateNextSound() { INTERNAL_activeSound = null; INTERNAL_eventList.Clear(); INTERNAL_eventPlayed.Clear(); INTERNAL_eventLoops.Clear(); INTERNAL_waveEventSounds.Clear(); // Pick a sound based on a Cue instance variable if (INTERNAL_data.IsUserControlled) { INTERNAL_userControlledPlaying = true; if (INTERNAL_baseEngine.INTERNAL_isGlobalVariable(INTERNAL_data.UserControlVariable)) { INTERNAL_controlledValue = INTERNAL_baseEngine.GetGlobalVariable( INTERNAL_data.UserControlVariable ); } else { INTERNAL_controlledValue = GetVariable( INTERNAL_data.UserControlVariable ); } for (int i = 0; i < INTERNAL_data.Probabilities.Length / 2; i += 1) { if (INTERNAL_controlledValue <= INTERNAL_data.Probabilities[i, 0] && INTERNAL_controlledValue >= INTERNAL_data.Probabilities[i, 1]) { INTERNAL_activeSound = INTERNAL_data.Sounds[i]; return(true); } } /* This should only happen when the * UserControlVariable is none of the sound * probabilities, in which case we are just * silent. But, we are still claiming to be * "playing" in the meantime. * -flibit */ return(false); } // Randomly pick a sound double max = 0.0; for (int i = 0; i < INTERNAL_data.Probabilities.GetLength(0); i += 1) { max += INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1]; } double next = random.NextDouble() * max; for (int i = INTERNAL_data.Probabilities.GetLength(0) - 1; i >= 0; i -= 1) { if (next > max - (INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1])) { INTERNAL_activeSound = INTERNAL_data.Sounds[i]; break; } max -= INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1]; } return(true); }
private bool INTERNAL_calculateNextSound() { INTERNAL_activeSound = null; INTERNAL_eventList.Clear(); INTERNAL_eventPlayed.Clear(); INTERNAL_eventLoops.Clear(); INTERNAL_waveEventSounds.Clear(); // Pick a sound based on a Cue instance variable if (INTERNAL_data.IsUserControlled) { INTERNAL_userControlledPlaying = true; if (INTERNAL_baseEngine.INTERNAL_isGlobalVariable(INTERNAL_data.UserControlVariable)) { INTERNAL_controlledValue = INTERNAL_baseEngine.GetGlobalVariable( INTERNAL_data.UserControlVariable ); } else { INTERNAL_controlledValue = GetVariable( INTERNAL_data.UserControlVariable ); } for (int i = 0; i < INTERNAL_data.Probabilities.Length / 2; i += 1) { if ( INTERNAL_controlledValue <= INTERNAL_data.Probabilities[i, 0] && INTERNAL_controlledValue >= INTERNAL_data.Probabilities[i, 1] ) { INTERNAL_activeSound = INTERNAL_data.Sounds[i]; return true; } } /* This should only happen when the * UserControlVariable is none of the sound * probabilities, in which case we are just * silent. But, we are still claiming to be * "playing" in the meantime. * -flibit */ return false; } // Randomly pick a sound double max = 0.0; for (int i = 0; i < INTERNAL_data.Probabilities.GetLength(0); i += 1) { max += INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1]; } double next = random.NextDouble() * max; for (int i = INTERNAL_data.Probabilities.GetLength(0) - 1; i >= 0; i -= 1) { if (next > max - (INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1])) { INTERNAL_activeSound = INTERNAL_data.Sounds[i]; break; } max -= INTERNAL_data.Probabilities[i, 0] - INTERNAL_data.Probabilities[i, 1]; } return true; }
public SoundBank(AudioEngine audioEngine, string filename) { if (audioEngine == null) { throw new ArgumentNullException("audioEngine"); } if (String.IsNullOrEmpty(filename)) { throw new ArgumentNullException("filename"); } INTERNAL_baseEngine = audioEngine; using (Stream soundBankStream = TitleContainer.OpenStream(filename)) using (BinaryReader reader = new BinaryReader(soundBankStream)) { // Check the file header. Should be 'SDBK' if (reader.ReadUInt32() != 0x4B424453) { throw new ArgumentException("SDBK format not recognized!"); } // Check the content version. Assuming XNA4 Refresh. if (reader.ReadUInt16() != AudioEngine.ContentVersion) { throw new ArgumentException("SDBK Content version!"); } // Check the tool version. Assuming XNA4 Refresh. if (reader.ReadUInt16() != 43) { throw new ArgumentException("SDBK Tool version!"); } // CRC, unused reader.ReadUInt16(); // Last modified, unused reader.ReadUInt64(); // Unknown value, Internet suggests platform reader.ReadByte(); // Cue Counts ushort numCueSimple = reader.ReadUInt16(); ushort numCueComplex = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Total Cues, unused reader.ReadUInt16(); // Number of associated WaveBanks byte numWaveBanks = reader.ReadByte(); // Unknown, Internet suggest number of "sounds" reader.ReadUInt16(); // Cue Name Table Length ushort cueNameTableLength = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Cue Offsets uint cueSimpleOffset = reader.ReadUInt32(); uint cueComplexOffset = reader.ReadUInt32(); // Cue Name Table Offset uint cueNameTableOffset = reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // Variable Tables Offset, unused reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // WaveBank Name Table Offset uint waveBankNameTableOffset = reader.ReadUInt32(); // Cue Name Hash Offsets, unused reader.ReadUInt32(); reader.ReadUInt32(); // Unknown value, Internet suggest "sounds" offset reader.ReadUInt32(); // SoundBank Name, unused System.Text.Encoding.UTF8.GetString( reader.ReadBytes(64), 0, 64 ).Replace("\0", ""); // Parse WaveBank names soundBankStream.Seek(waveBankNameTableOffset, SeekOrigin.Begin); INTERNAL_waveBankNames = new List <string>(); for (byte i = 0; i < numWaveBanks; i += 1) { INTERNAL_waveBankNames.Add( System.Text.Encoding.UTF8.GetString( reader.ReadBytes(64), 0, 64 ).Replace("\0", "") ); } // Parse Cue name list soundBankStream.Seek(cueNameTableOffset, SeekOrigin.Begin); string[] cueNames = System.Text.Encoding.UTF8.GetString( reader.ReadBytes(cueNameTableLength), 0, cueNameTableLength ).Split('\0'); // Create our CueData Dictionary INTERNAL_cueData = new Dictionary <string, CueData>(); // Parse Simple Cues soundBankStream.Seek(cueSimpleOffset, SeekOrigin.Begin); for (ushort i = 0; i < numCueSimple; i += 1) { // Cue flags, unused reader.ReadByte(); // Cue Sound Offset uint offset = reader.ReadUInt32(); // Store this for when we're done reading the sound. long curPos = reader.BaseStream.Position; // Go to the sound in the Bank. reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Parse the Sound INTERNAL_cueData.Add( cueNames[i], new CueData(new XACTSound(reader)) ); // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); } // Parse Complex Cues soundBankStream.Seek(cueComplexOffset, SeekOrigin.Begin); for (ushort i = 0; i < numCueComplex; i += 1) { // Cue flags byte cueFlags = reader.ReadByte(); if ((cueFlags & 0x04) != 0) // FIXME: ??? { // Cue Sound Offset uint offset = reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // Store this for when we're done reading the sound. long curPos = reader.BaseStream.Position; // Go to the sound in the bank reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Parse the Sound INTERNAL_cueData.Add( cueNames[numCueSimple + i], new CueData(new XACTSound(reader)) ); // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); } else { // Variation Table Offset for this Cue uint offset = reader.ReadUInt32(); // Transition Table Offset for this Cue, unused reader.ReadUInt32(); // Store this for when we're done reading the Variation Table long curPos = reader.BaseStream.Position; // Seek to the Variation Table in the file reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Number of Variations in the Table ushort numVariations = reader.ReadUInt16(); // Variation Table Flags ushort varTableFlags = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Probability Control Variable, if applicable ushort variable = reader.ReadUInt16(); // Create data for the CueData XACTSound[] cueSounds = new XACTSound[numVariations]; float[,] cueProbs = new float[numVariations, 2]; // Used to determine Variation storage format int varTableType = (varTableFlags >> 3) & 0x0007; for (ushort j = 0; j < numVariations; j += 1) { if (varTableType == 0) { // Wave with byte min/max ushort track = reader.ReadUInt16(); byte waveBank = reader.ReadByte(); byte wMin = reader.ReadByte(); byte wMax = reader.ReadByte(); // Create the Sound cueSounds[j] = new XACTSound(track, waveBank); // Calculate probability based on weight cueProbs[j, 0] = wMax / 255.0f; cueProbs[j, 1] = wMin / 255.0f; } else if (varTableType == 1) { // Complex with byte min/max uint varOffset = reader.ReadUInt32(); byte wMin = reader.ReadByte(); byte wMax = reader.ReadByte(); // Store for sound read long varPos = reader.BaseStream.Position; // Seek to the sound in the Bank reader.BaseStream.Seek(varOffset, SeekOrigin.Begin); // Read the sound cueSounds[j] = new XACTSound(reader); // Back to where we were... reader.BaseStream.Seek(varPos, SeekOrigin.Begin); // Calculate probability based on weight cueProbs[j, 0] = wMax / 255.0f; cueProbs[j, 1] = wMin / 255.0f; } else if (varTableType == 3) { // Complex with float min/max uint varOffset = reader.ReadUInt32(); float wMin = reader.ReadSingle(); float wMax = reader.ReadSingle(); // Unknown value reader.ReadUInt32(); // Store for sound read long varPos = reader.BaseStream.Position; // Seek to the sound in the Bank reader.BaseStream.Seek(varOffset, SeekOrigin.Begin); // Read the sound cueSounds[j] = new XACTSound(reader); // Back to where we were... reader.BaseStream.Seek(varPos, SeekOrigin.Begin); // Calculate probability based on weight cueProbs[j, 0] = wMax; cueProbs[j, 1] = wMin; } else if (varTableType == 4) { // Compact Wave ushort track = reader.ReadUInt16(); byte waveBank = reader.ReadByte(); // Create the Sound cueSounds[j] = new XACTSound(track, waveBank); // FIXME: Assume Sound weight is 100% cueProbs[j, 0] = 1.0f; cueProbs[j, 1] = 0.0f; } else { throw new NotSupportedException(); } } // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); // Add Built CueData to Dictionary INTERNAL_cueData.Add( cueNames[numCueSimple + i], new CueData( cueSounds, cueProbs, (varTableType == 3) ? INTERNAL_baseEngine.INTERNAL_getVariableName(variable) : String.Empty ) ); } // Cue instance limit byte instanceLimit = reader.ReadByte(); // Fade In/Out, unused reader.ReadUInt16(); reader.ReadUInt16(); // Cue max instance behavior byte behavior = reader.ReadByte(); INTERNAL_cueData[cueNames[numCueSimple + i]].SetLimit( instanceLimit, behavior ); } } IsDisposed = false; }
public SoundBank(AudioEngine audioEngine, string filename) { if (audioEngine == null) { throw new ArgumentNullException("audioEngine"); } if (String.IsNullOrEmpty(filename)) { throw new ArgumentNullException("filename"); } INTERNAL_baseEngine = audioEngine; using (Stream soundBankStream = TitleContainer.OpenStream(filename)) using (BinaryReader reader = new BinaryReader(soundBankStream)) { // Check the file header. Should be 'SDBK' if (reader.ReadUInt32() != 0x4B424453) { throw new ArgumentException("SDBK format not recognized!"); } // Check the content version. Assuming XNA4 Refresh. if (reader.ReadUInt16() != AudioEngine.ContentVersion) { throw new ArgumentException("SDBK Content version!"); } // Check the tool version. Assuming XNA4 Refresh. if (reader.ReadUInt16() != 43) { throw new ArgumentException("SDBK Tool version!"); } // CRC, unused reader.ReadUInt16(); // Last modified, unused reader.ReadUInt64(); // Unknown value, Internet suggests platform reader.ReadByte(); // Cue Counts ushort numCueSimple = reader.ReadUInt16(); ushort numCueComplex = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Total Cues, unused reader.ReadUInt16(); // Number of associated WaveBanks byte numWaveBanks = reader.ReadByte(); // Unknown, Internet suggest number of "sounds" reader.ReadUInt16(); // Cue Name Table Length ushort cueNameTableLength = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Cue Offsets uint cueSimpleOffset = reader.ReadUInt32(); uint cueComplexOffset = reader.ReadUInt32(); // Cue Name Table Offset uint cueNameTableOffset = reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // Variable Tables Offset, unused reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // WaveBank Name Table Offset uint waveBankNameTableOffset = reader.ReadUInt32(); // Cue Name Hash Offsets, unused reader.ReadUInt32(); reader.ReadUInt32(); // Unknown value, Internet suggest "sounds" offset reader.ReadUInt32(); // SoundBank Name, unused reader.ReadBytes(64); // Parse WaveBank names soundBankStream.Seek(waveBankNameTableOffset, SeekOrigin.Begin); INTERNAL_waveBankNames = new List<string>(); for (byte i = 0; i < numWaveBanks; i += 1) { INTERNAL_waveBankNames.Add( System.Text.Encoding.UTF8.GetString( reader.ReadBytes(64), 0, 64 ).Replace("\0", "") ); } // Parse Cue name list soundBankStream.Seek(cueNameTableOffset, SeekOrigin.Begin); string[] cueNames = System.Text.Encoding.UTF8.GetString( reader.ReadBytes(cueNameTableLength), 0, cueNameTableLength ).Split('\0'); // Create our CueData Dictionary INTERNAL_cueData = new Dictionary<string, CueData>(); // Parse Simple Cues soundBankStream.Seek(cueSimpleOffset, SeekOrigin.Begin); for (ushort i = 0; i < numCueSimple; i += 1) { // Cue flags, unused reader.ReadByte(); // Cue Sound Offset uint offset = reader.ReadUInt32(); // Store this for when we're done reading the sound. long curPos = reader.BaseStream.Position; // Go to the sound in the Bank. reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Parse the Sound INTERNAL_cueData.Add( cueNames[i], new CueData(new XACTSound(reader)) ); // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); } // Parse Complex Cues soundBankStream.Seek(cueComplexOffset, SeekOrigin.Begin); for (ushort i = 0; i < numCueComplex; i += 1) { // Cue flags byte cueFlags = reader.ReadByte(); if ((cueFlags & 0x04) != 0) // FIXME: ??? { // Cue Sound Offset uint offset = reader.ReadUInt32(); // Unknown value reader.ReadUInt32(); // Store this for when we're done reading the sound. long curPos = reader.BaseStream.Position; // Go to the sound in the bank reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Parse the Sound INTERNAL_cueData.Add( cueNames[numCueSimple + i], new CueData(new XACTSound(reader)) ); // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); } else { // Variation Table Offset for this Cue uint offset = reader.ReadUInt32(); // Transition Table Offset for this Cue, unused reader.ReadUInt32(); // Store this for when we're done reading the Variation Table long curPos = reader.BaseStream.Position; // Seek to the Variation Table in the file reader.BaseStream.Seek(offset, SeekOrigin.Begin); // Number of Variations in the Table ushort numVariations = reader.ReadUInt16(); // Variation Table Flags ushort varTableFlags = reader.ReadUInt16(); // Unknown value reader.ReadUInt16(); // Probability Control Variable, if applicable ushort variable = reader.ReadUInt16(); // Create data for the CueData XACTSound[] cueSounds = new XACTSound[numVariations]; float[,] cueProbs = new float[numVariations, 2]; // Used to determine Variation storage format int varTableType = (varTableFlags >> 3) & 0x0007; for (ushort j = 0; j < numVariations; j += 1) { if (varTableType == 0) { // Wave with byte min/max ushort track = reader.ReadUInt16(); byte waveBank = reader.ReadByte(); byte wMin = reader.ReadByte(); byte wMax = reader.ReadByte(); // Create the Sound cueSounds[j] = new XACTSound(track, waveBank); // Calculate probability based on weight cueProbs[j, 0] = wMax / 255.0f; cueProbs[j, 1] = wMin / 255.0f; } else if (varTableType == 1) { // Complex with byte min/max uint varOffset = reader.ReadUInt32(); byte wMin = reader.ReadByte(); byte wMax = reader.ReadByte(); // Store for sound read long varPos = reader.BaseStream.Position; // Seek to the sound in the Bank reader.BaseStream.Seek(varOffset, SeekOrigin.Begin); // Read the sound cueSounds[j] = new XACTSound(reader); // Back to where we were... reader.BaseStream.Seek(varPos, SeekOrigin.Begin); // Calculate probability based on weight cueProbs[j, 0] = wMax / 255.0f; cueProbs[j, 1] = wMin / 255.0f; } else if (varTableType == 3) { // Complex with float min/max uint varOffset = reader.ReadUInt32(); float wMin = reader.ReadSingle(); float wMax = reader.ReadSingle(); // Unknown value reader.ReadUInt32(); // Store for sound read long varPos = reader.BaseStream.Position; // Seek to the sound in the Bank reader.BaseStream.Seek(varOffset, SeekOrigin.Begin); // Read the sound cueSounds[j] = new XACTSound(reader); // Back to where we were... reader.BaseStream.Seek(varPos, SeekOrigin.Begin); // Calculate probability based on weight cueProbs[j, 0] = wMax; cueProbs[j, 1] = wMin; } else if (varTableType == 4) { // Compact Wave ushort track = reader.ReadUInt16(); byte waveBank = reader.ReadByte(); // Create the Sound cueSounds[j] = new XACTSound(track, waveBank); // FIXME: Assume Sound weight is 100% cueProbs[j, 0] = 1.0f; cueProbs[j, 1] = 0.0f; } else { throw new NotSupportedException(); } } // Back to where we were... reader.BaseStream.Seek(curPos, SeekOrigin.Begin); // Add Built CueData to Dictionary INTERNAL_cueData.Add( cueNames[numCueSimple + i], new CueData( cueSounds, cueProbs, (varTableType == 3) ? INTERNAL_baseEngine.INTERNAL_getVariableName(variable) : String.Empty ) ); } // Cue instance limit byte instanceLimit = reader.ReadByte(); // Fade In/Out, unused reader.ReadUInt16(); reader.ReadUInt16(); // Cue max instance behavior byte behavior = reader.ReadByte(); INTERNAL_cueData[cueNames[numCueSimple + i]].SetLimit( instanceLimit, behavior ); } } IsDisposed = false; }
public XACTSoundInstance(XACTSound sound) { Sound = sound; }