Source management efficiency

Started by Atta, March 17, 2007, 12:11:34

Previous topic - Next topic

Atta

Hi guys

Sorry for reopen other's topic again, but I would have questions.

So we have a world with hundreds of sounds.

I got it that, that we have Buffers and Sources.
When I am loading my world, I generate sources (around 12-14 depending on device) and load my sound Buffers.

I do not see clearly how to manage a lot of source if you could just generate few (12-14).

These generated sources are going to be used dynamically during the run-time, right?
I have created a little picture to clarify my question  ;)

Open a picture please and read me  ;D

- The green dot is the Listener
- The grey ones are my inactive sources (could be hundreds and these are just my classes to describe a hardware source)
    Something like this
    class mySource
    {
      vec3f pos;
      float pitch ....
      int index; // index to my loaded buffers array. What this source is playing
    }
    This class data is going to be passed for the alSource functions.
- The red ones are the generated sources (let say channels or hardware sources)

In theory it would be good to assign a hardware source for each of my GREY dot, but it cannot be done.
So we should somehow cull away the "far away" sources, right?
There is a topic here which was mentioned a some kind of priorities of the sources, but I would prefer some culling
depending on the "distance" of the Source and Listener.
As my green dot is moving in the world, my grey dots become reds, and always the closest ones to the green dot.

And finally my question is  ;)
How could I get the calculated Volume information about an active, playing hardware source ?
If I would be able to get the volume about a source, and it is almost silent, then I could cull it away and assign that hw source
to another, "closest" Grey source.


Any thoughts? I hope I clarified my question enough :)
Maybe point of view is bad ?!

Thank you

Atta

One more thing to make things even more cleared  ;D  Everybody know this from the openal sites

3.5.1. No Culling By Distance

With the DirectSound3D compatible Inverse Clamped Distance Model, OpenAL provides a per-source AL_MAX_DISTANCE attribute that can be used to define 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 processing, based on distance. However, the OpenAL does not support culling a source from processing based on a distance threshold.
At this time OpenAL does not support culling at all. Culling based on distance, or bounding volumes, or other criteria, is left to the application. For example, the application might employ sophisticated techniques to determine whether sources are audible. In particular, rule based culling inevitably introduces acoustic artifacts. For example, if the listener-source distance is nearly equal to the culling threshold distance, but varies above and below, there will be popping artifacts in the absence of hysteresis.


Actually the red sentence above, what I do not know how could be done

Do anybody implemented such before ?

directedchaos

Hey Atta,

I just started learning openAL to add sound to a game.  This post is kind of old, so I don't know how relevant this is, but here's an overview of the approach I'm working on.

Classes:
Sound -- holds info about the sound (most notably, source id)
SoundComparator -- compares two sounds (used when resources are tight for culling/freeing sources)
SoundLoader -- handles all sound resources

Most of the work is done in the last one, which I'm trying to make resemble a TextureLoader.  So I've got a HashMap of sound paths to buffer ids (to see if a sound is already loaded), a HashMap of sound paths to reference integers (to record how many sources are playing a buffered sound), and finally a sorted list of Sounds (the class).

The Sounds are sorted by volume (and an extra importance parameter, so the final value is volume * importance, but that's very application-specific).  The volume is determined using a linear distance model -- I messed around with the default Inverse Distance Clamped Model, but if you want to do culling, linear seems to make more sense so you can really make the sound go to zero.  As far as I can tell, you just manually calculate the gain every time and update it.  I could be wrong, about most of this... but things seem to work ok with my very limited testing.

Anyway, to get back to what I've done on your specific questions.  For the Inverse Distance Clamped Model, I found these equations:

dist = max(dist,REFERENCE_DISTANCE);
dist = min(dist,MAX_DISTANCE);
G_dB = GAIN - 20*log10(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE )
G_dB = min(G_dB,MAX_GAIN);
G_dB = max(G_dB,MIN_GAIN);


Now, if I understand correctly, every -6dB halves the gain (volume).  So, I divided the gain by 2^(-1/6*G_dB) to get the current volume.  dist is current distance to the listener from the sound location.  I use some more dynamic game objects, so my distance code is messier.

float G_dB = gain - 20*(float)Math.log10(1 + rolloffFactor*(dist-referenceDistance)/referenceDistance ); 
if(G_dB > maxGain) G_dB = maxGain;
if(G_dB < minGain) G_dB = minGain;
float divisor = (float)Math.pow(2,-1/6 * G_dB);
float curGain = gain / divisor;


The trickiest part I found was actually figuring out how to drop off the sound after a MAX_DISTANCE cutoff.  After some variable solving, I chugged out this, which again has had almost no testing:

public void calculateRolloff(){
        //NOTE: every -6db results in half volume
        //want: gain to be VOLUME_CUTOFF at maxDistance
        float G_dB_target = -6*(float)(Math.log(gain/VOLUME_CUTOFF)/Math.log(2));
        
        //solve for rolloff from Inverse Distance Clamped Model
        float newRolloff =
                (float)(Math.pow(10,(G_dB_target - gain)/(-20)) - 1)
                / ((maxDistance - referenceDistance) / referenceDistance);
        setRolloffFactor(newRolloff);
}


(Obviously, you can't have volume cutoff be zero). 

Frankly, all of this was giving me a bit of a headache, so I switched to manual linear model.  I inserted a little catch into the volume code:

float gainRange = maxGain - minGain;
float volume = ((maxDistance - dist-referenceDistance)
                     / (maxDistance-referenceDistance))
                        * gainRange
                        + minGain;


And now in fact set the volume the exact same way as I get it, so it's guaranteed to be correct.
To overview, when a Sound is made:

  • it loads the buffered sound (keyed via path to wav) from the SoundLoader (which in turn loads it if need be, and adds a reference)
  • requests a sound source (if none available, checks if its volume/priority is higher than one being used, in which case the used one is destroyed, if not, removes reference to buffer)

Each Sound object gets a turn every game cycle, and checks if its sound is done playing, or if it should be culled because it's too quiet.  If it is to be removed, the SoundLoader reference to its buffer is decreased, and its source id is returned to SoundLoader.

There's probably stuff like this out there, but my googling turned up more how-stuff-works than code snippets.  Right now my sound code is pretty entangled with my game code, with sounds following objects and whatnot each cycle.  I'm also not entirely sure where I got all parts from... I know there's some from the OpenAL lessons.  And I've done precious little testing on the full thing, let alone efficiency analysis (like, the hashmap thing might not make sense when you consider you only have a handful of sources tops... but it came to mind first).

Anyway, if this is something unique, I could try to clean it up for more general use.  My guess is once you figure out volume calculation, the sorting and culling will be pretty easy and based on how you want to do your app.  In particular it looks like you're going to be juggling lots of sound sources, maybe even all of them in the game world at once, constantly shuffling in those that you can play?  The way I'm doing it is more of a try-now-or-fail-forever approach.  My persistent sound sources will just have to periodically keep trying to play.  Hmm, more for me to think about...

Atta

Hey Directedchaos

What a good idea ! Why have not it come to my mind : calculating volume by myself.
I was just focusing on that how the volume could be retrived ...

I just see my sound manager class now ... so lets make it ...

Thanks man, I ll be back with the xp