AudioEmitter distance problem
by Ken Finney · in Torque Game Engine · 03/03/2002 (8:50 am) · 32 replies
When I place a looping 2d Audio emitter with min dist set to 10, and max set to 50, of course I don't hear anything when beyond the max range. Then I move closer, and it when I get close enough, voila ! there's the sound. But now it will never go away... no matter how far away I go (1 whole terrain, in one instance) that sound just continues to play, albeit at a somewhat more muted level (maybe 50% of max volume).
Has anyone else encountered this ?
Has anyone else encountered this ?
About the author
#22
01/07/2003 (7:42 pm)
Sam - yup it did work fine for me (as stated above), but now it no longer does...
#23
Replace the following 2 functions win audio.cc with these.
Note *This will only apply to 3d looping sounds for now*
This works for me on the latest major non-head version.
Sam
01/07/2003 (8:11 pm)
I have come up with a temp solution, please try it and tell me how it worksReplace the following 2 functions win audio.cc with these.
Note *This will only apply to 3d looping sounds for now*
void alxUpdateMaxDistance()
{
Point3F listener;
alGetListener3f(AL_POSITION, &listener.x, &listener.y, &listener.z);
for(U32 i = 0; i < mNumSources; i++)
{
if(mHandle[i] == NULL_AUDIOHANDLE)
continue;
LoopingList::iterator itr = mLoopingList.findImage(mHandle[i]);
if(itr && (*itr)->mDescription.mIs3D)
{
Point3F pos = (*itr)->mPosition - listener;
F32 dist = pos.magnitudeSafe();
F32 min = (*itr)->mDescription.mReferenceDistance;
F32 max = (*itr)->mDescription.mMaxDistance;
if(dist > max)
mSourceVolume[i] = 0.0f;
else if(dist > min)
mSourceVolume[i] = (*itr)->mDescription.mVolume * (min / dist);
else
mSourceVolume[i] = (*itr)->mDescription.mVolume;
F32 vol = mSourceVolume[i] * mAudioTypeVolume[mType[i]] * mMasterVolume;
alSourcef(mSource[i], AL_GAIN, vol);
/*Con::warnf("Distances");
Con::errorf("Max Distance = %f", max);
Con::errorf("Min Distance = %f", min);
Con::errorf("Our Distance = %f", dist);
Con::warnf("Source Volumes");
Con::errorf("Source Vol = %f", mSourceVolume[i]);
Con::errorf("Type Vol = %f", mAudioTypeVolume[mType[i]]);
Con::warnf("Description and overall volume");
Con::errorf("Desc Vol = %f", (*itr)->mDescription.mVolume);
Con::errorf("Vol = %f", vol);
Con::printf("");*/
}
}
}
//--------------------------------------------------------------------------
// Called to update alx system
//--------------------------------------------------------------------------
void alxUpdate()
{
#pragma message("todo")
//if(mForceMaxDistanceUpdate)
alxUpdateMaxDistance();
alxCloseHandles();
alxUpdateScores(false);
alxLoopingUpdate();
#ifdef GATHER_METRICS
alxGatherMetrics();
#endif
}This works for me on the latest major non-head version.
Sam
#24
01/08/2003 (10:19 am)
I put this into HEAD, and did NOT notice any difference - it still works for me, just as before. However, note that the functions AlGetSourcefv and relatives might be the source of the problem some people have. Maybe those functions don't work on every machine, maybe the driver DOES have issues.
#25
Sam's code looks like it manually does the volume changes, which on my machine adds to the volume effects openAL does, so the emitter is even quieter.
Sam, what sound card are you using, and which openAL32.dll??
Also, what is the ReferenceDistance and MaxDistance on the emitter?
01/08/2003 (8:22 pm)
I'm really starting to think this is an OpenAL driver issue. On my Audigy, the volumes attenuate correctly, but never mute. Calling the original alxUpdateMaxDistance checks for that case and manually mutes the sound.Sam's code looks like it manually does the volume changes, which on my machine adds to the volume effects openAL does, so the emitter is even quieter.
Sam, what sound card are you using, and which openAL32.dll??
Also, what is the ReferenceDistance and MaxDistance on the emitter?
#26
3.6. No Culling By Distance
With the DS3D compatible Inverse Clamped Distance Model, AL provides a
per-Source MAX_DISTANCE attribute that can be used to dene a distance beyond
which the Source will not be further attenuated by distance. The DS3D distance
attenuation model and its clamping of volume is also extended by a mechanism to
cull (mute) sources from proccessing, based on distance. However, AL does not
support culling a Source from processing based on a distance threshold.
At this time AL is not meant to support culling at all. Culling based on distance, or
bounding volumes, or other criteria, is best left to the application. For example, the
application might employ sophisticated techniques to determine whether sources
are audible that are beyond the scope of AL. In particular, rule based culling
inevitably introduces acoustic artifacts. E.g. if the Listener-Source distance is nearly
equal to the culling threshold distance, but varies above and below, there will be
popping artifacts in teh absence of hysteresis.
In effect, this means that MAX_DISTANCE is the distance where OpenAL stops attenuating the gain, not the distance where the gain is zero. Hence, the need to manually mute or cull sounds.
01/08/2003 (8:24 pm)
Ahh, I think I figured out the emitter not muting thing. From OpenAL spec:3.6. No Culling By Distance
With the DS3D compatible Inverse Clamped Distance Model, AL provides a
per-Source MAX_DISTANCE attribute that can be used to dene a distance beyond
which the Source will not be further attenuated by distance. The DS3D distance
attenuation model and its clamping of volume is also extended by a mechanism to
cull (mute) sources from proccessing, based on distance. However, AL does not
support culling a Source from processing based on a distance threshold.
At this time AL is not meant to support culling at all. Culling based on distance, or
bounding volumes, or other criteria, is best left to the application. For example, the
application might employ sophisticated techniques to determine whether sources
are audible that are beyond the scope of AL. In particular, rule based culling
inevitably introduces acoustic artifacts. E.g. if the Listener-Source distance is nearly
equal to the culling threshold distance, but varies above and below, there will be
popping artifacts in teh absence of hysteresis.
In effect, this means that MAX_DISTANCE is the distance where OpenAL stops attenuating the gain, not the distance where the gain is zero. Hence, the need to manually mute or cull sounds.
#27
02/27/2003 (10:29 pm)
Sam's code fixed the problem for me. If it doesn't break other audio cards it should be included in the build.
#28
02/28/2003 (4:25 am)
Didn't change anything for me.
#29
also add
somewhere in the function OpenALInit(). I added just before the lines:
FInally in client/prefs.cs set
If you'll notice I used:
For Ken:
Here's what I added to the scorchedPlanet.mis file for testing
and in server/scripts/audioProfiles.cs i have
Just make sure testing.wav exists in the sound folder
03/01/2003 (8:42 am)
Here's the code that I think the original author of audio.cc intendedvoid alxUpdateMaxDistance()
{
Point3F listener;
alGetListener3f(AL_POSITION, &listener.x, &listener.y, &listener.z);
for(U32 i = 0; i < mNumSources; i++)
{
if(mHandle[i] == NULL_AUDIOHANDLE)
continue;
ALint val = AL_FALSE;
alGetSourcei(mSource[i], AL_SOURCE_RELATIVE, &val);
if(val == AL_TRUE)
continue;
Point3F pos;
alGetSourcefv(mSource[i], AL_POSITION, (ALfloat*)((F32*)pos) );
ALfloat max;
alGetSourcef(mSource[i], AL_MAX_DISTANCE, &max);
pos -= listener;
F32 dist = pos.magnitudeSafe();
alSourcef(mSource[i], AL_GAIN, (dist >= max) ? 0.f : Audio::linearToDB(mSourceVolume[i]) * mAudioTypeVolume[mType[i]] * mMasterVolume);
}
}
//--------------------------------------------------------------------------
// Called to update alx system
//--------------------------------------------------------------------------
void alxUpdate()
{
if(mForceMaxDistanceUpdate)
alxUpdateMaxDistance();
alxCloseHandles();
alxUpdateScores(false);
alxLoopingUpdate();
#ifdef GATHER_METRICS
alxGatherMetrics();
#endif
}also add
mForceMaxDistanceUpdate = Con::getBoolVariable("$pref::audio::forceMaxDistanceUpdate", false);somewhere in the function OpenALInit(). I added just before the lines:
// Make this context the active context alcMakeContextCurrent(mContext);
FInally in client/prefs.cs set
$pref::Audio::forceMaxDistanceUpdate = 1;
If you'll notice I used:
Audio::linearToDB(mSourceVolume[i]) * mAudioTypeVolume[mType[i]] * mMasterVolumeThe rest of the audio.cc, whereever it calls Audio::linearToDB, makes the call like this:
Audio::linearToDB(mSourceVolume[i] * mAudioTypeVolume[mType[i]] * mMasterVolume)This has the effect of scaling the master and channel volume sliders in the user preferences logarithmically instead of linearly. So any values less than .8 become almost silent. It seems to me that the effect of the user preference sliders should be applied linearly so I've changed my code to reflect this. If you don't want it this way change the alSourcef(...) call to reflect the second format.
For Ken:
Here's what I added to the scorchedPlanet.mis file for testing
new AudioEmitter(test) {
position = "93.4289 -227.57 157.692";
rotation = "1 0 0 0";
scale = "1 1 1";
profile = "takeme";
useProfileDescription = "1";
fileName = "0";
type = "2";
volume = "1";
outsideAmbient = "1";
referenceDistance = "1";
maxDistance = "100";
isLooping = "1";
is3D = "1";
loopCount = "-1";
minLoopGap = "0";
maxLoopGap = "1";
coneInsideAngle = "360";
coneOutsideAngle = "360";
coneOutsideVolume = "1";
coneVector = "0 0 1";
minDistance = "20.0";
};and in server/scripts/audioProfiles.cs i have
datablock AudioProfile(takeme)
{
filename = "~/data/sound/testing.wav";
description = "AudioDefaultLooping3d";
preload = false;
};Just make sure testing.wav exists in the sound folder
#30
Time once again to resurrect this post...
*Waves hands around while chanting* **POOF!**
There we go.
Introduction
With the latest release of the OpenAL drivers (see the News page), I've decided to look into the audio side of Torque. To begin with, I've made the changes that Brett outlined above, and I do like what I hear. Thanks Brett! Now my sounds actually stop when they reach the maximum distance.
However, I can still hear my sounds just before they cut-off. The volume doesn't decrease enough for me at the maximum defined distance. What to do?! Well, I did what any programmer would do: I looked at the OpenAL source to try to get to the root of the problem.
Playing with Distance
To begin with, here's the code from the OpenAL source that appears to attenuate the sound based on distance:
I've made some charts so you may also follow along. All of the charts show how the sound's volume changes with distance. They each have a MinDist of 10 units and a MaxDist of 100 units. The first chart shows the volume changes from 1 to 300 units, using both unclamped (AL_INVERSE_DISTANCE) and clamped (AL_INVERSE_DISTANCE_CLAMPED) distance models, with a rolloff of 1.0 (the default that Torque uses):
Chart 1
As you may see, the unclamped volume increases dramatically when the listener is less than the MinDist from the source. In fact, at 1 unit, the volume reaches a value of 10. I've cut off the unclamped volume at 2 (5 units from source) to allow us to zoom in on the meaty part at the right-most end of the chart.
As you may see, at 100 units from the sound source, the sound volume is still quite loud. In fact, it's at 10% of the original volume. You'd have to go out as far as 1000 units for the sound to drop to 1%.
Playing with Rolloff
Based on the OpenAL formula above, the only thing we have to play with is the Rolloff. This parameter is not exposed in Torque, so I've added the following to the bottom of alxSourcePlay() in engine/audio/auido.cc:
Chart 2: Rolloff = 2
Interestingly, the unclamped volume has some problems prior to the minimum volume, although I didn't notice any audible problems while in Torque. However, I sure didn't like the idea of passing along possibly nasty values to OpenAL (I'm concerned that they may crash with certain sound drivers/cards), so I've continued my testing in the clamped mode. You may change to this format by changing the bottom of the OpenALInit() function in engine/audio/audio.cc from this:
Chart 3: Volume curve with various Rolloff values
As you would expect, a higher Rolloff value produces a sharper volume drop with distance. At 100 units with a Rolloff of 10, the final volume was at 1% of the maximum. When I tried this in Torque, I found the sound to be very quiet when it finally cut off. I felt that during gameplay, you'd not notice the sound cutting off.
Conclusions
It appears that the OpenAL driver only allows one to play with min/max distances and Rolloff when it comes to automatically modifying a sound's volume based on the distance a listener is from the source. As the min/max distances are very often chosen based on gameplay or level design (I want to be able to hear its sound just before I can see it, and not before, etc.), that only leaves Rolloff.
Based on the above modeling, Rolloff does allow the sound volume to be dramatically lowered prior to the range cutoff at the expense of a much steeper fall-off curve.
Suggestions
1. Perhaps by exposing the Rolloff value to the script audio profiles (rather than setting a value in code as I did above), it will be easier to fine-tune the sounds.
2. Maybe OpenAL should have a linear drop-off function in addition to the inverse distance ones. Will this make the sounds less realistic? I don't know...I'm not a sound Engineer. However, it sure would make sound programming a lot easier.
3. Place all of the automatic sound attenuation by distance code within Torque itself, and use OpenAL mainly for it's playback and sound driver interface capabilities.
So, what do you all think??
- LightWave Dave
04/04/2003 (10:02 am)
Greetings!Time once again to resurrect this post...
*Waves hands around while chanting* **POOF!**
There we go.
Introduction
With the latest release of the OpenAL drivers (see the News page), I've decided to look into the audio side of Torque. To begin with, I've made the changes that Brett outlined above, and I do like what I hear. Thanks Brett! Now my sounds actually stop when they reach the maximum distance.
However, I can still hear my sounds just before they cut-off. The volume doesn't decrease enough for me at the maximum defined distance. What to do?! Well, I did what any programmer would do: I looked at the OpenAL source to try to get to the root of the problem.
Playing with Distance
To begin with, here's the code from the OpenAL source that appears to attenuate the sound based on distance:
//3. Calculate distance attenuation
Distance=(ALfloat)sqrt(aluDotproduct(Position,Position));
if (DistanceModel!=AL_NONE)
{
if (DistanceModel==AL_INVERSE_DISTANCE_CLAMPED)
{
Distance=(Distance<MinDist?MinDist:Distance);
Distance=(Distance>MaxDist?MaxDist:Distance);
}
Volume=(Volume*ListenerGain*MinDist)/(MinDist+Rolloff*(Distance-MinDist));
}
else
Volume=(Volume*ListenerGain );This code is from the aluCalculateSourceParameters() function in openal/win/Alu/ALu.c (I haven't checked the other platforms for differences). It's a fairly straightforward formula, but I just can't visualize what's occurring. So, time to model it in Excel...I've made some charts so you may also follow along. All of the charts show how the sound's volume changes with distance. They each have a MinDist of 10 units and a MaxDist of 100 units. The first chart shows the volume changes from 1 to 300 units, using both unclamped (AL_INVERSE_DISTANCE) and clamped (AL_INVERSE_DISTANCE_CLAMPED) distance models, with a rolloff of 1.0 (the default that Torque uses):
Chart 1
As you may see, the unclamped volume increases dramatically when the listener is less than the MinDist from the source. In fact, at 1 unit, the volume reaches a value of 10. I've cut off the unclamped volume at 2 (5 units from source) to allow us to zoom in on the meaty part at the right-most end of the chart.
As you may see, at 100 units from the sound source, the sound volume is still quite loud. In fact, it's at 10% of the original volume. You'd have to go out as far as 1000 units for the sound to drop to 1%.
Playing with Rolloff
Based on the OpenAL formula above, the only thing we have to play with is the Rolloff. This parameter is not exposed in Torque, so I've added the following to the bottom of alxSourcePlay() in engine/audio/auido.cc:
alSourcef(source, AL_ROLLOFF_FACTOR, 2.0f);With a Rolloff of 2.0, the chart looks like this:
Chart 2: Rolloff = 2
Interestingly, the unclamped volume has some problems prior to the minimum volume, although I didn't notice any audible problems while in Torque. However, I sure didn't like the idea of passing along possibly nasty values to OpenAL (I'm concerned that they may crash with certain sound drivers/cards), so I've continued my testing in the clamped mode. You may change to this format by changing the bottom of the OpenALInit() function in engine/audio/audio.cc from this:
alDistanceModel(AL_INVERSE_DISTANCE);to this:
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);With a Rolloff of 2, at 100 units from the sound source, the volume is now at 5%. Not bad. I then decided to model how various Rolloff values modified the volume curve:
Chart 3: Volume curve with various Rolloff values
As you would expect, a higher Rolloff value produces a sharper volume drop with distance. At 100 units with a Rolloff of 10, the final volume was at 1% of the maximum. When I tried this in Torque, I found the sound to be very quiet when it finally cut off. I felt that during gameplay, you'd not notice the sound cutting off.
Conclusions
It appears that the OpenAL driver only allows one to play with min/max distances and Rolloff when it comes to automatically modifying a sound's volume based on the distance a listener is from the source. As the min/max distances are very often chosen based on gameplay or level design (I want to be able to hear its sound just before I can see it, and not before, etc.), that only leaves Rolloff.
Based on the above modeling, Rolloff does allow the sound volume to be dramatically lowered prior to the range cutoff at the expense of a much steeper fall-off curve.
Suggestions
1. Perhaps by exposing the Rolloff value to the script audio profiles (rather than setting a value in code as I did above), it will be easier to fine-tune the sounds.
2. Maybe OpenAL should have a linear drop-off function in addition to the inverse distance ones. Will this make the sounds less realistic? I don't know...I'm not a sound Engineer. However, it sure would make sound programming a lot easier.
3. Place all of the automatic sound attenuation by distance code within Torque itself, and use OpenAL mainly for it's playback and sound driver interface capabilities.
So, what do you all think??
- LightWave Dave
#31
ok - i've done some searching but i still haven't found the source of the problem. First, here is my datablock that i'm using and have defined in server/scripts/audioProfiles.cs:
datablock AudioProfile(OceanSounds)
{
filename = "~/data/sound/environment/ocean2.wav";
description = "AudioDefaultLooping3d";
preload = false;
};
here is my emitter in the mission file:
new AudioEmitter(beach1) {
position = "577.774 -165.558 348.111";
rotation = "1 0 0 0";
scale = "1 1 1";
profile = "OceanSounds";
useProfileDescription = "1";
description = "AudioDefaultLooping3d";
fileName = "0";
type = "2";
volume = "1";
outsideAmbient = "1";
referenceDistance = "1";
maxDistance = "300";
isLooping = "1";
is3D = "1";
loopCount = "-1";
minLoopGap = "0";
maxLoopGap = "0";
coneInsideAngle = "360";
coneOutsideAngle = "360";
coneOutsideVolume = "1";
coneVector = "0 0 1";
minDistance = "60.0";
};
when i step through void AudioEmitter::packData(NetConnection *, U32 mask, BitStream * stream) in audioemitter.cc, i see the values that i had entered for the emitter in the mission file, but the stream object isn't getting filled with those values because this test fails for every value:
// maxdistance
if(stream->writeFlag(mDirty.test(MaxDistance)))
so - that's where i'm stuck. Anybody? ... Andybody? ... Bueller?
04/24/2003 (5:48 pm)
Along the same thread.. but different - have any of you had a problem with the maxDistance value not updating the actual distance from the emitter that you start and stop hearing the sound? I've implemented Brett's code from above, and no matter what my maxDistance value is (20,30,300,500,1000,etc.), i always start and stop hearing the sound at 100 units from the source. Anybody else had this problem?ok - i've done some searching but i still haven't found the source of the problem. First, here is my datablock that i'm using and have defined in server/scripts/audioProfiles.cs:
datablock AudioProfile(OceanSounds)
{
filename = "~/data/sound/environment/ocean2.wav";
description = "AudioDefaultLooping3d";
preload = false;
};
here is my emitter in the mission file:
new AudioEmitter(beach1) {
position = "577.774 -165.558 348.111";
rotation = "1 0 0 0";
scale = "1 1 1";
profile = "OceanSounds";
useProfileDescription = "1";
description = "AudioDefaultLooping3d";
fileName = "0";
type = "2";
volume = "1";
outsideAmbient = "1";
referenceDistance = "1";
maxDistance = "300";
isLooping = "1";
is3D = "1";
loopCount = "-1";
minLoopGap = "0";
maxLoopGap = "0";
coneInsideAngle = "360";
coneOutsideAngle = "360";
coneOutsideVolume = "1";
coneVector = "0 0 1";
minDistance = "60.0";
};
when i step through void AudioEmitter::packData(NetConnection *, U32 mask, BitStream * stream) in audioemitter.cc, i see the values that i had entered for the emitter in the mission file, but the stream object isn't getting filled with those values because this test fails for every value:
// maxdistance
if(stream->writeFlag(mDirty.test(MaxDistance)))
so - that's where i'm stuck. Anybody? ... Andybody? ... Bueller?
#32
Have the changes you guys suggested here been submitted as patches?
07/11/2003 (6:45 pm)
@David/Brett,Have the changes you guys suggested here been submitted as patches?
Torque Owner Sam Guffey
I downloaded the AL_SDK and there is an example that deals with looping 3d sounds and they update fine so those that thought it may have been a hardware or OS problem it isnt, im running WinXP with a Creative SB Live card.
Any help would be appreiciated.
Sam