diff --git a/OpenRA.Game/Combat.cs b/OpenRA.Game/Combat.cs index 22e4645f03..76d9474179 100644 --- a/OpenRA.Game/Combat.cs +++ b/OpenRA.Game/Combat.cs @@ -50,7 +50,7 @@ namespace OpenRA world.AddFrameEndTask( w => w.Add(new Explosion(w, args.dest, warhead.Explosion, isWater))); - Sound.Play(GetImpactSound(warhead, isWater)); + Sound.Play(GetImpactSound(warhead, isWater), args.dest); if (warhead.SmudgeType != null) { diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 2430f0577e..caa9916b03 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -312,6 +312,7 @@ namespace OpenRA { ++RenderFrame; viewport.DrawRegions(world); + Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height)); } PerfHistory.items["render"].Tick(); diff --git a/OpenRA.Game/Sound.cs b/OpenRA.Game/Sound.cs index bcba1295c3..fdcb0043ae 100644 --- a/OpenRA.Game/Sound.cs +++ b/OpenRA.Game/Sound.cs @@ -58,14 +58,24 @@ namespace OpenRA stopped = false; } + public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); } + public static void Play(string name) + { + if (name == "" || name == null) + return; + + var sound = sounds[name]; + soundEngine.Play2D(sound, false, true, float2.Zero); + } + + public static void Play(string name, float2 pos) { if (name == "" || name == null) return; var sound = sounds[name]; - // todo: positioning - soundEngine.Play2D(sound, false); + soundEngine.Play2D(sound, false, false, pos); } public static void PlayToPlayer(Player player, string name) @@ -74,6 +84,12 @@ namespace OpenRA Play( name ); } + public static void PlayToPlayer(Player player, string name, float2 pos) + { + if (player == player.World.LocalPlayer) + Play(name, pos); + } + public static void PlayMusic(string name) { if (name == "" || name == null) @@ -83,7 +99,7 @@ namespace OpenRA soundEngine.StopSound(music); var sound = sounds[name]; - music = soundEngine.Play2D(sound, true); + music = soundEngine.Play2D(sound, true, true, float2.Zero); music.Volume = musicVolume; } @@ -160,12 +176,13 @@ namespace OpenRA interface ISoundEngine { ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate); - ISound Play2D(ISoundSource sound, bool loop); + ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos); float Volume { get; set; } void PauseSound(ISound sound, bool paused); void StopSound(ISound sound); void SetAllSoundsPaused(bool paused); void StopAllSounds(); + void SetListenerPosition(float2 position); } interface ISoundSource {} @@ -241,10 +258,10 @@ namespace OpenRA return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); } - public ISound Play2D(ISoundSource sound, bool loop) + public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos) { int source = GetSourceFromPool(); - return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop); + return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos); } public float Volume @@ -297,7 +314,15 @@ namespace OpenRA Al.alSourceStop(key); } } - + + public void SetListenerPosition(float2 position) + { + var orientation = new [] { 0f, 0f, 1f, 0f, -1f, 0f }; + + Al.alListener3f(Al.AL_POSITION, position.X, position.Y, 50); + Al.alListenerfv(Al.AL_ORIENTATION, ref orientation[0]); + Al.alListenerf(Al.AL_METERS_PER_UNIT, .01f); + } } class OpenAlSoundSource : ISoundSource @@ -324,16 +349,20 @@ namespace OpenRA public readonly int source = -1; float volume = 1f; - public OpenAlSound(int source, int buffer, bool looping) + public OpenAlSound(int source, int buffer, bool looping, bool relative, float2 pos) { if (source == -1) return; this.source = source; Al.alSourcef(source, Al.AL_PITCH, 1f); Al.alSourcef(source, Al.AL_GAIN, 1f); - Al.alSource3f(source, Al.AL_POSITION, 0f, 0f, 0f); + Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f); Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f); Al.alSourcei(source, Al.AL_BUFFER, buffer); Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE); + Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0); + Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200); + Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500); + Al.alSourcePlay(source); } diff --git a/OpenRA.Game/Traits/Activities/Leap.cs b/OpenRA.Game/Traits/Activities/Leap.cs index d869a47c2a..685705f67f 100644 --- a/OpenRA.Game/Traits/Activities/Leap.cs +++ b/OpenRA.Game/Traits/Activities/Leap.cs @@ -34,7 +34,7 @@ namespace OpenRA.Traits.Activities initialLocation = self.CenterLocation; self.traits.Get().Attacking(self); - Sound.Play("dogg5p.aud"); + Sound.Play("dogg5p.aud", self.CenterLocation); } public IActivity NextActivity { get; set; } diff --git a/OpenRA.Game/Traits/Attack/AttackBase.cs b/OpenRA.Game/Traits/Attack/AttackBase.cs index 1570571aba..a1c6f180fe 100755 --- a/OpenRA.Game/Traits/Attack/AttackBase.cs +++ b/OpenRA.Game/Traits/Attack/AttackBase.cs @@ -194,7 +194,7 @@ namespace OpenRA.Traits self.World.Add(projectile); if (!string.IsNullOrEmpty(args.weapon.Report)) - Sound.Play(args.weapon.Report + ".aud"); + Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); } }); diff --git a/OpenRA.Game/Traits/Building.cs b/OpenRA.Game/Traits/Building.cs index 2221d18567..f1d3d768bf 100644 --- a/OpenRA.Game/Traits/Building.cs +++ b/OpenRA.Game/Traits/Building.cs @@ -97,7 +97,7 @@ namespace OpenRA.Traits if (e.DamageState == DamageState.Dead) { self.World.WorldActor.traits.Get().AddEffect(10, self.CenterLocation, 1); - Sound.Play(Info.DestroyedSound); + Sound.Play(Info.DestroyedSound, self.CenterLocation); } } diff --git a/OpenRA.Game/Traits/Cloak.cs b/OpenRA.Game/Traits/Cloak.cs index 0803e511fb..9241ff16b3 100644 --- a/OpenRA.Game/Traits/Cloak.cs +++ b/OpenRA.Game/Traits/Cloak.cs @@ -71,12 +71,12 @@ namespace OpenRA.Traits void OnCloak() { - Sound.Play(self.Info.Traits.Get().CloakSound); + Sound.Play(self.Info.Traits.Get().CloakSound, self.CenterLocation); } void OnUncloak() { - Sound.Play(self.Info.Traits.Get().UncloakSound); + Sound.Play(self.Info.Traits.Get().UncloakSound, self.CenterLocation); } } } diff --git a/OpenRA.Game/Traits/Render/RenderBuilding.cs b/OpenRA.Game/Traits/Render/RenderBuilding.cs index 9d4ee880e1..9013aa4459 100644 --- a/OpenRA.Game/Traits/Render/RenderBuilding.cs +++ b/OpenRA.Game/Traits/Render/RenderBuilding.cs @@ -88,7 +88,7 @@ namespace OpenRA.Traits break; case DamageState.Half: anim.ReplaceAnim("damaged-idle"); - Sound.Play(self.Info.Traits.Get().DamagedSound); + Sound.Play(self.Info.Traits.Get().DamagedSound, self.CenterLocation); break; case DamageState.Dead: self.World.AddFrameEndTask(w => w.Add(new Explosion(w, self.CenterLocation.ToInt2(), 7, false))); diff --git a/OpenRA.Game/Traits/Render/RenderBuildingCharge.cs b/OpenRA.Game/Traits/Render/RenderBuildingCharge.cs index d347e3a3b7..38f7e8d01b 100755 --- a/OpenRA.Game/Traits/Render/RenderBuildingCharge.cs +++ b/OpenRA.Game/Traits/Render/RenderBuildingCharge.cs @@ -36,7 +36,7 @@ namespace OpenRA.Traits public void PlayCharge(Actor self) { - Sound.Play(self.Info.Traits.Get().ChargeAudio); + Sound.Play(self.Info.Traits.Get().ChargeAudio, self.CenterLocation); anim.PlayThen(GetPrefix(self) + "active", () => anim.PlayRepeating(GetPrefix(self) + "idle")); } diff --git a/OpenRA.Game/Traits/Render/RenderBuildingTurreted.cs b/OpenRA.Game/Traits/Render/RenderBuildingTurreted.cs index 02283baebd..f098ae8357 100644 --- a/OpenRA.Game/Traits/Render/RenderBuildingTurreted.cs +++ b/OpenRA.Game/Traits/Render/RenderBuildingTurreted.cs @@ -48,7 +48,7 @@ namespace OpenRA.Traits break; case DamageState.Half: anim.Play( "damaged-idle" ); - Sound.Play(self.Info.Traits.Get().DamagedSound); + Sound.Play(self.Info.Traits.Get().DamagedSound, self.CenterLocation); break; } } diff --git a/OpenRA.Game/Traits/Render/RenderBuildingWall.cs b/OpenRA.Game/Traits/Render/RenderBuildingWall.cs index 7188046913..0d069f8b57 100644 --- a/OpenRA.Game/Traits/Render/RenderBuildingWall.cs +++ b/OpenRA.Game/Traits/Render/RenderBuildingWall.cs @@ -85,13 +85,13 @@ namespace OpenRA.Traits break; case ExtendedDamageState.Half: seqName = "damaged-idle"; - Sound.Play(self.Info.Traits.Get().DamagedSound); + Sound.Play(self.Info.Traits.Get().DamagedSound, self.CenterLocation); break; case ExtendedDamageState.Quarter: if (damageStates >= 3) { seqName = "critical-idle"; - Sound.Play(self.Info.Traits.Get().DamagedSound); + Sound.Play(self.Info.Traits.Get().DamagedSound, self.CenterLocation); } break; } diff --git a/OpenRA.Game/Traits/Submarine.cs b/OpenRA.Game/Traits/Submarine.cs index b4912b51de..eb679351c7 100644 --- a/OpenRA.Game/Traits/Submarine.cs +++ b/OpenRA.Game/Traits/Submarine.cs @@ -74,12 +74,12 @@ namespace OpenRA.Traits void OnSurface() { - Sound.Play(self.Info.Traits.Get().SurfaceSound); + Sound.Play(self.Info.Traits.Get().SurfaceSound, self.CenterLocation); } void OnDive() { - Sound.Play(self.Info.Traits.Get().SubmergeSound); + Sound.Play(self.Info.Traits.Get().SubmergeSound, self.CenterLocation); } } } diff --git a/OpenRA.Mods.Aftermath/ChronoshiftDeploy.cs b/OpenRA.Mods.Aftermath/ChronoshiftDeploy.cs index 6bc4eaab95..f8c8e3aa0a 100644 --- a/OpenRA.Mods.Aftermath/ChronoshiftDeploy.cs +++ b/OpenRA.Mods.Aftermath/ChronoshiftDeploy.cs @@ -73,7 +73,8 @@ namespace OpenRA.Mods.Aftermath Game.controller.CancelInputMode(); self.CancelActivity(); self.QueueActivity(new Teleport(order.TargetLocation)); - Sound.Play("chrotnk1.aud"); + Sound.Play("chrotnk1.aud", self.CenterLocation); + Sound.Play("chrotnk1.aud", Game.CellSize * order.TargetLocation.ToFloat2()); chargeTick = 25 * self.Info.Traits.Get().ChargeTime; foreach (var a in self.World.Queries.WithTrait()) diff --git a/OpenRA.Mods.Aftermath/DemoTruck.cs b/OpenRA.Mods.Aftermath/DemoTruck.cs index 616ba7d952..b830667680 100644 --- a/OpenRA.Mods.Aftermath/DemoTruck.cs +++ b/OpenRA.Mods.Aftermath/DemoTruck.cs @@ -58,7 +58,7 @@ namespace OpenRA.Mods.Aftermath Combat.DoExplosion(self, info.PrimaryWeapon, detonateLocation, altitude); var report = self.GetPrimaryWeapon().Report; if (report != null) - Sound.Play(report + ".aud"); + Sound.Play(report + ".aud", self.CenterLocation); // Remove from world self.Health = 0; diff --git a/OpenRA.Mods.Cnc/IonCannonPower.cs b/OpenRA.Mods.Cnc/IonCannonPower.cs index ded378db30..0b4cdf2ed7 100644 --- a/OpenRA.Mods.Cnc/IonCannonPower.cs +++ b/OpenRA.Mods.Cnc/IonCannonPower.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.Cnc { Owner.World.AddFrameEndTask(w => { - Sound.Play(Info.LaunchSound); + Sound.Play(Info.LaunchSound, Game.CellSize * order.TargetLocation.ToFloat2()); w.Add(new IonCannon(self, w, order.TargetLocation)); }); diff --git a/OpenRA.Mods.RA/CarpetBomb.cs b/OpenRA.Mods.RA/CarpetBomb.cs index 468c47ebc0..7e3a42fc9b 100644 --- a/OpenRA.Mods.RA/CarpetBomb.cs +++ b/OpenRA.Mods.RA/CarpetBomb.cs @@ -70,7 +70,7 @@ namespace OpenRA.Mods.RA self.World.Add(args.weapon.Projectile.Create(args)); if (!string.IsNullOrEmpty(args.weapon.Report)) - Sound.Play(args.weapon.Report + ".aud"); + Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); } } } diff --git a/OpenRA.Mods.RA/IronCurtainPower.cs b/OpenRA.Mods.RA/IronCurtainPower.cs index e6b1a1beb7..fe105fced2 100644 --- a/OpenRA.Mods.RA/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/IronCurtainPower.cs @@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA if (curtain != null) curtain.traits.Get().PlayCustomAnim(curtain, "active"); - Sound.Play("ironcur9.aud"); + Sound.Play("ironcur9.aud", order.TargetActor.CenterLocation); order.TargetActor.traits.Get().Activate(order.TargetActor, (int)((Info as IronCurtainPowerInfo).Duration * 25 * 60)); diff --git a/OpenRA.Mods.RA/ParaDrop.cs b/OpenRA.Mods.RA/ParaDrop.cs index 7bca5b90ab..b900a8457c 100644 --- a/OpenRA.Mods.RA/ParaDrop.cs +++ b/OpenRA.Mods.RA/ParaDrop.cs @@ -73,7 +73,7 @@ namespace OpenRA.Mods.RA Util.CenterOfCell((1 / 24f * self.CenterLocation).ToInt2()), self.traits.Get().Altitude, a))); - Sound.Play("chute1.aud"); + Sound.Play("chute1.aud", self.CenterLocation); } } } diff --git a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs index 9c14a132dc..66c3e9930b 100755 --- a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs @@ -77,7 +77,7 @@ namespace OpenRA.Mods.RA.SupportPowers if (success) { - Sound.Play("chrono2.aud"); + Sound.Play("chrono2.aud", chronosphere.CenterLocation); // Trigger screen desaturate effect foreach (var a in self.World.Queries.WithTrait())