/// <summary>Plays a car sound.</summary> /// <param name="sound">The car sound.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="train">The train the sound is attached to.</param> /// <param name="car">The car in the train the sound is attached to.</param> /// <param name="looped">Whether to play the sound in a loop.</param> /// <returns>The sound source.</returns> internal static void PlayCarSound(TrainManager.CarSound sound, double pitch, double volume, TrainManager.Train train, int car, bool looped) { if (sound.Buffer == null) { return; } if (train == null) { throw new InvalidDataException("A train and car must be specified"); } sound.Source = PlaySound(sound.Buffer, pitch, volume, sound.Position, train, car, looped); }
/// <summary>Attempts to load an array of sound files into a car-sound array</summary> /// <param name="Folder">The folder the sound files are located in</param> /// <param name="FileStart">The first sound file</param> /// <param name="FileEnd">The last sound file</param> /// <param name="Position">The position the sound is to be emitted from within the car</param> /// <param name="Radius">The sound radius</param> /// <returns>The new car sound array</returns> internal static TrainManager.CarSound[] TryLoadSoundArray(string Folder, string FileStart, string FileEnd, Vector3 Position, double Radius) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; TrainManager.CarSound[] Sounds = { }; if (!System.IO.Directory.Exists(Folder)) { //Detect whether the given folder exists before attempting to load from it return(Sounds); } string[] Files = System.IO.Directory.GetFiles(Folder); for (int i = 0; i < Files.Length; i++) { string a = System.IO.Path.GetFileName(Files[i]); if (a == null) { return(Sounds); } if (a.Length > FileStart.Length + FileEnd.Length) { if (a.StartsWith(FileStart, StringComparison.OrdinalIgnoreCase) & a.EndsWith(FileEnd, StringComparison.OrdinalIgnoreCase)) { string b = a.Substring(FileStart.Length, a.Length - FileEnd.Length - FileStart.Length); int n; if (int.TryParse(b, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n >= 0) { int m = Sounds.Length; if (n >= m) { Array.Resize <TrainManager.CarSound>(ref Sounds, n + 1); for (int j = m; j < n; j++) { Sounds[j] = TrainManager.CarSound.Empty; Sounds[j].Source = null; } } Sounds[n] = new TrainManager.CarSound(Files[i], Position, Radius); } } } } } return(Sounds); }
/// <summary>Parses an XML node containing a list of sounds into a car sound array</summary> /// <param name="node">The node to parse</param> /// <param name="Sounds">The car sound array</param> /// <param name="Position">The default position of the sound (May be overriden by any node)</param> /// <param name="Radius">The default radius of the sound (May be overriden by any node)</param> private static void ParseArrayNode(XmlNode node, out TrainManager.CarSound[] Sounds, Vector3 Position, double Radius) { Sounds = new TrainManager.CarSound[0]; foreach (XmlNode c in node.ChildNodes) { int idx = -1; if (c.Name.ToLowerInvariant() != "sound") { Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array node " + c.Name + " in XML node " + node.Name); } else { for (int i = 0; i < c.ChildNodes.Count; i++) { if (c.ChildNodes[i].Name.ToLowerInvariant() == "index") { if (!NumberFormats.TryParseIntVb6(c.ChildNodes[i].InnerText.ToLowerInvariant(), out idx)) { Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name); return; } break; } } if (idx >= 0) { int l = Sounds.Length; Array.Resize(ref Sounds, idx + 1); while (l < Sounds.Length) { Sounds[l] = TrainManager.CarSound.Empty; l++; } ParseNode(c, out Sounds[idx], Position, Radius); } else { Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name); } } } }
private static TrainManager.CarSound[] TryLoadSoundArray(string Folder, string FileStart, string FileEnd, Vector3 Position, double Radius) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; TrainManager.CarSound[] Sounds = new TrainManager.CarSound[] { }; string[] Files = System.IO.Directory.GetFiles(Folder); for (int i = 0; i < Files.Length; i++) { string a = System.IO.Path.GetFileName(Files[i]); if (a.Length > FileStart.Length + FileEnd.Length) { if (a.StartsWith(FileStart, StringComparison.OrdinalIgnoreCase) & a.EndsWith(FileEnd, StringComparison.OrdinalIgnoreCase)) { string b = a.Substring(FileStart.Length, a.Length - FileEnd.Length - FileStart.Length); int n; if (int.TryParse(b, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n >= 0) { int m = Sounds.Length; if (n >= m) { Array.Resize<TrainManager.CarSound>(ref Sounds, n + 1); for (int j = m; j < n; j++) { Sounds[j] = TrainManager.CarSound.Empty; Sounds[j].Source = null; } } Sounds[n] = TryLoadSound(Files[i], Position, Radius); } } } } } return Sounds; }
/// <summary>Parses a single XML node into a car sound</summary> /// <param name="node">The node to parse</param> /// <param name="Sound">The car sound</param> /// <param name="Position">The default position of this sound (May be overriden by the node)</param> /// <param name="Radius">The default radius of this sound (May be overriden by the node)</param> private static void ParseNode(XmlNode node, out TrainManager.CarSound Sound, Vector3 Position, double Radius) { string fileName = null; foreach (XmlNode c in node.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { fileName = OpenBveApi.Path.CombineFile(currentPath, c.InnerText); if (!System.IO.File.Exists(fileName)) { //Valid path, but the file does not exist Interface.AddMessage(Interface.MessageType.Error, false, "The sound path " + c.InnerText + " in XML node " + node.Name + " does not exist."); Sound = TrainManager.CarSound.Empty; return; } } catch { //Probably invalid filename characters Interface.AddMessage(Interface.MessageType.Error, false, "The sound path " + c.InnerText + " in XML node " + node.Name + " is invalid."); Sound = TrainManager.CarSound.Empty; return; } break; case "position": string[] Arguments = c.InnerText.Split(','); double x = 0.0, y = 0.0, z = 0.0; if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius X " + Arguments[0] + " in XML node " + node.Name + " is invalid."); x = 0.0; } if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[1], out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius Y " + Arguments[1] + " in XML node " + node.Name + " is invalid."); y = 0.0; } if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[2], out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius Z " + Arguments[2] + " in XML node " + node.Name + " is invalid."); z = 0.0; } Position = new Vector3(x, y, z); break; case "radius": if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Radius)) { Interface.AddMessage(Interface.MessageType.Error, false, "The sound radius " + c.InnerText + " in XML node " + node.Name + " is invalid."); } break; } } if (fileName == null) { //No valid filename node specified Interface.AddMessage(Interface.MessageType.Error, false, "XML node " + node.Name + " does not point to a valid sound file."); Sound = TrainManager.CarSound.Empty; return; } Sound = new TrainManager.CarSound(fileName, Position, Radius); }
/// <summary>Loads the sound set for a BVE2 based train</summary> /// <param name="train">The train</param> /// <param name="trainFolder">The absolute on-disk path to the train's folder</param> internal static void Parse(string trainFolder, TrainManager.Train train) { // set sound positions and radii Vector3 front = new Vector3(0.0, 0.0, 0.5 * train.Cars[train.DriverCar].Length); Vector3 center = new Vector3(0.0, 0.0, 0.0); Vector3 left = new Vector3(-1.3, 0.0, 0.0); Vector3 right = new Vector3(1.3, 0.0, 0.0); Vector3 cab = new Vector3(-train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z - 0.5); Vector3 panel = new Vector3(train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z + 1.0); // load sounds for driver's car train.Cars[train.DriverCar].Sounds.Adjust = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Adjust.wav"), panel, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Sounds.Brake = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Brake.wav"), center, SoundCfgParser.smallRadius); train.Cars[train.DriverCar].Sounds.Halt = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Halt.wav"), cab, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Horns[0].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon0.wav"), SoundCfgParser.smallRadius); train.Cars[train.DriverCar].Horns[0].Loop = false; train.Cars[train.DriverCar].Horns[0].SoundPosition = front; if (train.Cars[train.DriverCar].Horns[0].LoopSound == null) { train.Cars[train.DriverCar].Horns[0].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon.wav"), SoundCfgParser.largeRadius); } train.Cars[train.DriverCar].Horns[1].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon1.wav"), SoundCfgParser.largeRadius); train.Cars[train.DriverCar].Horns[1].Loop = false; train.Cars[train.DriverCar].Horns[1].SoundPosition = front; train.Cars[train.DriverCar].Horns[2].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon2.wav"), SoundCfgParser.mediumRadius); train.Cars[train.DriverCar].Horns[2].Loop = true; train.Cars[train.DriverCar].Horns[2].SoundPosition = front; train.Cars[train.DriverCar].Sounds.PilotLampOn = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Leave.wav"), cab, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Sounds.PilotLampOff = TrainManager.CarSound.Empty; // load sounds for all cars for (int i = 0; i < train.Cars.Length; i++) { Vector3 frontaxle = new Vector3(0.0, 0.0, train.Cars[i].FrontAxle.Position); Vector3 rearaxle = new Vector3(0.0, 0.0, train.Cars[i].RearAxle.Position); train.Cars[i].Sounds.Air = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Air.wav"), center, SoundCfgParser.smallRadius); train.Cars[i].Sounds.AirHigh = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "AirHigh.wav"), center, SoundCfgParser.smallRadius); train.Cars[i].Sounds.AirZero = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "AirZero.wav"), center, SoundCfgParser.smallRadius); if (train.Cars[i].CarBrake.brakeType == BrakeType.Main) { train.Cars[i].Sounds.CpEnd = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpEnd.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.CpLoop = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpLoop.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.CpStart = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpStart.wav"), center, SoundCfgParser.mediumRadius); } train.Cars[i].Sounds.BreakerResume = TrainManager.CarSound.Empty; train.Cars[i].Sounds.BreakerResumeOrInterrupt = TrainManager.CarSound.Empty; train.Cars[i].Sounds.BreakerResumed = false; train.Cars[i].Doors[0].CloseSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorClsL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Doors[1].CloseSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorClsR.wav"), right, SoundCfgParser.smallRadius); if (train.Cars[i].Doors[0].CloseSound.Buffer == null) { train.Cars[i].Doors[0].CloseSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorCls.wav"), left, SoundCfgParser.smallRadius); } if (train.Cars[i].Doors[1].CloseSound.Buffer == null) { train.Cars[i].Doors[1].CloseSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorCls.wav"), right, SoundCfgParser.smallRadius); } train.Cars[i].Doors[0].OpenSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpnL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Doors[1].OpenSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpnR.wav"), right, SoundCfgParser.smallRadius); if (train.Cars[i].Doors[0].OpenSound.Buffer == null) { train.Cars[i].Doors[0].OpenSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpn.wav"), left, SoundCfgParser.smallRadius); } if (train.Cars[i].Doors[1].OpenSound.Buffer == null) { train.Cars[i].Doors[1].OpenSound = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpn.wav"), right, SoundCfgParser.smallRadius); } train.Cars[i].Sounds.EmrBrake = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "EmrBrake.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Flange = SoundCfgParser.TryLoadSoundArray(trainFolder, "Flange", ".wav", center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.FlangeVolume = new double[train.Cars[i].Sounds.Flange.Length]; train.Cars[i].Sounds.Loop = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Loop.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].FrontAxle.PointSounds = new TrainManager.CarSound[] { new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Point.wav"), frontaxle, SoundCfgParser.smallRadius) }; train.Cars[i].RearAxle.PointSounds = new TrainManager.CarSound[] { new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Point.wav"), rearaxle, SoundCfgParser.smallRadius) }; train.Cars[i].Sounds.Rub = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Rub.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Run = SoundCfgParser.TryLoadSoundArray(trainFolder, "Run", ".wav", center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.RunVolume = new double[train.Cars[i].Sounds.Run.Length]; train.Cars[i].Sounds.SpringL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "SpringL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Sounds.SpringR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "SpringR.wav"), right, SoundCfgParser.smallRadius); // motor sound if (train.Cars[i].Specs.IsMotorCar) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; train.Cars[i].Sounds.Motor.Position = center; for (int j = 0; j < train.Cars[i].Sounds.Motor.Tables.Length; j++) { for (int k = 0; k < train.Cars[i].Sounds.Motor.Tables[j].Entries.Length; k++) { int idx = train.Cars[i].Sounds.Motor.Tables[j].Entries[k].SoundIndex; if (idx >= 0) { TrainManager.CarSound snd = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Motor" + idx.ToString(Culture) + ".wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Motor.Tables[j].Entries[k].Buffer = snd.Buffer; } } } } } }