Skip to content

Commit

Permalink
Positional sound: Limit volume when closer than 1 node
Browse files Browse the repository at this point in the history
Change OpenAL distance model from AL_INVERSE_DISTANCE to
AL_INVERSE_DISTANCE_CLAMPED to avoid excessive volume when very close
to the sound location, for example MTG doors, and MTG fire sounds which
are combined at an average position and often located in air nodes.

Because AL_REFERENCE_DISTANCE has been reduced to 1 node (the distance
under which gain is clamped), multiply volume by the same factor to keep
sound gains the same as before, since the gain is calculated as:

gain = (AL_REFERENCE_DISTANCE / distance)
  • Loading branch information
paramat committed Sep 25, 2017
1 parent d5a97e0 commit a455297
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/sound_openal.cpp
Expand Up @@ -36,6 +36,7 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
#include <AL/alc.h>
#include <AL/alext.h>
#endif
#include <cmath>
#include <vorbis/vorbisfile.h>
#include <cassert>
#include "log.h"
Expand Down Expand Up @@ -332,7 +333,7 @@ class OpenALSoundManager: public ISoundManager
return;
}

alDistanceModel(AL_INVERSE_DISTANCE);
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);

infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
<<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
Expand Down Expand Up @@ -405,7 +406,7 @@ class OpenALSoundManager: public ISoundManager
alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
volume = MYMAX(0.0, volume);
volume = std::max(0.0f, volume);
alSourcef(sound->source_id, AL_GAIN, volume);
alSourcef(sound->source_id, AL_PITCH, pitch);
alSourcePlay(sound->source_id);
Expand All @@ -427,9 +428,14 @@ class OpenALSoundManager: public ISoundManager
alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
// Use alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED) and set reference
// distance to clamp gain at <1 node distance, to avoid excessive
// volume when closer
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 10.0f);
alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
volume = MYMAX(0.0, volume);
// Multiply by 3 to compensate for reducing AL_REFERENCE_DISTANCE from
// the previous value of 30 to the new value of 10
volume = std::max(0.0f, volume * 3.0f);
alSourcef(sound->source_id, AL_GAIN, volume);
alSourcef(sound->source_id, AL_PITCH, pitch);
alSourcePlay(sound->source_id);
Expand Down

4 comments on commit a455297

@HybridDog
Copy link
Contributor

@HybridDog HybridDog commented on a455297 Sep 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the gain be calculated following way because it's a 3d wave?
gain = AL_REFERENCE_DISTANCE * AL_REFERENCE_DISTANCE / (distance * distance)

@HybridDog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like openal gets the positions and calculated the distance itself

@paramat
Copy link
Contributor Author

@paramat paramat commented on a455297 Sep 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the gain be calculated following way because it's a 3d wave?

Page 87 here https://www.openal.org/documentation/OpenAL_Programmers_Guide.pdf
There is an AL_EXPONENT_DISTANCE_CLAMPED distance model that could do inverse-square.

@HybridDog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Human volume perception is not linear (therefore the dB unit), the exponent distance model with rollback factor 2 may work better but it doesn't matter as long as media (e.g. walls and water) have no effect on the sound in minetest.

Please sign in to comment.