internal void Prepare() { IsDisposed = false; IsCreated = false; IsPrepared = true; _currentSound = null; }
internal Cue(AudioEngine engine, string cuename, XactSound sound) { _engine = engine; Name = cuename; _sounds = new XactSound[1]; _sounds[0] = sound; _probs = new float[1]; _probs[0] = 1f; _variables = engine.CreateCueVariables(); }
/// <summary> /// Requests playback of a prepared or preparing <see cref="Cue"/>. /// </summary> public void Play() { lock (_engine.UpdateLock) { if (!_engine.ActiveCues.Contains(this)) { _engine.ActiveCues.Add(this); } //TODO: Probabilities var index = XactHelpers.Random.Next(_sounds.Length); _currentSound = _sounds[index]; var volume = UpdateRpcCurves(); _currentSound.Play(volume, _engine); } _played = true; IsPrepared = false; }
internal void AddSound(XactSound sound) { _sounds.Add(sound); }
/// <param name="audioEngine">The engine that will be associated with this sound bank.</param> /// <param name="fileName">Path to a .xsb sound bank file.</param> public SoundBank(AudioEngine audioEngine, string fileName) { _audioengine = audioEngine ?? throw new ArgumentNullException(nameof(audioEngine)); if (string.IsNullOrEmpty(fileName)) { throw new ArgumentNullException(nameof(fileName)); } using (var stream = AudioEngine.OpenStream(fileName)) using (var reader = new BinaryReader(stream)) { // Thanks to Liandril for "xactxtract" for some of the offsets. uint magic = reader.ReadUInt32(); if (magic != 0x4B424453) //"SDBK" { throw new Exception("Bad soundbank format"); } reader.ReadUInt16(); // toolVersion uint formatVersion = reader.ReadUInt16(); if (formatVersion != 43) { Debug.WriteLine("Warning: SoundBank format {0} not supported.", formatVersion); } reader.ReadUInt16(); // crc, TODO: Verify crc (FCS16) reader.ReadUInt32(); // lastModifiedLow reader.ReadUInt32(); // lastModifiedHigh reader.ReadByte(); // platform ??? uint numSimpleCues = reader.ReadUInt16(); uint numComplexCues = reader.ReadUInt16(); reader.ReadUInt16(); //unkn reader.ReadUInt16(); // numTotalCues uint numWaveBanks = reader.ReadByte(); reader.ReadUInt16(); // numSounds uint cueNameTableLen = reader.ReadUInt16(); reader.ReadUInt16(); //unkn uint simpleCuesOffset = reader.ReadUInt32(); uint complexCuesOffset = reader.ReadUInt32(); //unkn uint cueNamesOffset = reader.ReadUInt32(); reader.ReadUInt32(); //unkn reader.ReadUInt32(); // variationTablesOffset reader.ReadUInt32(); //unkn uint waveBankNameTableOffset = reader.ReadUInt32(); reader.ReadUInt32(); // cueNameHashTableOffset reader.ReadUInt32(); // cueNameHashValsOffset reader.ReadUInt32(); // soundsOffset //parse wave bank name table stream.Seek(waveBankNameTableOffset, SeekOrigin.Begin); _waveBanks = new WaveBank[numWaveBanks]; _waveBankNames = new string[numWaveBanks]; for (int i = 0; i < numWaveBanks; i++) { _waveBankNames[i] = System.Text.Encoding.UTF8 .GetString(reader.ReadBytes(64)).Replace("\0", "", StringComparison.Ordinal); } //parse cue name table stream.Seek(cueNamesOffset, SeekOrigin.Begin); string[] cueNames = System.Text.Encoding.UTF8 .GetString(reader.ReadBytes((int)cueNameTableLen)).Split('\0'); // Simple cues if (numSimpleCues > 0) { stream.Seek(simpleCuesOffset, SeekOrigin.Begin); for (int i = 0; i < numSimpleCues; i++) { reader.ReadByte(); // flags uint soundOffset = reader.ReadUInt32(); var oldPosition = stream.Position; stream.Seek(soundOffset, SeekOrigin.Begin); var sound = new XactSound(audioEngine, this, reader); stream.Seek(oldPosition, SeekOrigin.Begin); _entries.Add( cueNames[i], new XactCueEntry(new XactSound[] { sound }, _defaultProbability)); } } // Complex cues if (numComplexCues > 0) { stream.Seek(complexCuesOffset, SeekOrigin.Begin); for (int i = 0; i < numComplexCues; i++) { byte flags = reader.ReadByte(); if (((flags >> 2) & 1) != 0) { uint soundOffset = reader.ReadUInt32(); reader.ReadUInt32(); //unkn var oldPosition = stream.Position; stream.Seek(soundOffset, SeekOrigin.Begin); var sound = new XactSound(audioEngine, this, reader); stream.Seek(oldPosition, SeekOrigin.Begin); _entries.Add( cueNames[numSimpleCues + i], new XactCueEntry(new XactSound[] { sound }, _defaultProbability)); } else { uint variationTableOffset = reader.ReadUInt32(); reader.ReadUInt32(); // transitionTableOffset //parse variation table long savepos = stream.Position; stream.Seek(variationTableOffset, SeekOrigin.Begin); uint numEntries = reader.ReadUInt16(); uint variationflags = reader.ReadUInt16(); reader.ReadByte(); reader.ReadUInt16(); reader.ReadByte(); var cueSounds = new XactSound[numEntries]; var probs = new float[numEntries]; uint tableType = (variationflags >> 3) & 0x7; for (int j = 0; j < numEntries; j++) { switch (tableType) { case 0: //Wave { int trackIndex = reader.ReadUInt16(); int waveBankIndex = reader.ReadByte(); reader.ReadByte(); // weightMin reader.ReadByte(); // weightMax cueSounds[j] = new XactSound(this, waveBankIndex, trackIndex); break; } case 1: { uint soundOffset = reader.ReadUInt32(); reader.ReadByte(); // weightMin reader.ReadByte(); // weightMax var oldPosition = stream.Position; stream.Seek(soundOffset, SeekOrigin.Begin); cueSounds[j] = new XactSound(audioEngine, this, reader); stream.Seek(oldPosition, SeekOrigin.Begin); break; } case 3: { uint soundOffset = reader.ReadUInt32(); reader.ReadSingle(); // weightMin reader.ReadSingle(); // weightMax reader.ReadUInt32(); // flags var oldPosition = stream.Position; stream.Seek(soundOffset, SeekOrigin.Begin); cueSounds[j] = new XactSound(audioEngine, this, reader); stream.Seek(oldPosition, SeekOrigin.Begin); break; } case 4: //CompactWave { int trackIndex = reader.ReadUInt16(); int waveBankIndex = reader.ReadByte(); cueSounds[j] = new XactSound(this, waveBankIndex, trackIndex); break; } default: throw new NotSupportedException(); } } stream.Seek(savepos, SeekOrigin.Begin); _entries.Add( cueNames[numSimpleCues + i], new XactCueEntry(cueSounds, probs)); } // Instance limiting reader.ReadByte(); //instanceLimit reader.ReadUInt16(); //fadeInSec, divide by 1000f reader.ReadUInt16(); //fadeOutSec, divide by 1000f reader.ReadByte(); //instanceFlags } } } }