public WadSoundInfo(WadSoundInfo s) { Id = s.Id; Name = s.Name; Volume = s.Volume; RangeInSectors = s.RangeInSectors; Chance = s.Chance; PitchFactor = s.PitchFactor; DisablePanning = s.DisablePanning; RandomizePitch = s.RandomizePitch; RandomizeVolume = s.RandomizeVolume; LoopBehaviour = s.LoopBehaviour; Samples = new List <WadSample>(); SoundCatalog = s.SoundCatalog; Global = s.Global; Indexed = s.Indexed; foreach (var sample in s.Samples) { Samples.Add(new WadSample(sample.FileName)); } }
private static WadSounds ReadFromTxt(string filename) { var sounds = new WadSounds(); try { using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None)) { using (var reader = new StreamReader(fileStream)) { ushort soundId = 0; while (!reader.EndOfStream) { var s = reader.ReadLine().Trim(); var sound = new WadSoundInfo(soundId); // Get the name (ends with :) int endOfSoundName = s.IndexOf(':'); if (endOfSoundName == -1) { soundId++; continue; } sound.Name = s.Substring(0, endOfSoundName); sound.SoundCatalog = filename; // Get everything else and remove empty tokens var tokens = s.Substring(endOfSoundName + 1).Split(' ', '\t').Where(token => !string.IsNullOrEmpty(token)).ToList(); if (tokens.Count <= 1) { soundId++; continue; } // Trim comments int commentTokenIndex = tokens.FindIndex(t => t.StartsWith(";")); if (commentTokenIndex != -1) { tokens.RemoveRange(commentTokenIndex, tokens.Count - commentTokenIndex); } var anyTokenFound = false; for (int i = 0; i < tokens.Count; i++) { var token = tokens[i]; short temp = 0; if (token.StartsWith("PIT", StringComparison.InvariantCultureIgnoreCase) && short.TryParse(token.Substring(3), out temp)) { sound.PitchFactor = temp; anyTokenFound = true; } else if (token.StartsWith("RAD", StringComparison.InvariantCultureIgnoreCase) && short.TryParse(token.Substring(3), out temp)) { sound.RangeInSectors = temp; anyTokenFound = true; } else if (token.StartsWith("VOL", StringComparison.InvariantCultureIgnoreCase) && short.TryParse(token.Substring(3), out temp)) { sound.Volume = temp; anyTokenFound = true; } else if (token.StartsWith("CH", StringComparison.InvariantCultureIgnoreCase) && short.TryParse(token.Substring(2), out temp)) { sound.Chance = temp; anyTokenFound = true; } else if (token.Equals("P", StringComparison.InvariantCultureIgnoreCase)) { sound.RandomizePitch = true; anyTokenFound = true; } else if (token.Equals("V", StringComparison.InvariantCultureIgnoreCase)) { sound.RandomizeVolume = true; anyTokenFound = true; } else if (token.Equals("N", StringComparison.InvariantCultureIgnoreCase)) { sound.DisablePanning = true; anyTokenFound = true; } else if (token.Equals("L", StringComparison.InvariantCultureIgnoreCase)) { sound.LoopBehaviour = WadSoundLoopBehaviour.Looped; anyTokenFound = true; } else if (token.Equals("R", StringComparison.InvariantCultureIgnoreCase)) { sound.LoopBehaviour = WadSoundLoopBehaviour.OneShotRewound; anyTokenFound = true; } else if (token.Equals("W", StringComparison.InvariantCultureIgnoreCase)) { sound.LoopBehaviour = WadSoundLoopBehaviour.OneShotWait; anyTokenFound = true; } else if (token.StartsWith("#g")) { sound.Global = true; anyTokenFound = true; } else if (!token.StartsWith("#") && !anyTokenFound) { sound.Samples.Add(new WadSample(token + ".wav")); } if (token.StartsWith("#")) { sound.Indexed = true; } } sounds.SoundInfos.Add(sound); soundId++; } } } } catch (Exception ex) { return(null); } return(sounds); }
private static WadSounds ReadFromSfx(string filename) { var samples = new List <string>(); // Read version int version = 129; using (var readerVersion = new BinaryReaderEx(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) version = readerVersion.ReadInt32(); // Read samples var samPath = Path.GetDirectoryName(filename) + "\\" + Path.GetFileNameWithoutExtension(filename) + ".sam"; using (var readerSounds = new StreamReader(new FileStream(samPath, FileMode.Open, FileAccess.Read, FileShare.Read))) while (!readerSounds.EndOfStream) { samples.Add(readerSounds.ReadLine()); } // Read sounds int soundMapSize = 0; short[] soundMap; var wadSoundInfos = new List <wad_sound_info>(); var soundInfos = new List <WadSoundInfo>(); var sfxPath = Path.GetDirectoryName(filename) + "\\" + Path.GetFileNameWithoutExtension(filename) + ".sfx"; using (var readerSfx = new BinaryReaderEx(new FileStream(sfxPath, FileMode.Open, FileAccess.Read, FileShare.Read))) { // Try to guess the WAD version readerSfx.BaseStream.Seek(740, SeekOrigin.Begin); short first = readerSfx.ReadInt16(); short second = readerSfx.ReadInt16(); version = ((first == -1 || second == (first + 1)) ? 130 : 129); readerSfx.BaseStream.Seek(0, SeekOrigin.Begin); soundMapSize = (version == 130 ? 2048 : 370); soundMap = new short[soundMapSize]; for (var i = 0; i < soundMapSize; i++) { soundMap[i] = readerSfx.ReadInt16(); } var numSounds = readerSfx.ReadUInt32(); for (var i = 0; i < numSounds; i++) { var info = new wad_sound_info(); info.Sample = readerSfx.ReadUInt16(); info.Volume = readerSfx.ReadByte(); info.Range = readerSfx.ReadByte(); info.Chance = readerSfx.ReadByte(); info.Pitch = readerSfx.ReadByte(); info.Characteristics = readerSfx.ReadUInt16(); wadSoundInfos.Add(info); } } // Convert old data to new format for (int i = 0; i < soundMapSize; i++) { // Check if sound is defined at all if (soundMap[i] == -1 || soundMap[i] >= wadSoundInfos.Count) { continue; } // Fill the new sound info var oldInfo = wadSoundInfos[soundMap[i]]; var newInfo = new WadSoundInfo(i); newInfo.Name = TrCatalog.GetOriginalSoundName(TRVersion.Game.TR4, (uint)i); newInfo.Volume = (int)Math.Round(oldInfo.Volume * 100.0f / 255.0f); newInfo.RangeInSectors = oldInfo.Range; newInfo.Chance = (int)Math.Round(oldInfo.Chance * 100.0f / 255.0f); if (newInfo.Chance == 0) { newInfo.Chance = 100; // Convert legacy chance value } newInfo.PitchFactor = (int)Math.Round((oldInfo.Pitch > 127 ? oldInfo.Pitch - 256 : oldInfo.Pitch) * 100.0f / 128.0f); newInfo.RandomizePitch = ((oldInfo.Characteristics & 0x2000) != 0); newInfo.RandomizeVolume = ((oldInfo.Characteristics & 0x4000) != 0); newInfo.DisablePanning = ((oldInfo.Characteristics & 0x1000) != 0); newInfo.LoopBehaviour = (WadSoundLoopBehaviour)(oldInfo.Characteristics & 0x03); newInfo.SoundCatalog = sfxPath; // Read all samples linked to this sound info (for example footstep has 4 samples) int numSamplesInGroup = (oldInfo.Characteristics & 0x00fc) >> 2; for (int j = oldInfo.Sample; j < oldInfo.Sample + numSamplesInGroup; j++) { newInfo.Samples.Add(new WadSample(samples[j])); } soundInfos.Add(newInfo); } var sounds = new WadSounds(soundInfos); return(sounds); }
public static void PlaySoundInfo(Level level, WadSoundInfo soundInfo) { if (soundInfo == null || soundInfo.Samples == null || soundInfo.Samples.Count == 0) { return; } int channelIndex = FindPlayingIndex(soundInfo.Id); if (channelIndex >= 0) { switch (soundInfo.LoopBehaviour) { case WadSoundLoopBehaviour.Looped: case WadSoundLoopBehaviour.OneShotWait: return; case WadSoundLoopBehaviour.OneShotRewound: StopSample(channelIndex); break; case WadSoundLoopBehaviour.None: channelIndex = GetFreeChannel(); break; } } else { channelIndex = GetFreeChannel(); } _indices[channelIndex] = soundInfo.Id; // Figure out the precise play parameters int sampleIndex; int loopCount = soundInfo.LoopBehaviour == WadSoundLoopBehaviour.Looped ? 3 : 1; float pan = 0.0f; float volume = soundInfo.Volume / 100.0f; float pitch = (soundInfo.PitchFactor / 127.0f) + 1.0f; float chance = soundInfo.Chance == 0 ? 1.0f : soundInfo.Chance / 100.0f; lock (_rng) { if (chance != 1.0f && _rng.NextDouble() > chance) { return; } sampleIndex = _rng.Next(0, soundInfo.Samples.Count); if (sampleIndex == soundInfo.Samples.Count) { sampleIndex = soundInfo.Samples.Count - 1; } if (!soundInfo.DisablePanning) { pan = (float)((_rng.NextDouble() - 0.5f) * 1.6); } if (soundInfo.RandomizePitch) { pitch += (float)(_rng.NextDouble() * (6000.0 / 65536.0)); } if (soundInfo.RandomizeVolume) { volume -= (float)_rng.NextDouble() * 0.125f; } } PlaySample(level, soundInfo.Samples[sampleIndex], channelIndex, volume, pitch, pan, loopCount); }
private static bool LoadSoundInfo(ChunkReader chunkIO, Wad2 wad, Dictionary <long, WadSample> samples, out WadSoundInfo soundInfo, out long index) { var tempSoundInfo = new WadSoundInfo(0); long tempIndex = 0; float volume = 0; float chance = 0; float pitch = 0; float range = 0; chunkIO.ReadChunks((id2, chunkSize2) => { // XML_SOUND_SYSTEM if (id2 == Wad2Chunks.SoundInfoIndex) { tempIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoVolume) { volume = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRange) { range = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoPitch) { pitch = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoChance) { chance = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoDisablePanning) { tempSoundInfo.DisablePanning = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRandomizePitch) { tempSoundInfo.RandomizePitch = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRandomizeVolume) { tempSoundInfo.RandomizeVolume = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoLoopBehaviour) { tempSoundInfo.LoopBehaviour = (WadSoundLoopBehaviour)(3 & chunkIO.ReadChunkByte(chunkSize2)); } else if (id2 == Wad2Chunks.SoundInfoName || id2 == Wad2Chunks.SoundInfoNameObsolete) { tempSoundInfo.Name = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoSampleIndex) { tempSoundInfo.Samples.Add(samples[chunkIO.ReadChunkInt(chunkSize2)]); // Legacy } else { return(false); } return(true); }); // Convert from floats to ints tempSoundInfo.Volume = (int)Math.Round(volume * 100.0f); tempSoundInfo.RangeInSectors = (int)range; tempSoundInfo.Chance = (int)Math.Round(chance * 100.0f); tempSoundInfo.PitchFactor = (int)Math.Round((pitch - 1.0f) * 100.0f); // Try to get the old ID tempSoundInfo.Id = TrCatalog.TryGetSoundInfoIdByDescription(wad.GameVersion, tempSoundInfo.Name); if (string.IsNullOrWhiteSpace(tempSoundInfo.Name)) { tempSoundInfo.Name = TrCatalog.GetOriginalSoundName(wad.GameVersion, unchecked ((uint)tempIndex)); } index = tempIndex; soundInfo = tempSoundInfo; return(true); }