Sound effects behave differently on level 8

Normally in vanilla Doom, sound effects decrease in volume with distance, with a cutoff at 1200 units. Sound effects originating at a distance of more than 1200 units from the player are not heard.

This behaviour is different on an ExM8 level of Doom/Ultimate Doom as well as MAP08 of Doom II or Final Doom.

When playing on an ExM8 level, sound effects are not cut off. As the boss levels in Doom 1 all occur on ExM8, it is possible that this behaviour was intended so that the player could always hear the boss monster from any distance. Doom95 incorrectly also applies this to Map08 of Doom2 and Final Doom.

As an additional effect of this also mistakenly occurs on Map08 of Doom and Final Doom, if the sfx volume is decreased to zero, sound effects still play, but very quietly. In this scenario, the effect of distance on volume is reversed. Close sound effects are quiet while sound effects at a distance are loud.

Demonstrating the effect
To demonstrate this effect:


 * 1) Start Doom and warp to level 8 (mission 8 of any episode or MAP08).
 * 2) Wake up some monsters by attacking them.
 * 3) Activate the noclip cheat (IDCLIP/IDSPISPOPD) and walk outside the level, far away from any monsters.
 * 4) Notice that monster growling noises can still be heard despite the distance.
 * 5) Go to the sound menu and move the sound effect volume slider to minimum.
 * 6) Monsters can still be heard.  Travel back toward the monsters.
 * 7) Notice that the volume of the monsters decreases when moving closer to them.

Technical
The cause of this is found in s_sound.c in the Doom source code:

// From _GG1_ p.428. Appox. eucledian distance fast. approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); if (gamemap != 8  && approx_dist > S_CLIPPING_DIST) {    return 0; }

This code calculates the distance of the sound from the player. If the sound is greater than the clipping distance (1200 units), the function returns and the sound does not play. However, a specific test is made to see if the current level is level 8. If so, there is no distance cutoff.

// volume calculation if (approx_dist < S_CLOSE_DIST) {    *vol = snd_SfxVolume; } else if (gamemap == 8) {    if (approx_dist > S_CLIPPING_DIST) approx_dist = S_CLIPPING_DIST; *vol = 15+ ((snd_SfxVolume-15)              *((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } else {    // distance effect *vol = (snd_SfxVolume            * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; }

This is the code which decreases the volume of sound effects with distance. A different calculation is used here for level 8. A value of 15 is always added to the volume, so that it is always above zero.

Differences between Vanilla Doom and the released source
Examination of the released Doom source code can be misleading because of a change made to the sound code before the source release. In Vanilla Doom, there are two variables which hold the sound effect volume. One of these is named "sfxVolume", and has a range of 0-15. This is the value stored in the configuration file and controlled via the sound volume screen.

The second variable is internal to the sound subsystem (snd_SfxVolume in the above code fragment). Unlike sfxVolume this has a range of 0-127. The menu updates this internal variable by calling S_SetSfxVolume to inform the sound subsystem of volume changes. Before the source code release, the two variables were combined into a single variable named snd_SfxVolume, having a range of 0-15.

The result of this is that the sound code from the source release behaves differently on level 8. If the volume setting is at maximum (15), then all sound effects play at maximum volume regardless of distance from the player. Secondly, the reversed volume effect occurs at any volume setting below this.

Remnants of this change are scattered throughout the source release. The following is from m_menu.c:

S_SetSfxVolume(snd_SfxVolume /* *8 */);

The commented-out multiply-by-8 was needed in Vanilla Doom to convert from the 0-15 to 0-127 range, but after the two variables were merged, became useless. S_SetSfxVolume itself still checks values are in the range 0-127, although it should be noted that the function essentially became pointless after the change.