internal static void Update(double TimeElapsed) {
if (OpenAlContext != ContextHandle.Zero) {
// listener
double vx = World.CameraTrackFollower.WorldDirection.X * World.CameraSpeed;
double vy = World.CameraTrackFollower.WorldDirection.Y * World.CameraSpeed;
double vz = World.CameraTrackFollower.WorldDirection.Z * World.CameraSpeed;
if (World.CameraMode == World.CameraViewMode.Interior | World.CameraMode == World.CameraViewMode.InteriorLookAhead) {
ListenerVelocity[0] = 0.0f;
ListenerVelocity[1] = 0.0f;
ListenerVelocity[2] = 0.0f;
} else {
ListenerVelocity[0] = (float)vx;
ListenerVelocity[1] = (float)vy;
ListenerVelocity[2] = (float)vz;
}
ListenerOrientation[0] = (float)World.AbsoluteCameraDirection.X;
ListenerOrientation[1] = (float)World.AbsoluteCameraDirection.Y;
ListenerOrientation[2] = (float)World.AbsoluteCameraDirection.Z;
ListenerOrientation[3] = (float)-World.AbsoluteCameraUp.X;
ListenerOrientation[4] = (float)-World.AbsoluteCameraUp.Y;
ListenerOrientation[5] = (float)-World.AbsoluteCameraUp.Z;
AL.Listener(ALListener3f.Position, ListenerPosition[0], ListenerPosition[1], ListenerPosition[2]);
AL.Listener(ALListener3f.Velocity, ListenerVelocity[0], ListenerVelocity[1], ListenerVelocity[2]);
AL.Listener(ALListenerfv.Orientation, ref ListenerOrientation);
double cx = World.AbsoluteCameraPosition.X;
double cy = World.AbsoluteCameraPosition.Y;
double cz = World.AbsoluteCameraPosition.Z;
if (Mute) {
// mute
for (int i = 0; i < SoundSources.Length; i++) {
if (SoundSources[i] != null && !SoundSources[i].FinishedPlaying) {
if (!SoundSources[i].Suppressed) {
if (SoundSources[i].Looped) {
if (SoundSources[i].OpenAlSourceIndex.Valid) {
int j = SoundSources[i].OpenAlSourceIndex.Index;
AL.SourceStop(j);
AL.DeleteSources(1, ref j);
}
SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false);
SoundSources[i].Suppressed = true;
} else {
StopSound(i, false);
}
} else if (!SoundSources[i].Looped) {
StopSound(i, false);
}
}
}
} else {
// outer radius
int n = Interface.CurrentOptions.SoundNumber - 3;
if (SoundsActuallyPlaying >= n) {
OuterRadiusSpeed -= OuterRadiusDeceleration * TimeElapsed;
if (OuterRadiusSpeed < -1.0) OuterRadiusSpeed = -1.0;
} else if (SoundsQueriedPlaying < n) {
OuterRadiusSpeed += OuterRadiusAcceleration * TimeElapsed;
if (OuterRadiusSpeed > 1.0) OuterRadiusSpeed = 1.0;
} else {
OuterRadiusSpeed -= (double)Math.Sign(OuterRadiusSpeed) * OuterRadiusDeceleration * TimeElapsed;
if (OuterRadiusSpeed * OuterRadiusSpeed <= TimeElapsed * TimeElapsed) {
OuterRadiusSpeed = 0.0;
}
}
OuterRadiusFactor += OuterRadiusSpeed * TimeElapsed;
if (OuterRadiusFactor < OuterRadiusFactorMinimum) {
OuterRadiusFactor = OuterRadiusFactorMinimum;
} else if (OuterRadiusFactor > OuterRadiusFactorMaximum) {
OuterRadiusFactor = OuterRadiusFactorMaximum;
}
// sources
SoundsQueriedPlaying = 0;
SoundsActuallyPlaying = 0;
for (int i = 0; i < SoundSources.Length; i++) {
if (SoundSources[i] != null && !SoundSources[i].FinishedPlaying) {
double rx = SoundSources[i].Position.X;
double ry = SoundSources[i].Position.Y;
double rz = SoundSources[i].Position.Z;
double px, py, pz;
if (SoundSources[i].Train != null) {
int c = SoundSources[i].CarIndex;
double tx, ty, tz;
TrainManager.CreateWorldCoordinates(SoundSources[i].Train, c, rx, ry, rz, out px, out py, out pz, out tx, out ty, out tz);
px -= cx; py -= cy; pz -= cz;
double sp = SoundSources[i].Train.Specs.CurrentAverageSpeed;
if (World.CameraMode != World.CameraViewMode.Interior & World.CameraMode != World.CameraViewMode.InteriorLookAhead) {
SoundSources[i].OpenAlVelocity[0] = (float)(tx * sp);
SoundSources[i].OpenAlVelocity[1] = (float)(ty * sp);
SoundSources[i].OpenAlVelocity[2] = (float)(tz * sp);
} else {
SoundSources[i].OpenAlVelocity[0] = (float)(tx * sp - vx);
SoundSources[i].OpenAlVelocity[1] = (float)(ty * sp - vy);
SoundSources[i].OpenAlVelocity[2] = (float)(tz * sp - vz);
}
} else {
px = rx - cx; py = ry - cy; pz = rz - cz;
if (World.CameraMode != World.CameraViewMode.Interior & World.CameraMode != World.CameraViewMode.InteriorLookAhead) {
SoundSources[i].OpenAlVelocity[0] = 0.0f;
SoundSources[i].OpenAlVelocity[1] = 0.0f;
SoundSources[i].OpenAlVelocity[2] = 0.0f;
} else {
SoundSources[i].OpenAlVelocity[0] = (float)-vx;
SoundSources[i].OpenAlVelocity[1] = (float)-vy;
SoundSources[i].OpenAlVelocity[2] = (float)-vz;
}
}
// play the sound only if within the outer radius
double distanceSquared = px * px + py * py + pz * pz;
double distance = Math.Sqrt(distanceSquared);
double innerRadius = SoundSources[i].Radius;
double outerRadius = OuterRadiusFactor * innerRadius;
double outerRadiusSquared = outerRadius * outerRadius;
if (distanceSquared < outerRadiusSquared) {
// sound is in range
double gain;
double innerRadiusSquared = innerRadius * innerRadius;
const double rollOffFactor = 0.9;
if (distanceSquared < innerRadiusSquared) {
gain = 1.0 - (1.0 - rollOffFactor) * distanceSquared / innerRadiusSquared;
} else {
double value = distance / outerRadius;
gain = innerRadius * rollOffFactor * (1.0 - value * value * value) / distance;
}
SoundsQueriedPlaying++;
SoundsActuallyPlaying++;
bool startPlaying = false;
// play sound if currently suppressed
if (SoundSources[i].Suppressed) {
if (SoundSources[i].SoundBufferIndex >= 0) {
UseSoundBuffer(SoundSources[i].SoundBufferIndex);
if (SoundBuffers[SoundSources[i].SoundBufferIndex].OpenAlBufferIndex.Valid) {
int j;
AL.GetError();
AL.GenSources(1, out j);
ALError err = AL.GetError();
if (err == ALError.NoError) {
SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(j, true);
AL.Source(j, ALSourcei.Buffer, SoundBuffers[SoundSources[i].SoundBufferIndex].OpenAlBufferIndex.Index);
SoundSources[i].Suppressed = false;
startPlaying = true;
} else {
continue;
}
} else {
StopSound(i, false);
continue;
}
} else {
StopSound(i, false);
continue;
}
}
// play or stop sound
if (startPlaying || IsPlaying(i)) {
SoundSources[i].OpenAlPosition[0] = (float)px;
SoundSources[i].OpenAlPosition[1] = (float)py;
SoundSources[i].OpenAlPosition[2] = (float)pz;
if (!SoundSources[i].OpenAlSourceIndex.Valid) {
throw new InvalidOperationException("A bug in the sound manager. (9431)");
}
int j = SoundSources[i].OpenAlSourceIndex.Index;
AL.Source(j, ALSource3f.Position, SoundSources[i].OpenAlPosition[0], SoundSources[i].OpenAlPosition[1], SoundSources[i].OpenAlPosition[2]);
AL.Source(j, ALSource3f.Velocity, SoundSources[i].OpenAlVelocity[0], SoundSources[i].OpenAlVelocity[1], SoundSources[i].OpenAlVelocity[2]);
AL.Source(j, ALSourcef.Pitch, SoundSources[i].Pitch);
float g = SoundSources[i].Gain * SoundSources[i].Gain * (float)gain;
if (g > 1.0f) g = 1.0f;
AL.Source(j, ALSourcef.Gain, g);
} else {
StopSound(i, false);
continue;
}
// update position and velocity of sound
if (startPlaying) {
if (!SoundSources[i].OpenAlSourceIndex.Valid) {
throw new InvalidOperationException("A bug in the sound manager. (7625)");
}
int j = SoundSources[i].OpenAlSourceIndex.Index;
AL.Source(j, ALSourceb.Looping, SoundSources[i].Looped ? true : false);
AL.Source(j, ALSourcef.ReferenceDistance, SoundBuffers[SoundSources[i].SoundBufferIndex].Radius);
AL.SourcePlay(j);
}
} else {
// sound is not in range
if (!SoundSources[i].Suppressed) {
if (SoundSources[i].Looped) {
if (SoundSources[i].OpenAlSourceIndex.Valid) {
int j = SoundSources[i].OpenAlSourceIndex.Index;
AL.SourceStop(j);
AL.DeleteSources(1, ref j);
}
SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false);
SoundSources[i].Suppressed = true;
} else {
StopSound(i, false);
}
} else if (!SoundSources[i].Looped) {
StopSound(i, false);
}
}
}
}
}
// infrequent updates
InternalTimer += TimeElapsed;
if (InternalTimer > 1.0) {
InternalTimer = 0.0;
double Elevation = World.AbsoluteCameraPosition.Y + Game.RouteInitialElevation;
double AirTemperature = Game.GetAirTemperature(Elevation);
double AirPressure = Game.GetAirPressure(Elevation, AirTemperature);
double SpeedOfSound = Game.GetSpeedOfSound(AirPressure, AirTemperature);
AL.SpeedOfSound((float)SpeedOfSound);
}
}
}