From f3343d11dd396bbb0b1a675331aeb2b3526b0efe Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sun, 5 Feb 2023 22:24:59 +0000 Subject: [PATCH 1/2] New: Add XML sound parser --- source/OpenBVE/Audio/Sounds.cs | 4 +- source/OpenBVE/System/Host.cs | 18 ++ source/OpenBveApi/Sounds/Sounds.SoundType.cs | 2 + source/OpenBveApi/System/Hosts.cs | 14 ++ .../CsvRwRouteParser.ApplyRouteData.cs | 24 +-- .../Namespaces/Track/Track.Commands.cs | 4 +- .../Route.CsvRw/Namespaces/Track/Track.cs | 18 ++ .../Structures/Miscellaneous/Sound.cs | 188 +++++++++++++++--- .../Route.Mechanik/MechanikRouteParser.cs | 3 +- source/RouteManager2/Events/Sound.cs | 51 +++-- source/SoundManager/Sounds.SoundBuffer.cs | 30 ++- source/SoundManager/Sounds.cs | 26 ++- .../SafetySystems/TrainSafetySystems.cs | 3 + 13 files changed, 310 insertions(+), 75 deletions(-) diff --git a/source/OpenBVE/Audio/Sounds.cs b/source/OpenBVE/Audio/Sounds.cs index f50eae9bf4..088a82ee72 100644 --- a/source/OpenBVE/Audio/Sounds.cs +++ b/source/OpenBVE/Audio/Sounds.cs @@ -1,7 +1,5 @@ -using System.IO; -using System.Linq; +using System.Linq; using OpenBveApi.Sounds; -using OpenBveApi.Trains; using OpenTK.Audio.OpenAL; using SoundManager; using TrainManager.Trains; diff --git a/source/OpenBVE/System/Host.cs b/source/OpenBVE/System/Host.cs index 20c6cb8eab..cefd861ef0 100644 --- a/source/OpenBVE/System/Host.cs +++ b/source/OpenBVE/System/Host.cs @@ -271,6 +271,24 @@ public override bool RegisterSound(string path, double radius, out SoundHandle h return false; } + /// Registers a sound and returns a handle to the sound. + /// The path to the file or folder that contains the sound. + /// /// The sound radius + /// The trailing silence at the end of the sound + /// Receives a handle to the sound. + /// Whether loading the sound was successful. + public override bool RegisterSound(string path, double radius, double trailingSilence, out SoundHandle handle) + { + if (File.Exists(path) || Directory.Exists(path)) + { + handle = Program.Sounds.RegisterBuffer(path, radius, trailingSilence); + return true; + } + ReportProblem(ProblemType.PathNotFound, path); + handle = null; + return false; + } + /// Registers a sound and returns a handle to the sound. /// The sound data. /// Receives a handle to the sound. diff --git a/source/OpenBveApi/Sounds/Sounds.SoundType.cs b/source/OpenBveApi/Sounds/Sounds.SoundType.cs index 7d5fade673..4af84c900f 100644 --- a/source/OpenBveApi/Sounds/Sounds.SoundType.cs +++ b/source/OpenBveApi/Sounds/Sounds.SoundType.cs @@ -27,6 +27,8 @@ public enum SoundType StaticObject = 8, /// The sound source is emitted by an animated object, and may move AnimatedObject = 9, + /// The sound is train based, but player triggered in the driver car + TrainPlayerTrigger = 10, /// The sound source is undefined Undefined = -1 } diff --git a/source/OpenBveApi/System/Hosts.cs b/source/OpenBveApi/System/Hosts.cs index 5fa324bc32..275a0a2562 100644 --- a/source/OpenBveApi/System/Hosts.cs +++ b/source/OpenBveApi/System/Hosts.cs @@ -14,6 +14,7 @@ using OpenBveApi.Trains; using OpenBveApi.World; using SoundHandle = OpenBveApi.Sounds.SoundHandle; +// ReSharper disable RedundantNameQualifier - Needed as otherwise it actually breaks :/ namespace OpenBveApi.Hosts { @@ -95,6 +96,7 @@ public HostPlatform Platform { try { + // ReSharper disable once UnusedVariable var version = GetWineVersion(); cachedPlatform = HostPlatform.WINE; return cachedPlatform; @@ -277,6 +279,18 @@ public virtual bool RegisterSound(string path, double radius, out SoundHandle ha handle = null; return false; } + + /// Registers a sound and returns a handle to the sound. + /// The path to the file or folder that contains the sound. + /// The sound radius + /// The trailing silence to be played upon repetition of the sound + /// Receives a handle to the sound. + /// Whether loading the sound was successful. + public virtual bool RegisterSound(string path, double radius, double trailingSilence, out SoundHandle handle) + { + handle = null; + return false; + } /// Registers a sound and returns a handle to the sound. /// The sound data. diff --git a/source/Plugins/Route.CsvRw/CsvRwRouteParser.ApplyRouteData.cs b/source/Plugins/Route.CsvRw/CsvRwRouteParser.ApplyRouteData.cs index a4c569e836..c582829902 100644 --- a/source/Plugins/Route.CsvRw/CsvRwRouteParser.ApplyRouteData.cs +++ b/source/Plugins/Route.CsvRw/CsvRwRouteParser.ApplyRouteData.cs @@ -486,27 +486,7 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl { for (int j = 0; j < Data.Blocks[i].SoundEvents.Length; j++) { - if ((int)Data.Blocks[i].SoundEvents[j].Type > 1 && (int)Data.Blocks[i].SoundEvents[j].Type < 6 ) - { - int m = CurrentRoute.Tracks[0].Elements[n].Events.Length; - Array.Resize(ref CurrentRoute.Tracks[0].Elements[n].Events, m + 1); - double d = Data.Blocks[i].SoundEvents[j].TrackPosition - StartingDistance; - switch (Data.Blocks[i].SoundEvents[j].Type) - { - case SoundType.TrainStatic: - CurrentRoute.Tracks[0].Elements[n].Events[m] = new SoundEvent(Plugin.CurrentHost, d, Data.Blocks[i].SoundEvents[j].SoundBuffer, true, true, false, Vector3.Zero); - break; - case SoundType.TrainAllCarStatic: - CurrentRoute.Tracks[0].Elements[n].Events[m] = new SoundEvent(Plugin.CurrentHost, d, Data.Blocks[i].SoundEvents[j].SoundBuffer, true, true, true, false, Vector3.Zero); - break; - case SoundType.TrainDynamic: - CurrentRoute.Tracks[0].Elements[n].Events[m] = new SoundEvent(Plugin.CurrentHost, d, Data.Blocks[i].SoundEvents[j].SoundBuffer, false, false, false, true, Vector3.Zero, Data.Blocks[i].SoundEvents[j].Speed); - break; - case SoundType.TrainAllCarDynamic: - CurrentRoute.Tracks[0].Elements[n].Events[m] = new SoundEvent(Plugin.CurrentHost, d, Data.Blocks[i].SoundEvents[j].SoundBuffer, false, true, false, true, Vector3.Zero, Data.Blocks[i].SoundEvents[j].Speed); - break; - } - } + Data.Blocks[i].SoundEvents[j].CreateEvent(CurrentRoute, n, StartingDistance); } } // turn @@ -763,7 +743,7 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl { for (int k = 0; k < Data.Blocks[i].SoundEvents.Length; k++) { - Data.Blocks[i].SoundEvents[k].Create(pos, StartingDistance, Direction, planar, updown); + Data.Blocks[i].SoundEvents[k].CreateAmbient(pos, StartingDistance, Direction, planar, updown); } } // forms diff --git a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.Commands.cs b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.Commands.cs index 2b8ccb4709..7cc78c8a21 100644 --- a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.Commands.cs +++ b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.Commands.cs @@ -138,6 +138,8 @@ internal enum TrackCommand /// Starts a repeating object cycle PatternObj, /// Ends a repeating object cycle - PatternEnd + PatternEnd, + /// Plays a sound + Sound } } diff --git a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs index 5620b42156..303cc83ceb 100644 --- a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs +++ b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs @@ -2835,6 +2835,24 @@ private void ParseTrackCommand(TrackCommand Command, string[] Arguments, string } } break; + case TrackCommand.Sound: + // XML Sound- All properties to be loaded from the XML + if (PreviewOnly) + { + break; + } + string fileName = Path.CombineFile(Arguments[0], SoundPath); + if (!System.IO.File.Exists(fileName)) + { + Plugin.CurrentHost.AddMessage(MessageType.Error, false, "SoundFile " + Arguments[0] + " was not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File); + } + else + { + int n = Data.Blocks[BlockIndex].SoundEvents.Length; + Array.Resize(ref Data.Blocks[BlockIndex].SoundEvents, n + 1); + Data.Blocks[BlockIndex].SoundEvents[n] = new Sound(Data.TrackPosition, fileName); + } + break; case TrackCommand.PreTrain: { if (!PreviewOnly) diff --git a/source/Plugins/Route.CsvRw/Structures/Miscellaneous/Sound.cs b/source/Plugins/Route.CsvRw/Structures/Miscellaneous/Sound.cs index 3771faf918..a247a5ae8c 100644 --- a/source/Plugins/Route.CsvRw/Structures/Miscellaneous/Sound.cs +++ b/source/Plugins/Route.CsvRw/Structures/Miscellaneous/Sound.cs @@ -1,6 +1,11 @@ using System; +using System.Linq; +using System.Xml; +using OpenBveApi.Interface; using OpenBveApi.Math; using OpenBveApi.Sounds; +using RouteManager2; +using RouteManager2.Events; namespace CsvRwRouteParser { @@ -13,7 +18,7 @@ internal class Sound /// The type of sound internal readonly SoundType Type; /// The relative sound position to the track position - internal readonly Vector2 Position; + internal readonly Vector3 Position; /// The radius of the sound internal readonly double Radius; /// If a dynamic sound, the train speed at which the sound will be played at original speed @@ -24,13 +29,10 @@ internal class Sound internal readonly double ForwardTolerance; /// The backwards tolerance for triggering the sound internal readonly double BackwardTolerance; - + internal Sound(double trackPosition, string fileName, double speed, Vector2 position = new Vector2(), double forwardTolerance = 0, double backwardTolerance = 0, bool allCars = false) { - //TODO: - //This is always set to a constant 15.0 on loading a sound, and never touched again - //I presume Michelle intended to have sounds with different radii available - //This would require a custom or extended command which allowed the radius value to be set + // Radius of 15.0m at full volume as per BVE2 / BVE4 Radius = 15.0; if (string.IsNullOrEmpty(fileName)) { @@ -56,36 +58,172 @@ internal class Sound TrackPosition = trackPosition; Speed = speed; - Position = position; + Position = new Vector3(position.X, position.Y, 0); ForwardTolerance = forwardTolerance; BackwardTolerance = backwardTolerance; } - internal void Create(Vector3 pos, double StartingDistance, Vector2 Direction, double planar, double updown) + internal Sound(double trackPosition, string xmlFile) { - if (Type == SoundType.Ambient) + double trailingSilence = 0; + TrackPosition = trackPosition; + bool looped = false; + string fn = string.Empty; + XmlDocument currentXML = new XmlDocument(); + //Load the object's XML file + currentXML.Load(xmlFile); + string Path = System.IO.Path.GetDirectoryName(xmlFile); + //Check for null + if (currentXML.DocumentElement != null) { - if (SoundBuffer != null || IsMicSound) + XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/WorldSound"); + if (DocumentNodes != null) { - double d = TrackPosition - StartingDistance; - double dx = Position.X; - double dy = Position.Y; - double wa = Math.Atan2(Direction.Y, Direction.X) - planar; - Vector3 w = new Vector3(Math.Cos(wa), Math.Tan(updown), Math.Sin(wa)); - w.Normalize(); - Vector3 s = new Vector3(Direction.Y, 0.0, -Direction.X); - Vector3 u = Vector3.Cross(w, s); - Vector3 wpos = pos + new Vector3(s.X * dx + u.X * dy + w.X * d, s.Y * dx + u.Y * dy + w.Y * d, s.Z * dx + u.Z * dy + w.Z * d); - if (IsMicSound) + foreach (XmlNode n in DocumentNodes) { - Plugin.CurrentHost.PlayMicSound(wpos, BackwardTolerance, ForwardTolerance); - } - else - { - Plugin.CurrentHost.PlaySound(SoundBuffer, 1.0, 1.0, wpos, null, true); + if (n.ChildNodes.OfType().Any()) + { + foreach (XmlNode c in n.ChildNodes) + { + switch (c.Name.ToLowerInvariant()) + { + case "filename": + fn = OpenBveApi.Path.CombineFile(Path, c.InnerText); + if (!System.IO.File.Exists(fn)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound " + c.InnerText + " does not exist in XML sound " + xmlFile); + return; + } + break; + case "radius": + if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Radius)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound radius was invalid in XML sound " + xmlFile); + } + break; + case "position": + string[] splitString = c.InnerText.Split(','); + if (!NumberFormats.TryParseDoubleVb6(splitString[0], out Position.X)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound Position X was invalid in XML sound " + xmlFile); + } + + if (!NumberFormats.TryParseDoubleVb6(splitString[1], out Position.Y)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound Position Y was invalid in XML sound " + xmlFile); + } + + if (!NumberFormats.TryParseDoubleVb6(splitString[2], out Position.Z)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound Position Z was invalid in XML sound " + xmlFile); + } + + break; + case "looped": + if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true") + { + looped = true; + } + else + { + looped = false; + } + + break; + case "trainspeed": + if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Speed)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Sound speed was invalid in XML sound " + xmlFile); + } + break; + case "repetitioninterval": + if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out trailingSilence)) + { + Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Repetition interval was invalid in XML sound " + xmlFile); + } + break; + } + } + } } } } + + //Data has been collected so setup the actual sound + Plugin.CurrentHost.RegisterSound(fn, Radius, out SoundBuffer); + if (looped) + { + Type = SoundType.Ambient; + } + else + { + if (Speed == 0.0) + { + Type = SoundType.TrainStatic; + } + else + { + Type = SoundType.TrainDynamic; + } + } + } + + internal void CreateAmbient(Vector3 pos, double StartingDistance, Vector2 Direction, double planar, double updown) + { + if (Type != SoundType.Ambient) + { + return; + } + + if (SoundBuffer == null && !IsMicSound) + { + return; + } + + double d = TrackPosition - StartingDistance; + double dx = Position.X; + double dy = Position.Y; + double wa = Math.Atan2(Direction.Y, Direction.X) - planar; + Vector3 w = new Vector3(Math.Cos(wa), Math.Tan(updown), Math.Sin(wa)); + w.Normalize(); + Vector3 s = new Vector3(Direction.Y, 0.0, -Direction.X); + Vector3 u = Vector3.Cross(w, s); + Vector3 wpos = pos + new Vector3(s.X * dx + u.X * dy + w.X * d, s.Y * dx + u.Y * dy + w.Y * d, s.Z * dx + u.Z * dy + w.Z * d); + if (IsMicSound) + { + Plugin.CurrentHost.PlayMicSound(wpos, BackwardTolerance, ForwardTolerance); + } + else + { + Plugin.CurrentHost.PlaySound(SoundBuffer, 1.0, 1.0, wpos, null, true); + } + } + + internal void CreateEvent(CurrentRoute CurrentRoute, int CurrentElement, double StartingDistance) + { + if (Type == SoundType.Ambient) + { + return; + } + + int m = CurrentRoute.Tracks[0].Elements[CurrentElement].Events.Length; + Array.Resize(ref CurrentRoute.Tracks[0].Elements[CurrentElement].Events, m + 1); + double d = TrackPosition - StartingDistance; + switch (Type) + { + case SoundType.TrainStatic: + CurrentRoute.Tracks[0].Elements[CurrentElement].Events[m] = new SoundEvent(Plugin.CurrentHost, d, SoundBuffer, true, Type, false, Position); + break; + case SoundType.TrainAllCarStatic: + CurrentRoute.Tracks[0].Elements[CurrentElement].Events[m] = new SoundEvent(Plugin.CurrentHost, d, SoundBuffer, true, Type, true, Position); + break; + case SoundType.TrainDynamic: + CurrentRoute.Tracks[0].Elements[CurrentElement].Events[m] = new SoundEvent(Plugin.CurrentHost, d, SoundBuffer, false, Type, false, Position, Speed); + break; + case SoundType.TrainAllCarDynamic: + CurrentRoute.Tracks[0].Elements[CurrentElement].Events[m] = new SoundEvent(Plugin.CurrentHost, d, SoundBuffer, false, Type, false, Position, Speed); + break; + } } } } diff --git a/source/Plugins/Route.Mechanik/MechanikRouteParser.cs b/source/Plugins/Route.Mechanik/MechanikRouteParser.cs index 288a83f0fb..0d16e08347 100644 --- a/source/Plugins/Route.Mechanik/MechanikRouteParser.cs +++ b/source/Plugins/Route.Mechanik/MechanikRouteParser.cs @@ -32,6 +32,7 @@ using OpenBveApi.Objects; using OpenBveApi.Routes; using OpenBveApi.Runtime; +using OpenBveApi.Sounds; using OpenBveApi.Textures; using OpenBveApi.World; using Route.Mechanik; @@ -867,7 +868,7 @@ private static void ProcessRoute(bool PreviewOnly) } int e = Plugin.CurrentRoute.Tracks[0].Elements[n].Events.Length; Array.Resize(ref Plugin.CurrentRoute.Tracks[0].Elements[n].Events, e + 1); - Plugin.CurrentRoute.Tracks[0].Elements[n].Events[e] = new RouteManager2.Events.SoundEvent(Plugin.CurrentHost, 0, AvailableSounds[currentRouteData.Blocks[i].Sounds[j].SoundIndex], true, false, currentRouteData.Blocks[i].Sounds[j].Looped, false, currentRouteData.Blocks[i].Sounds[j].Position); + Plugin.CurrentRoute.Tracks[0].Elements[n].Events[e] = new RouteManager2.Events.SoundEvent(Plugin.CurrentHost, 0, AvailableSounds[currentRouteData.Blocks[i].Sounds[j].SoundIndex], true, SoundType.TrainStatic, currentRouteData.Blocks[i].Sounds[j].Looped, currentRouteData.Blocks[i].Sounds[j].Position); } } Array.Resize(ref Plugin.CurrentRoute.Tracks[0].Elements, CurrentTrackLength); diff --git a/source/RouteManager2/Events/Sound.cs b/source/RouteManager2/Events/Sound.cs index ef90b05084..2b0f9bfb66 100644 --- a/source/RouteManager2/Events/Sound.cs +++ b/source/RouteManager2/Events/Sound.cs @@ -18,47 +18,42 @@ public class SoundEvent : GeneralEvent private readonly bool PlayerTrainOnly; /// Whether this sound should play once, or repeat if triggered again private readonly bool Once; - /// Whether the sound pitch is affected by the speed of the train - private readonly bool Dynamic; /// The 3D position of the sound within the world public Vector3 Position; /// The speed in km/h at which the sound is played at it's original pitch private readonly double Speed; - /// Whether this triggers for all cars - private readonly bool AllCars; + /// The sound type + private readonly SoundType Type; /// The /// The delta position of the sound within a track block. /// The sound buffer to play. /// Defines whether this sound is played for the player's train only, or for player and AI trains - /// Whether this triggers for all cars in a train + /// The type of sound /// Defines whether this sound repeats looped, or plays once - /// Whether this sound is dynamic (Attached to a train) /// The position of the sound relative to it's track location /// The speed in km/h at which this sound is played at it's original pitch (Set to zero to play at original pitch at all times) - public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, bool AllCars, bool Once, bool Dynamic, Vector3 Position, double Speed) : base(TrackPositionDelta) + public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, SoundType Type, bool Once, Vector3 Position, double Speed) : base(TrackPositionDelta) { this.currentHost = Host; this.DontTriggerAnymore = false; this.SoundBuffer = (SoundBuffer)SoundBuffer; this.PlayerTrainOnly = PlayerTrainOnly; this.Once = Once; - this.Dynamic = Dynamic; this.Position = Position; this.Speed = Speed; - this.AllCars = AllCars; + this.Type = Type; } /// The /// The delta position of the sound within a track block. /// The sound buffer to play. /// Defines whether this sound is played for the player's train only, or for player and AI trains - /// Whether this triggers for all cars in a train + /// The type of sound /// Defines whether this sound repeats looped, or plays once - /// Whether this sound is dynamic (Attached to a train) /// The position of the sound relative to it's track location - public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, bool AllCars, bool Once, bool Dynamic, Vector3 Position) - : this(Host, TrackPositionDelta, SoundBuffer, PlayerTrainOnly, AllCars, Once, Dynamic, Position, 0.0) + public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, SoundType Type, bool Once, Vector3 Position) + : this(Host, TrackPositionDelta, SoundBuffer, PlayerTrainOnly, Type, Once, Position, 0.0) { } @@ -67,10 +62,9 @@ public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle Sou /// The sound buffer to play. /// Defines whether this sound is played for the player's train only, or for player and AI trains /// Defines whether this sound repeats looped, or plays once - /// Whether this sound is dynamic (Attached to a train) /// The position of the sound relative to it's track location - public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, bool Once, bool Dynamic, Vector3 Position) - : this(Host, TrackPositionDelta, SoundBuffer, PlayerTrainOnly, false, Once, Dynamic, Position) + public SoundEvent(HostInterface Host, double TrackPositionDelta, SoundHandle SoundBuffer, bool PlayerTrainOnly, bool Once, Vector3 Position) + : this(Host, TrackPositionDelta, SoundBuffer, PlayerTrainOnly, SoundType.TrainCar, Once, Position) { } @@ -83,9 +77,24 @@ public override void Trigger(int direction, TrackFollower trackFollower) EventTriggerType triggerType = trackFollower.TriggerType; if (triggerType == EventTriggerType.FrontCarFrontAxle | triggerType == EventTriggerType.OtherCarFrontAxle | triggerType == EventTriggerType.OtherCarRearAxle | triggerType == EventTriggerType.RearCarRearAxle) { + if (Type == SoundType.TrainPlayerTrigger) + { + /* + * Special case sound! + * Minor abuse of the dynamic, but as the API train is passed to plugins and stuff we + * don't want to be chucking around what could easily be a mega large sound buffer + */ + if (trackFollower.Train.IsPlayerTrain) + { + dynamic train = trackFollower.Train; + train.SafetySystems.QueuedAnnouncement = SoundBuffer; + } + return; + } + if (!PlayerTrainOnly | trackFollower.Train.IsPlayerTrain) { - if (AllCars && triggerType == EventTriggerType.OtherCarRearAxle) + if ((Type == SoundType.TrainAllCarDynamic || Type == SoundType.TrainAllCarStatic) && triggerType == EventTriggerType.OtherCarRearAxle) { /* * For a multi-car announce, we only want the front axles to trigger @@ -96,10 +105,10 @@ public override void Trigger(int direction, TrackFollower trackFollower) double pitch = 1.0; double gain = 1.0; //In order to play for all cars, we need to create a clone of the buffer, as 1 buffer can only be playing in a single location - SoundBuffer buffer = this.AllCars ? SoundBuffer.Clone() : SoundBuffer; + SoundBuffer buffer = Type == SoundType.TrainAllCarDynamic || Type == SoundType.TrainAllCarStatic ? SoundBuffer.Clone() : SoundBuffer; if (buffer != null) { - if (this.Dynamic) + if (Type == SoundType.TrainDynamic || Type == SoundType.TrainAllCarDynamic) { double spd = Math.Abs(trackFollower.Train.CurrentSpeed); pitch = spd / this.Speed; @@ -111,13 +120,13 @@ public override void Trigger(int direction, TrackFollower trackFollower) } if (buffer != null) { - if (AllCars || triggerType != EventTriggerType.RearCarRearAxle) + if (Type == SoundType.TrainAllCarDynamic || Type == SoundType.TrainAllCarStatic || triggerType != EventTriggerType.RearCarRearAxle) { currentHost.PlaySound(buffer, pitch, gain, Position, trackFollower.Car, false); } } } - if (!AllCars || triggerType == EventTriggerType.RearCarRearAxle) + if (!(Type == SoundType.TrainAllCarDynamic || Type == SoundType.TrainAllCarStatic) || triggerType == EventTriggerType.RearCarRearAxle) { this.DontTriggerAnymore = this.Once; } diff --git a/source/SoundManager/Sounds.SoundBuffer.cs b/source/SoundManager/Sounds.SoundBuffer.cs index 0efb17f0f0..9b771bfab5 100644 --- a/source/SoundManager/Sounds.SoundBuffer.cs +++ b/source/SoundManager/Sounds.SoundBuffer.cs @@ -1,4 +1,5 @@ -using OpenBveApi.FunctionScripting; +using System; +using OpenBveApi.FunctionScripting; using OpenBveApi.Hosts; using OpenBveApi.Sounds; using OpenTK.Audio.OpenAL; @@ -42,6 +43,27 @@ public double Duration internal double InternalVolumeFactor; + /// Sets the amount of trailing silence to be played after this sound when looping + internal double TrailingSilence; + + /// Creates a new sound buffer + /// The host application + /// The on-disk path to the sound to load + /// The radius for this sound + /// The amount of trailing silence to play + internal SoundBuffer(HostInterface host, string path, double radius, double trailingSilence) { + Origin = new PathOrigin(path, host); + Radius = radius; + Loaded = false; + OpenAlBufferName = 0; + _duration = 0.0; + InternalVolumeFactor = 0.5; + Ignore = false; + PitchFunction = null; + VolumeFunction = null; + TrailingSilence = trailingSilence; + } + /// Creates a new sound buffer /// The host application /// The on-disk path to the sound to load @@ -141,6 +163,12 @@ public void Load() byte[] bytes = sound.GetMonoMix(); AL.GenBuffers(1, out OpenAlBufferName); ALFormat format = sound.BitsPerSample == 8 ? ALFormat.Mono8 : ALFormat.Mono16; + if (TrailingSilence != 0) + { + int sampleCount = (int)(TrailingSilence * sound.SampleRate); + int b = bytes.Length; + Array.Resize(ref bytes, b + sampleCount); // n.b. Default value of byte in array is zero, hence new duration is silent + } AL.BufferData(OpenAlBufferName, format, bytes, bytes.Length, sound.SampleRate); _duration = sound.Duration; Loaded = true; diff --git a/source/SoundManager/Sounds.cs b/source/SoundManager/Sounds.cs index c2d733d4ac..80279de09a 100644 --- a/source/SoundManager/Sounds.cs +++ b/source/SoundManager/Sounds.cs @@ -225,7 +225,7 @@ public SoundBuffer RegisterBuffer(string path, double radius) continue; } - if (((PathOrigin)Buffers[i].Origin).Path == path) + if (((PathOrigin)Buffers[i].Origin).Path == path && Buffers[i].TrailingSilence == 0.0) { return Buffers[i]; } @@ -247,6 +247,30 @@ public SoundBuffer RegisterBuffer(string path, double radius) return Buffers[BufferCount - 1]; } + /// Registers a sound buffer and returns a handle to the buffer. + /// The path to the sound. + /// The default effective radius. + /// The amount of trailing silence to play whilst looping this sound + /// The handle to the sound buffer. + public SoundBuffer RegisterBuffer(string path, double radius, double trailingSilence) + { + for (int i = 0; i < BufferCount; i++) + { + if (!(Buffers[i].Origin is PathOrigin) || Buffers[i].TrailingSilence != trailingSilence) continue; + if (((PathOrigin)Buffers[i].Origin).Path == path) + { + return Buffers[i]; + } + } + if (Buffers.Length == BufferCount) + { + Array.Resize(ref Buffers, Buffers.Length << 1); + } + Buffers[BufferCount] = new SoundBuffer(CurrentHost, path, radius, trailingSilence); + BufferCount++; + return Buffers[BufferCount - 1]; + } + /// Registers a sound buffer and returns a handle to the buffer. /// The raw sound data. /// The default effective radius. diff --git a/source/TrainManager/SafetySystems/TrainSafetySystems.cs b/source/TrainManager/SafetySystems/TrainSafetySystems.cs index f2ad2c875b..18807951a8 100644 --- a/source/TrainManager/SafetySystems/TrainSafetySystems.cs +++ b/source/TrainManager/SafetySystems/TrainSafetySystems.cs @@ -1,4 +1,5 @@ using OpenBveApi.Runtime; +using SoundManager; using TrainManager.Trains; namespace TrainManager.SafetySystems @@ -15,5 +16,7 @@ public struct TrainSafetySystems public DoorInterlockStates DoorInterlockState; /// The train headlights public LightSource Headlights; + /// An announcement queued for manual playback + public SoundBuffer QueuedAnnouncement; } } From e782677f437336190bf05d480777928b013c66fe Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 6 Feb 2023 11:09:38 +0000 Subject: [PATCH 2/2] Change: Convert sound arrays to lists, simplify accesses --- source/OpenBVE/Audio/Sounds.Update.cs | 60 +++----------- source/OpenBVE/Audio/Sounds.cs | 2 +- source/RouteViewer/Audio/Sounds.Update.cs | 60 +++----------- source/SoundManager/Sounds.CarSound.cs | 9 +-- source/SoundManager/Sounds.cs | 85 ++++++-------------- source/TrainEditor2/Audio/SoundApi.Update.cs | 30 ++----- 6 files changed, 57 insertions(+), 189 deletions(-) diff --git a/source/OpenBVE/Audio/Sounds.Update.cs b/source/OpenBVE/Audio/Sounds.Update.cs index 2193851ae5..72fece4843 100644 --- a/source/OpenBVE/Audio/Sounds.Update.cs +++ b/source/OpenBVE/Audio/Sounds.Update.cs @@ -50,7 +50,7 @@ protected override void UpdateLinearModel(double timeElapsed) * Update the sound sources * */ int actuallyPlaying = 0; - for (int i = 0; i < SourceCount; i++) { + for (int i = Sources.Count - 1; i > 0; i--) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. @@ -58,19 +58,13 @@ protected override void UpdateLinearModel(double timeElapsed) * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (GlobalMute) { /* * The sound is playing or about to be played, but @@ -84,11 +78,7 @@ protected override void UpdateLinearModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -155,11 +145,7 @@ protected override void UpdateLinearModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -199,11 +185,7 @@ protected override void UpdateLinearModel(double timeElapsed) * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else { actuallyPlaying++; } @@ -303,7 +285,7 @@ protected override void UpdateInverseModel(double timeElapsed) * and ensure that all others are stopped. * */ List toBePlayed = new List(); - for (int i = 0; i < SourceCount; i++) { + for (int i = Sources.Count - 1; i > 0; i--) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. @@ -311,19 +293,13 @@ protected override void UpdateInverseModel(double timeElapsed) * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (GlobalMute) { /* * The sound is playing or about to be played, but @@ -337,11 +313,7 @@ protected override void UpdateInverseModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -356,11 +328,7 @@ protected override void UpdateInverseModel(double timeElapsed) * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); continue; } } @@ -410,11 +378,7 @@ protected override void UpdateInverseModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* diff --git a/source/OpenBVE/Audio/Sounds.cs b/source/OpenBVE/Audio/Sounds.cs index 088a82ee72..f957f1874f 100644 --- a/source/OpenBVE/Audio/Sounds.cs +++ b/source/OpenBVE/Audio/Sounds.cs @@ -15,7 +15,7 @@ public override void StopAllSounds(object train) if (train is TrainBase) { var t = (TrainBase) train; - for (int i = 0; i < SourceCount; i++) + for (int i = 0; i < Sources.Count; i++) { if (t.Cars.Contains(Sources[i].Parent) || Sources[i].Parent == train) { diff --git a/source/RouteViewer/Audio/Sounds.Update.cs b/source/RouteViewer/Audio/Sounds.Update.cs index 81072881ef..7ad725afa0 100644 --- a/source/RouteViewer/Audio/Sounds.Update.cs +++ b/source/RouteViewer/Audio/Sounds.Update.cs @@ -49,7 +49,7 @@ protected override void UpdateLinearModel(double timeElapsed) * Update the sound sources * */ int actuallyPlaying = 0; - for (int i = 0; i < SourceCount; i++) { + for (int i = Sources.Count - 1; i > 0; i--) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. @@ -57,19 +57,13 @@ protected override void UpdateLinearModel(double timeElapsed) * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (GlobalMute) { /* * The sound is playing or about to be played, but @@ -83,11 +77,7 @@ protected override void UpdateLinearModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -147,11 +137,7 @@ protected override void UpdateLinearModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -191,11 +177,7 @@ protected override void UpdateLinearModel(double timeElapsed) * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else { actuallyPlaying++; } @@ -293,7 +275,7 @@ protected override void UpdateInverseModel(double timeElapsed) * and ensure that all others are stopped. * */ List toBePlayed = new List(); - for (int i = 0; i < SourceCount; i++) { + for (int i = Sources.Count - 1; i > 0; i--) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. @@ -301,19 +283,13 @@ protected override void UpdateInverseModel(double timeElapsed) * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (GlobalMute) { /* * The sound is playing or about to be played, but @@ -327,11 +303,7 @@ protected override void UpdateInverseModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* @@ -346,11 +318,7 @@ protected override void UpdateInverseModel(double timeElapsed) * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); continue; } } @@ -396,11 +364,7 @@ protected override void UpdateInverseModel(double timeElapsed) Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else { /* diff --git a/source/SoundManager/Sounds.CarSound.cs b/source/SoundManager/Sounds.CarSound.cs index 40300e975a..c9eb7337ee 100644 --- a/source/SoundManager/Sounds.CarSound.cs +++ b/source/SoundManager/Sounds.CarSound.cs @@ -118,13 +118,8 @@ public void Play(double pitch, double volume, AbstractCar Car, bool looped) } if (Buffer != null) { - if (SoundsBase.Sources.Length == SoundsBase.SourceCount) - { - Array.Resize(ref SoundsBase.Sources, SoundsBase.Sources.Length << 1); - } - SoundsBase.Sources[SoundsBase.SourceCount] = new SoundSource(Buffer, Buffer.Radius, pitch, volume, Position, Car, looped); - this.Source = SoundsBase.Sources[SoundsBase.SourceCount]; - SoundsBase.SourceCount++; + SoundsBase.Sources.Add(new SoundSource(Buffer, Buffer.Radius, pitch, volume, Position, Car, looped)); + this.Source = SoundsBase.Sources[SoundsBase.Sources.Count - 1]; } } diff --git a/source/SoundManager/Sounds.cs b/source/SoundManager/Sounds.cs index 80279de09a..378f6aa37e 100644 --- a/source/SoundManager/Sounds.cs +++ b/source/SoundManager/Sounds.cs @@ -24,16 +24,10 @@ public abstract partial class SoundsBase private ContextHandle OpenAlContext; /// A list of all sound buffers. - private SoundBuffer[] Buffers = new SoundBuffer[16]; - - /// The number of sound buffers. - private int BufferCount = 0; + private readonly List Buffers = new List(); /// A list of all sound sources. - protected internal static SoundSource[] Sources = new SoundSource[16]; - - /// The number of sound sources. - protected internal static int SourceCount = 0; + protected internal static List Sources = new List(); /// The gain threshold. Sounds with gains below this value are not played. protected const double GainThreshold = 0.0001; @@ -218,7 +212,7 @@ public SoundBuffer RegisterBuffer(string path, double radius) { return null; } - for (int i = 0; i < BufferCount; i++) + for (int i = 0; i < Buffers.Count; i++) { if (!(Buffers[i].Origin is PathOrigin)) { @@ -230,21 +224,16 @@ public SoundBuffer RegisterBuffer(string path, double radius) return Buffers[i]; } } - if (Buffers.Length == BufferCount) - { - Array.Resize(ref Buffers, Buffers.Length << 1); - } try { - Buffers[BufferCount] = new SoundBuffer(CurrentHost, path, radius); + Buffers.Add(new SoundBuffer(CurrentHost, path, radius)); } catch { return null; } - BufferCount++; - return Buffers[BufferCount - 1]; + return Buffers[Buffers.Count - 1]; } /// Registers a sound buffer and returns a handle to the buffer. @@ -254,7 +243,7 @@ public SoundBuffer RegisterBuffer(string path, double radius) /// The handle to the sound buffer. public SoundBuffer RegisterBuffer(string path, double radius, double trailingSilence) { - for (int i = 0; i < BufferCount; i++) + for (int i = 0; i < Buffers.Count; i++) { if (!(Buffers[i].Origin is PathOrigin) || Buffers[i].TrailingSilence != trailingSilence) continue; if (((PathOrigin)Buffers[i].Origin).Path == path) @@ -262,13 +251,8 @@ public SoundBuffer RegisterBuffer(string path, double radius, double trailingSil return Buffers[i]; } } - if (Buffers.Length == BufferCount) - { - Array.Resize(ref Buffers, Buffers.Length << 1); - } - Buffers[BufferCount] = new SoundBuffer(CurrentHost, path, radius, trailingSilence); - BufferCount++; - return Buffers[BufferCount - 1]; + Buffers.Add(new SoundBuffer(CurrentHost, path, radius, trailingSilence)); + return Buffers[Buffers.Count - 1]; } /// Registers a sound buffer and returns a handle to the buffer. @@ -277,21 +261,15 @@ public SoundBuffer RegisterBuffer(string path, double radius, double trailingSil /// The handle to the sound buffer. public SoundBuffer RegisterBuffer(Sound data, double radius) { - if (Buffers.Length == BufferCount) - { - Array.Resize(ref Buffers, Buffers.Length << 1); - } - try { - Buffers[BufferCount] = new SoundBuffer(data, radius); + Buffers.Add(new SoundBuffer(data, radius)); } catch { return null; } - BufferCount++; - return Buffers[BufferCount - 1]; + return Buffers[Buffers.Count - 1]; } /// Attempts to load a new sound buffer @@ -331,7 +309,7 @@ public void LoadBuffer(SoundBuffer buffer) /// Loads all sound buffers immediately. internal void LoadAllBuffers() { - for (int i = 0; i < BufferCount; i++) + for (int i = 0; i < Buffers.Count; i++) { LoadBuffer(Buffers[i]); } @@ -356,7 +334,7 @@ protected void UnloadBuffer(SoundBuffer buffer) /// Unloads all sound buffers immediately. internal void UnloadAllBuffers() { - for (int i = 0; i < BufferCount; i++) + for (int i = 0; i < Buffers.Count; i++) { UnloadBuffer(Buffers[i]); } @@ -397,13 +375,8 @@ private void UnloadAllMicBuffers() /// The sound source. public SoundSource PlaySound(SoundBuffer buffer, double pitch, double volume, OpenBveApi.Math.Vector3 position, bool looped) { - if (Sources.Length == SourceCount) - { - Array.Resize(ref Sources, Sources.Length << 1); - } - Sources[SourceCount] = new SoundSource(buffer, buffer.Radius, pitch, volume, position, null, looped); - SourceCount++; - return Sources[SourceCount - 1]; + Sources.Add(new SoundSource(buffer, buffer.Radius, pitch, volume, position, null, looped)); + return Sources[Sources.Count - 1]; } /// Plays a sound. @@ -419,13 +392,8 @@ public SoundSource PlaySound(SoundHandle buffer, double pitch, double volume, Op if (buffer is SoundBuffer) { SoundBuffer b = (SoundBuffer)buffer; - if (Sources.Length == SourceCount) - { - Array.Resize(ref Sources, Sources.Length << 1); - } - Sources[SourceCount] = new SoundSource(b, b.Radius, pitch, volume, position, parent, looped); - SourceCount++; - return Sources[SourceCount - 1]; + Sources.Add(new SoundSource(b, b.Radius, pitch, volume, position, parent, looped)); + return Sources[Sources.Count - 1]; } throw new NotSupportedException(); } @@ -442,13 +410,8 @@ public SoundSource PlaySound(SoundHandle buffer, double pitch, double volume, Op if (buffer is SoundBuffer) { SoundBuffer b = (SoundBuffer)buffer; - if (Sources.Length == SourceCount) - { - Array.Resize(ref Sources, Sources.Length << 1); - } - Sources[SourceCount] = new SoundSource(b, b.Radius, pitch, volume, position, null, looped); - SourceCount++; - return Sources[SourceCount - 1]; + Sources.Add(new SoundSource(b, b.Radius, pitch, volume, position, null, looped)); + return Sources[Sources.Count - 1]; } throw new NotSupportedException(); } @@ -486,7 +449,7 @@ public void StopSound(SoundSource source) /// Stops all sounds. public void StopAllSounds() { - for (int i = 0; i < SourceCount; i++) + for (int i = 0; i < Sources.Count; i++) { if (Sources[i] == null) { @@ -505,7 +468,7 @@ public void StopAllSounds() /// The train. public virtual void StopAllSounds(object train) { - for (int i = 0; i < SourceCount; i++) + for (int i = 0; i < Sources.Count; i++) { if (Sources[i] == null) { @@ -563,7 +526,7 @@ protected bool IsStopped(SoundSource source) /// The number of registered sound buffers. public int GetNumberOfRegisteredBuffers() { - return BufferCount; + return Buffers.Count; } /// Gets the number of loaded sound buffers. @@ -571,7 +534,7 @@ public int GetNumberOfRegisteredBuffers() public int GetNumberOfLoadedBuffers() { int count = 0; - for (int i = 0; i < BufferCount; i++) + for (int i = 0; i < Buffers.Count; i++) { if (Buffers[i].Loaded) { @@ -585,7 +548,7 @@ public int GetNumberOfLoadedBuffers() /// The number of registered sound sources. public int GetNumberOfRegisteredSources() { - return SourceCount; + return Sources.Count; } /// Gets the number of playing sound sources. @@ -593,7 +556,7 @@ public int GetNumberOfRegisteredSources() public int GetNumberOfPlayingSources() { int count = 0; - for (int i = 0; i < SourceCount; i++) + for (int i = 0; i < Sources.Count; i++) { if (Sources[i] == null) { diff --git a/source/TrainEditor2/Audio/SoundApi.Update.cs b/source/TrainEditor2/Audio/SoundApi.Update.cs index 577f87de59..c6380012e9 100644 --- a/source/TrainEditor2/Audio/SoundApi.Update.cs +++ b/source/TrainEditor2/Audio/SoundApi.Update.cs @@ -34,7 +34,7 @@ protected override void UpdateInverseModel(double timeElapsed) * and ensure that all others are stopped. * */ List toBePlayed = new List(); - for (int i = 0; i < SourceCount; i++) + for (int i = Sources.Count - 1; i > 0; i--) { if (Sources[i].State == SoundSourceState.StopPending) { @@ -44,11 +44,7 @@ protected override void UpdateInverseModel(double timeElapsed) * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (Sources[i].State == SoundSourceState.Stopped) { @@ -56,9 +52,7 @@ protected override void UpdateInverseModel(double timeElapsed) * The sound was already stopped. Remove it from * the list of sound sources. * */ - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } else if (GlobalMute) { @@ -76,11 +70,7 @@ protected override void UpdateInverseModel(double timeElapsed) } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else @@ -99,11 +89,7 @@ protected override void UpdateInverseModel(double timeElapsed) * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); continue; } } @@ -140,11 +126,7 @@ protected override void UpdateInverseModel(double timeElapsed) } if (!Sources[i].Looped) { - Sources[i].State = SoundSourceState.Stopped; - Sources[i].OpenAlSourceName = 0; - Sources[i] = Sources[SourceCount - 1]; - SourceCount--; - i--; + Sources.RemoveAt(i); } } else