1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using OpenBveApi.Math;
5 using OpenBveApi.Trains;
6 using SoundManager;
7 using TrainEditor2.Models.Sounds;
8 using TrainManager.Car;
9 using TrainManager.Motor;
10 
11 namespace TrainEditor2.Simulation.TrainManager
12 {
13 	public static partial class TrainManager
14 	{
15 		/// <summary>The base class containing the properties of a train car</summary>
16 		internal class Car : AbstractCar
17 		{
18 			private readonly Train baseTrain;
19 			internal CarPhysics Specs;
20 			internal CarSounds Sounds;
21 
Car(Train baseTrain)22 			internal Car(Train baseTrain)
23 			{
24 				this.baseTrain = baseTrain;
25 				this.Specs = new CarPhysics();
26 				this.Sounds = new CarSounds();
27 				InitializeCarSounds();
28 			}
29 
30 			/// <summary>Initializes a train with the default (empty) set of car sounds</summary>
InitializeCarSounds()31 			internal void InitializeCarSounds()
32 			{
33 				Sounds.Run = new Dictionary<int, CarSound>();
34 				Sounds.Flange = new Dictionary<int, CarSound>();
35 			}
36 
UpdateRunSounds(double TimeElapsed, int RunIndex)37 			internal void UpdateRunSounds(double TimeElapsed, int RunIndex)
38 			{
39 				if (Sounds.Run == null || Sounds.Run.Count == 0)
40 				{
41 					return;
42 				}
43 
44 				const double factor = 0.04; // 90 km/h -> m/s -> 1/x
45 				double speed = Math.Abs(CurrentSpeed);
46 				double pitch = speed * factor;
47 				double baseGain = speed < 2.77777777777778 ? 0.36 * speed : 1.0;
48 
49 				for (int i = 0; i < Sounds.Run.Count; i++)
50 				{
51 					int key = Sounds.Run.ElementAt(i).Key;
52 					if (key == RunIndex)
53 					{
54 						Sounds.Run[key].TargetVolume += 3.0 * TimeElapsed;
55 
56 						if (Sounds.Run[key].TargetVolume > 1.0)
57 						{
58 							Sounds.Run[key].TargetVolume = 1.0;
59 						}
60 					}
61 					else
62 					{
63 						Sounds.Run[key].TargetVolume -= 3.0 * TimeElapsed;
64 
65 						if (Sounds.Run[key].TargetVolume < 0.0)
66 						{
67 							Sounds.Run[key].TargetVolume = 0.0;
68 						}
69 					}
70 
71 					double gain = baseGain * Sounds.Run[key].TargetVolume;
72 
73 					if (Sounds.Run[key].IsPlaying)
74 					{
75 						if (pitch > 0.01 & gain > 0.001)
76 						{
77 							Sounds.Run[key].Source.Pitch = pitch;
78 							Sounds.Run[key].Source.Volume = gain;
79 						}
80 						else
81 						{
82 							Sounds.Run[key].Stop();
83 						}
84 					}
85 					else if (pitch > 0.02 & gain > 0.01)
86 					{
87 						Sounds.Run[key].Play(pitch, gain, this, true);
88 					}
89 				}
90 			}
91 
UpdateMotorSounds(bool isPlayTrack1, bool isPlayTrack2)92 			internal void UpdateMotorSounds(bool isPlayTrack1, bool isPlayTrack2)
93 			{
94 				Vector3 pos = Sounds.Motor.Position;
95 				double speed = Math.Abs(Specs.PerceivedSpeed);
96 				int idx = (int)Math.Round(speed * Sounds.Motor.SpeedConversionFactor);
97 				int odir = Sounds.Motor.CurrentAccelerationDirection;
98 				int ndir = Math.Sign(Specs.Acceleration);
99 
100 				for (int h = 0; h < 2; h++)
101 				{
102 					int j = h == 0 ? BVEMotorSound.MotorP1 : BVEMotorSound.MotorP2;
103 					int k = h == 0 ? BVEMotorSound.MotorB1 : BVEMotorSound.MotorB2;
104 
105 					if (odir > 0 & ndir <= 0)
106 					{
107 						if (j < Sounds.Motor.Tables.Length)
108 						{
109 							Program.SoundApi.StopSound(Sounds.Motor.Tables[j].Source);
110 							Sounds.Motor.Tables[j].Source = null;
111 							Sounds.Motor.Tables[j].Buffer = null;
112 						}
113 					}
114 					else if (odir < 0 & ndir >= 0)
115 					{
116 						if (k < Sounds.Motor.Tables.Length)
117 						{
118 							Program.SoundApi.StopSound(Sounds.Motor.Tables[k].Source);
119 							Sounds.Motor.Tables[k].Source = null;
120 							Sounds.Motor.Tables[k].Buffer = null;
121 						}
122 					}
123 
124 					if (ndir != 0)
125 					{
126 						if (ndir < 0)
127 						{
128 							j = k;
129 						}
130 
131 						if (j < Sounds.Motor.Tables.Length)
132 						{
133 							int idx2 = idx;
134 
135 							if (idx2 >= Sounds.Motor.Tables[j].Entries.Length)
136 							{
137 								idx2 = Sounds.Motor.Tables[j].Entries.Length - 1;
138 							}
139 
140 							if ((!isPlayTrack1 && h == 0) || (!isPlayTrack2 && h == 1))
141 							{
142 								idx2 = -1;
143 							}
144 
145 							if (idx2 >= 0)
146 							{
147 								SoundBuffer obuf = Sounds.Motor.Tables[j].Buffer;
148 								SoundBuffer nbuf = Sounds.Motor.Tables[j].Entries[idx2].Buffer;
149 								double pitch = Sounds.Motor.Tables[j].Entries[idx2].Pitch;
150 								double gain = Sounds.Motor.Tables[j].Entries[idx2].Gain;
151 
152 								if (obuf != nbuf)
153 								{
154 									Program.SoundApi.StopSound(Sounds.Motor.Tables[j].Source);
155 
156 									if (nbuf != null)
157 									{
158 										Sounds.Motor.Tables[j].Source = Program.SoundApi.PlaySound(nbuf, pitch, gain, pos, baseTrain, true);
159 										Sounds.Motor.Tables[j].Buffer = nbuf;
160 									}
161 									else
162 									{
163 										Sounds.Motor.Tables[j].Source = null;
164 										Sounds.Motor.Tables[j].Buffer = null;
165 									}
166 								}
167 								else if (nbuf != null)
168 								{
169 									if (Sounds.Motor.Tables[j].Source != null)
170 									{
171 										Sounds.Motor.Tables[j].Source.Pitch = pitch;
172 										Sounds.Motor.Tables[j].Source.Volume = gain;
173 									}
174 								}
175 								else
176 								{
177 									Program.SoundApi.StopSound(Sounds.Motor.Tables[j].Source);
178 									Sounds.Motor.Tables[j].Source = null;
179 									Sounds.Motor.Tables[j].Buffer = null;
180 								}
181 							}
182 							else
183 							{
184 								Program.SoundApi.StopSound(Sounds.Motor.Tables[j].Source);
185 								Sounds.Motor.Tables[j].Source = null;
186 								Sounds.Motor.Tables[j].Buffer = null;
187 							}
188 						}
189 					}
190 				}
191 
192 				Sounds.Motor.CurrentAccelerationDirection = ndir;
193 			}
194 
ApplySounds()195 			internal void ApplySounds()
196 			{
197 				//Default sound positions and radii
198 				double mediumRadius = 10.0;
199 
200 				//3D center of the car
201 				Vector3 center = Vector3.Zero;
202 
203 				// run sound
204 				foreach (var element in RunSounds)
205 				{
206 					Sounds.Run[element.Key] = new CarSound(Program.SoundApi.RegisterBuffer(element.FilePath, mediumRadius), center);
207 				}
208 
209 				// motor sound
210 				Sounds.Motor.Position = center;
211 
212 				for (int i = 0; i < Sounds.Motor.Tables.Length; i++)
213 				{
214 					Sounds.Motor.Tables[i].Buffer = null;
215 					Sounds.Motor.Tables[i].Source = null;
216 
217 					for (int j = 0; j < Sounds.Motor.Tables[i].Entries.Length; j++)
218 					{
219 						MotorElement element = MotorSounds.FirstOrDefault(x => x.Key == Sounds.Motor.Tables[i].Entries[j].SoundIndex);
220 
221 						if (element != null)
222 						{
223 							Sounds.Motor.Tables[i].Entries[j].Buffer = Program.SoundApi.RegisterBuffer(element.FilePath, mediumRadius);
224 						}
225 					}
226 				}
227 			}
228 		}
229 	}
230 }
231