Choosing an OpenAL 1.1 Distance Model: A Practical Decision Guide
OpenAL 1.1 offers six distance attenuation models. This guide compares inverse, linear, and exponential curves (clamped and unclamped), explains the trade-offs, and shows how to validate gain curves in code.
06 Jun 2026, 17:00 UTC

The decision you're actually making
OpenAL 1.1 gives you six distance attenuation models, and the one you pick changes how every 3D source in your game or simulation fades as it moves away from the listener. The default (AL_INVERSE_DISTANCE) is physically plausible but has a trap: sources closer than their reference distance get louder, which can clip your mix. This guide compares the models, explains the trade-offs, and shows how to validate your choice with a small test program.
One model applies to the whole context — you set it once with alDistanceModel(), and it affects all active sources immediately. (Per-source override exists via an OpenAL Soft extension; see below.)
The six models compared
All models compute a gain multiplier from the source-listener distance and three per-source parameters you set with alSourcef():
AL_REFERENCE_DISTANCE— distance at which attenuation begins (gain = 1.0).AL_MAX_DISTANCE— distance at which gain hits zero (linear models only).AL_ROLLOFF_FACTOR— scales how fast the sound drops off.
| Model | Gain formula (d = distance, r = reference, k = rolloff) | Behavior | Good fit for |
|---|---|---|---|
AL_INVERSE_DISTANCE | r / (r + k·(d − r)) | Physically inspired; gain exceeds 1.0 when d < r | Realism when you control near-field gain yourself |
AL_INVERSE_DISTANCE_CLAMPED | Same, but d clamped to [r, max] | Natural falloff, gain never exceeds 1.0 | General-purpose game audio (most common choice) |
AL_LINEAR_DISTANCE | 1 − k·(d − r) / (max − r) | Straight-line fade; can exceed 1.0 near listener | Rarely used unclamped |
AL_LINEAR_DISTANCE_CLAMPED | Same, clamped to [0, 1] | Predictable fade to exactly zero at max distance | UI sounds, 2D-style fades, hard cutoff |
AL_EXPONENT_DISTANCE | (d / r)^(−k) | Stylized curve; near-field boost possible | Artistic falloff |
AL_EXPONENT_DISTANCE_CLAMPED | Same, clamped to [0, 1] | Fast initial drop, long tail | Stylized falloff without clipping risk |
Trade-offs that matter in practice
Clamped vs unclamped
The _CLAMPED variants clamp the effective distance so gain stays in [0, 1]. Unclamped models boost sources inside the reference distance — useful for a deliberate "presence" effect, but a walking-past-the-camera NPC can suddenly dominate the mix and clip. Unless you have a specific reason, start with a clamped variant.
Which curve shape
- Inverse clamped sounds natural because it approximates how sound actually propagates. It's the safe default for world audio.
- Linear clamped is the only family that reaches exactly zero at
AL_MAX_DISTANCE. That makes it ideal when you want guaranteed silence beyond a radius — and it pairs well with culling logic ("past max distance, stop the source entirely"). - Exponent clamped drops quickly at first then tails off slowly. Useful for stylized or arcade-feel audio.
Gotchas
AL_MAX_DISTANCEonly matters for linear and clamped models. Inverse and exponential curves asymptotically approach zero but never reach it, so distant sources stay technically audible (and still cost mixer CPU) unless you cull them yourself.- The same rolloff value means different things per model — it's a linear multiplier for inverse/linear but an exponent for exponential. Don't reuse tuning constants across models.
- Switching models mid-playback re-gains every active source instantly, which can produce an audible jump. Set the model at context creation, or switch only during quiet moments.
- The 1.1 spec doesn't guarantee thread safety for
alDistanceModel(); call it from your audio thread or guard it.
Per-source override with OpenAL Soft
OpenAL Soft (the implementation shipped with most Linux distros and commonly bundled on Windows) supports AL_SOFT_source_distance_model, letting you override the model per source. Check for it before use:
// Run on the audio thread, after context creation.
if (alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()),
"AL_SOFT_source_distance_model")) {
alSourcei(uiSoundSource, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE_CLAMPED);
alSourcei(worldSource, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE_CLAMPED);
}
ALenum err = alGetError(); // AL_INVALID_ENUM = extension not really usableYou can confirm extension availability out-of-band with the openal-info tool bundled with OpenAL Soft.
Validating the curve
Don't trust the formula alone — verify against your actual implementation. A minimal check: create a context, set the model, place a looping source, step it away from the listener, and read back the applied gain:
// Build against OpenAL Soft 1.23+; run on the machine/headset you target.
// gcc gaincheck.c -lopenal -o gaincheck
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
for (float d = 0.5f; d <= 16.0f; d *= 2.0f) {
alSource3f(src, AL_POSITION, d, 0.0f, 0.0f);
alGetSourcef(src, AL_GAIN, &g); // read back applied gain
printf("d=%.1f gain=%.3f\n", d, g);
/* sleep briefly so the mixer applies the update */
}Expected checks: with inverse clamped, gain should be exactly 1.0 at d ≤ r, 0.5 at d = 2·r, 0.25 at d = 4·r. With linear clamped and max = 16, gain should hit 0.0 at d = 16. Call alGetError() after each call; AL_INVALID_ENUM after alDistanceModel() means you're on a pre-1.1 implementation without clamped variants. For an end-to-end check, record the output of a moving source in a DAW and measure RMS versus distance.
Recommendation
Default to AL_INVERSE_DISTANCE_CLAMPED for world audio, AL_LINEAR_DISTANCE_CLAMPED where you need a guaranteed silence radius, and reserve unclamped models for deliberate near-field effects. For VR/AR, layer this with HRTF (AL_SOFT_HRTF) and source cones (AL_CONE_INNER_ANGLE, AL_CONE_OUTER_GAIN) — distance attenuation alone won't sell spatialization.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.