Sound Attenuation does not behave as expected when using setRefDistance

[java]

music = new AudioNode(assetManager, “Sound/Effects/Gun.wav”, false);

music.setPositional(true);

music.setVolume(1f);

music.setRefDistance(0.0000001f);

music.setMaxDistance(2000.0f);

[/java]





This ref distance is so small that I should not be able to hear the sound at all unless I am right on top of it. However, I can still hear the sound out to about 300 meters, at which point it becomes too quiet for me to hear. Here’s a table of values for some experiments with refDistance:



refDistance Distance (meters) out to which I can just hear the sound

1 300

0.5 300

0.1 300

0.001 300

0.000001 300

5 300

50 958



The reference distance is the distance at which the sound becomes half as powerful due to attenuation. So with the reference distance set to 0.001 and a distance of 1 meter, the sound should have 1024 times less power than at its default volume, and should be imperceptible. Instead it is loud and clear. Why is this so? I’m using 64 bit linux.



sincerely,

–Robert McIntyre

Turns out that I had to set the AL_ROLLOFF_FACTOR to get the effect I wanted, which is very close range attenuation of sound. At close distances the rolloff factor dominates the equation for sound attenuation, given the current default sound attenuation model which JME uses.



I had to do something like this:



[java]

org.lwjgl.openal.AL10.alSourcef(1, org.lwjgl.openal.AL10.AL_ROLLOFF_FACTOR, 5f);

[/java]



Since jMonkeyEngine3 does not currently expose the AL_ROLLOFF_FACTOR parameter, I propose to add it to the audio system.



It involves three patches to jme3



[patch]

Index: src/core/com/jme3/audio/AudioParam.java

===================================================================

— src/core/com/jme3/audio/AudioParam.java (revision 8529)

+++ src/core/com/jme3/audio/AudioParam.java (working copy)

@@ -15,5 +15,6 @@

MaxDistance,

DryFilter,

ReverbFilter,

  • RolloffFactor,

    ReverbEnabled;

    }[/patch]



    [patch]

    Index: src/core/com/jme3/audio/AudioNode.java

    ===================================================================

    — src/core/com/jme3/audio/AudioNode.java (revision 8529)

    +++ src/core/com/jme3/audio/AudioNode.java (working copy)

    @@ -72,6 +72,7 @@

    protected boolean reverbEnabled = true;

    protected float maxDistance = 200; // 200 meters

    protected float refDistance = 10; // 10 meters
  • protected float rolloffFactor = 1f; // unitless

    protected Filter reverbFilter;

    private boolean directional = false;

    protected Vector3f direction = new Vector3f(0, 0, 1);

    @@ -398,7 +399,38 @@

    getRenderer().updateSourceParam(this, AudioParam.Pitch);

    }



    +

    /**
  • * @return The rolloff factor of the audio node.<br />
    
  • *<br />
    
  • * @see AudioNode#setRolloffFactor<br />
    
  • */<br />
    
  • public float getRolloffFactor(){
  •   return rolloffFactor;<br />
    
  • }

    +

    +
  • /**
  • * Set the rolloff factor for this node.  Larger values cause the<br />
    
  • * node's sound to attenuate more severely with distance.  Setting the<br />
    
  • * rolloff factor to zero prevents all attenuation.<br />
    
  • *<br />
    
  • * @param rolloffFactor the rolloffFactor to set<br />
    
  • * @throws IllegalArgumentException if rolloffFactor is negative.<br />
    
  • *<br />
    
  • */<br />
    
  • public void setRolloffFactor(float rolloffFactor){
  •   if (rolloffFactor &lt; 0){<br />
    
  •   	throw new IllegalArgumentException(&quot;rolloffFactor cannot be negative&quot;);<br />
    
  •   }<br />
    
  •   this.rolloffFactor = rolloffFactor;<br />
    
  •   if (channel &gt;= 0){<br />
    
  •   	getRenderer().updateSourceParam(this, AudioParam.RolloffFactor);<br />
    
  •   }<br />
    
  • }

    +

    +
  • /**
  • @return The volume of this audio node.

    *
  • @see AudioNode#setVolume(float)

    @@ -457,7 +489,7 @@



    /**
  • Set the velocity of the audio node. The velocity is expected
  • * to be in meters. Does nothing if the audio node is not positional.<br />
    
  • * to be in meters/second. Does nothing if the audio node is not positional.<br />
    

*

  • @param velocity The velocity to set.
  • @see AudioNode#setPositional(boolean)

    [/patch]



    [patch]

    Index: src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java

    ===================================================================

    — src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java (revision 8529)

    +++ src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java (working copy)



    @@ -460,6 +462,9 @@

    case Pitch:

    alSourcef(id, AL_PITCH, src.getPitch());

    break;
  •            case RolloffFactor:<br />
    
  •            	alSourcef(id, AL_ROLLOFF_FACTOR, src.getRolloffFactor());<br />
    
  •            	break;<br />
    

}

}

}

[/patch]



Do people like this and want to add it to JME?



sincerely,

–Robert McIntyre

So what do you guys think?

@pspeed: ?

Seems ok to me… as long as the default behavior doesn’t change. (looks like defaults stay unchanged to me = good)

I can confirm that the default OpenAL value for AL_ROLLOFF_FACTOR is 1.0f:



http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm



at Table 4.13, the specification says:


Table 4.13: ROLLOFF_FACTOR Attribute

Name
AL_ROLLOFF_FACTOR

Signature
f, fv, i, iv

Values
[0, any]

Default
1.0f

This is used for distance attenuation calculations based on inverse distance with rolloff. For distances smaller than AL_MAX_DISTANCE (and, depending on the distance model, larger than AL_REFERENCE_DISTANCE), this will scale the distance attenuation over the applicable range. See section on distance models for details how the attenuation is computed as a function of the distance.



In particular, AL_ROLLOFF_FACTOR can be set to zero for those sources that are supposed to be exempt from distance attenuation. The implementation is encouraged to optimize this case, bypassing distance attenuation calculation entirely on a per-source basis.

One bit missing from the patches, rolloff support needs to be added to the setSourceParams() method in LwjglAudioRenderer as well or it will not work when playing a sound instance. Was just encountering the same problem as bortreb.



I guess ultimately it would be nice to be able to set the distance attenuation model, possibly including support for a custom one (turning OpenAL attenuation off with AL_NONE and then plugging in a java class to set AL_GAIN manually). I may well end up doing that so I can add a penalty if line of sight between the sound and listener is blocked by a wall, or even calculate the distance through a pathfinding algorithm.