Prevent too many instances of a single sound starting at once in an absolute location and attenuate volume of new sounds based on number active sounds already playing.
This commit is contained in:
committed by
Chris Forbes
parent
208a3a47fe
commit
ce806fdbe6
@@ -72,14 +72,14 @@ namespace OpenRA
|
|||||||
|
|
||||||
static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier)
|
static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier)
|
||||||
{
|
{
|
||||||
if (player != null && player != player.World.LocalPlayer)
|
if (String.IsNullOrEmpty(name))
|
||||||
return null;
|
return null;
|
||||||
if (name == "" || name == null)
|
if (player != null && player != player.World.LocalPlayer)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return soundEngine.Play2D(sounds[name],
|
return soundEngine.Play2D(sounds[name],
|
||||||
false, headRelative, pos.ToFloat2(),
|
false, headRelative, pos.ToFloat2(),
|
||||||
InternalSoundVolume * volumeModifier);
|
InternalSoundVolume * volumeModifier, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ISound Play(string name) { return Play(null, name, true, PPos.Zero, 1); }
|
public static ISound Play(string name) { return Play(null, name, true, PPos.Zero, 1); }
|
||||||
@@ -92,7 +92,7 @@ namespace OpenRA
|
|||||||
public static void PlayVideo(byte[] raw)
|
public static void PlayVideo(byte[] raw)
|
||||||
{
|
{
|
||||||
rawSource = LoadSoundRaw(raw);
|
rawSource = LoadSoundRaw(raw);
|
||||||
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume);
|
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PlayVideo()
|
public static void PlayVideo()
|
||||||
@@ -149,7 +149,7 @@ namespace OpenRA
|
|||||||
var sound = sounds[m.Filename];
|
var sound = sounds[m.Filename];
|
||||||
if (sound == null) return;
|
if (sound == null) return;
|
||||||
|
|
||||||
music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume);
|
music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume, false);
|
||||||
currentMusic = m;
|
currentMusic = m;
|
||||||
MusicPlaying = true;
|
MusicPlaying = true;
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ namespace OpenRA
|
|||||||
interface ISoundEngine
|
interface ISoundEngine
|
||||||
{
|
{
|
||||||
ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate);
|
ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate);
|
||||||
ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume);
|
ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume);
|
||||||
float Volume { get; set; }
|
float Volume { get; set; }
|
||||||
void PauseSound(ISound sound, bool paused);
|
void PauseSound(ISound sound, bool paused);
|
||||||
void StopSound(ISound sound);
|
void StopSound(ISound sound);
|
||||||
@@ -335,8 +335,17 @@ namespace OpenRA
|
|||||||
|
|
||||||
class OpenAlSoundEngine : ISoundEngine
|
class OpenAlSoundEngine : ISoundEngine
|
||||||
{
|
{
|
||||||
|
class PoolSlot
|
||||||
|
{
|
||||||
|
public bool isActive;
|
||||||
|
public int frameStarted;
|
||||||
|
public float2 pos;
|
||||||
|
public bool isRelative;
|
||||||
|
public ISoundSource sound;
|
||||||
|
}
|
||||||
|
|
||||||
float volume = 1f;
|
float volume = 1f;
|
||||||
Dictionary<int, bool> sourcePool = new Dictionary<int, bool>();
|
Dictionary<int, PoolSlot> sourcePool = new Dictionary<int, PoolSlot>();
|
||||||
const int POOL_SIZE = 32;
|
const int POOL_SIZE = 32;
|
||||||
|
|
||||||
public OpenAlSoundEngine()
|
public OpenAlSoundEngine()
|
||||||
@@ -360,7 +369,7 @@ namespace OpenRA
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sourcePool.Add(source, false);
|
sourcePool.Add(source, new PoolSlot() { isActive = false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,9 +377,9 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
foreach (var kvp in sourcePool)
|
foreach (var kvp in sourcePool)
|
||||||
{
|
{
|
||||||
if (!kvp.Value)
|
if (!kvp.Value.isActive)
|
||||||
{
|
{
|
||||||
sourcePool[kvp.Key] = true;
|
sourcePool[kvp.Key].isActive = true;
|
||||||
return kvp.Key;
|
return kvp.Key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,9 +397,9 @@ namespace OpenRA
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
foreach (int i in freeSources)
|
foreach (int i in freeSources)
|
||||||
sourcePool[i] = false;
|
sourcePool[i].isActive = false;
|
||||||
|
|
||||||
sourcePool[freeSources[0]] = true;
|
sourcePool[freeSources[0]].isActive = true;
|
||||||
|
|
||||||
return freeSources[0];
|
return freeSources[0];
|
||||||
}
|
}
|
||||||
@@ -400,15 +409,62 @@ namespace OpenRA
|
|||||||
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
|
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume)
|
const int maxInstancesPerFrame = 3;
|
||||||
|
const int groupDistance = 64;
|
||||||
|
const int groupDistanceSqr = groupDistance * groupDistance;
|
||||||
|
|
||||||
|
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume)
|
||||||
{
|
{
|
||||||
if (sound == null)
|
if (sound == null)
|
||||||
{
|
{
|
||||||
Log.Write("debug", "Attempt to Play2D a null `ISoundSource`");
|
Log.Write("debug", "Attempt to Play2D a null `ISoundSource`");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var world = Game.orderManager.world;
|
||||||
|
int currFrame = world != null ? world.FrameNumber : 0;
|
||||||
|
float atten = 1f;
|
||||||
|
|
||||||
|
// Check if max # of instances-per-location reached:
|
||||||
|
if (attenuateVolume)
|
||||||
|
{
|
||||||
|
int instances = 0, activeCount = 0;
|
||||||
|
foreach (var s in sourcePool.Values)
|
||||||
|
{
|
||||||
|
if (!s.isActive)
|
||||||
|
continue;
|
||||||
|
if (s.isRelative != relative)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
++activeCount;
|
||||||
|
if (s.sound != sound)
|
||||||
|
continue;
|
||||||
|
if (currFrame - s.frameStarted >= 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Too far away to count?
|
||||||
|
var lensqr = (s.pos - pos).LengthSquared;
|
||||||
|
if (lensqr >= groupDistanceSqr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If we are starting too many instances of the same sound within a short time then stop this one:
|
||||||
|
if (++instances == maxInstancesPerFrame)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attenuate a little bit based on number of active sounds:
|
||||||
|
atten = 0.66f * ((POOL_SIZE - activeCount * 0.5f) / POOL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
int source = GetSourceFromPool();
|
int source = GetSourceFromPool();
|
||||||
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume);
|
if (source == -1) return null;
|
||||||
|
|
||||||
|
var slot = sourcePool[source];
|
||||||
|
slot.pos = pos;
|
||||||
|
slot.frameStarted = currFrame;
|
||||||
|
slot.sound = sound;
|
||||||
|
slot.isRelative = relative;
|
||||||
|
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume * atten);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Volume
|
public float Volume
|
||||||
@@ -521,15 +577,14 @@ namespace OpenRA
|
|||||||
if (source == -1) return;
|
if (source == -1) return;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
Al.alSourcef(source, Al.AL_PITCH, 1f);
|
Al.alSourcef(source, Al.AL_PITCH, 1f);
|
||||||
Al.alSourcef(source, Al.AL_GAIN, 1f);
|
Volume = volume;
|
||||||
Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f);
|
Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f);
|
||||||
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
|
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
|
||||||
Al.alSourcei(source, Al.AL_BUFFER, buffer);
|
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_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE);
|
||||||
Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0);
|
Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0);
|
||||||
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200);
|
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 160);
|
||||||
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500);
|
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 3200 / Game.viewport.Zoom);
|
||||||
Volume = volume;
|
|
||||||
Al.alSourcePlay(source);
|
Al.alSourcePlay(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +626,7 @@ namespace OpenRA
|
|||||||
return new NullSoundSource();
|
return new NullSoundSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume)
|
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume)
|
||||||
{
|
{
|
||||||
return new NullSound();
|
return new NullSound();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user