Question about hardware channel allocation and sound buffers

View: New views
4 Messages — Rating Filter:   Alert me  

Question about hardware channel allocation and sound buffers

by slytron :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I am building a rpg. I currently have over 300 sounds but normally fewer than 10 will actually be playing at any given time.
I realize that most sound cards can only mix 32 or 64 sounds at a time.
The question is does a sound card hardware channel get allocated when a buffer is loaded with alBufferData and attached with AL_BUFFER or is the hardware channel only in use while the sound is playing? My plan is to buffer the sound when it is first played but not delete with alDeleteBuffers unless the creature is destroyed. My other option is to load the buffers when the sound is about to played and destroy it when the sound has finished but this seems ineffectient ( I am not currently worried about memory consumption.. only performance and avoiding loading from file each time ).
In other words in the extreme case there could be 100s of sounds loaded at the same time but only a few playing at any given time. Is it ok to leave the buffers loaded or do I need to reload them each time a sound is required to avoid using up all the hardware sound channels?
BTW Thanks for the previous help:)
Brett

Re: Question about hardware channel allocation and sound buffers

by Chris Robinson-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 10 November 2008 04:27:07 pm slytron wrote:
> I realize that most sound cards can only mix 32 or 64 sounds at a time.
> The question is does a sound card hardware channel get allocated when a
> buffer is loaded with alBufferData and attached with AL_BUFFER or is the
> hardware channel only in use while the sound is playing?

Generally the hardware channel is in use while a buffer is attached to a
source. So setting a source with alSourcei(source,AL_BUFFER,0); will release
the hardware channels. Note that this isn't gauranteed by the spec, but AFAIK
all current hardware drivers behave this way.

The one thing to watch out for though, is that an implementation may only
generate enough sources for each one to play a mono sound (multichannel
buffers may take up multiple hardware channels, too). What you'll probably
have to do is hold a pool of sources, and pick from them as you need one. So,
at your program's start, you could have:

vector<ALuint> Sources;
...
while(1) {
    ALuint src;
    alGenSources(1, &src);
    if(alGetError() != AL_NO_ERROR)
        break;
    Sources.push_back(src);
}

Since they don't have attached buffers, they won't be taking up hardware
channels yet. Then when you want to play a sound:

void myObject::PlaySound(const string &name, bool looping
                         /*, other parameters*/)
{
    // Get the buffer based on the given name. If it's the first time it's
    // used, it can be loaded into an AL buffer then cached globally to be
    // returned immediately on subsequent calls
    ALuint buffer = GetBufferByName(name);
    if(!buffer) // failed to load sound
        return;

    // Make sure there's a useable source and get it
    if(Sources.size() == 0)
    {
        // if not, you'll have to kill a current sound based on distance,
        // gain, and priority (find the sound with the lowest priority and is
        // quietest based on distance and gain; if it has lesser priority, or
        // equal priority but is quieter, than the sound trying to play, force
        // it to stop)

        // if there's still no sources (ie. no sounds could be killed), just
        // skip
        if(Sources.size() == 0)
            return;
    }
    this->source = Sources.back();
    Sources.pop_back();

    ...set source properties...
    alSourcei(this->source, AL_LOOPING, looping?AL_TURE:AL_FALSE);
    alSourcei(this->source, AL_BUFFER, buffer);
    if(alGetError() != AL_NO_ERROR)
    {
        // failed to setup the sound. return the source to the pool
        Sources.push_back(this->source);
        this->source = 0;
        return;
    }
    alSourcePlay(this->source);
    alGetError();
}

Then about 20 to 30 times a second, you'll want to update the sound. You can
check then to make sure the sound is still playing.

void myObject::UpdateSound()
{
    if(!this->source) // no sound to update
        return;

    ALint state;
    alGetSourcei(this->source, AL_SOURCE_STATE, &state);
    if(state == AL_STOPPED)
    {
        // source stopped playing. free the channel and return the source to
        // the pool
        alSourceRewind(this->source);
        alSourcei(this->source, AL_BUFFER, 0);

        Sources.push_back(this->source);
        this->source = 0;
        return;
    }

    ...update parameters...
}

This is similar to a method I used in a project, and is rather scalable. It
works well even with limited sources (32) in high-sound-count environments
(at least 80 trying to play). The higher-level logic will have to check if
the object's supposed to be playing a looping sound and make sure it's still
playing, periodically trying to restart it if its not.
_______________________________________________
Openal-devel mailing list
Openal-devel@...
http://opensource.creative.com/mailman/listinfo/openal-devel

Re: Question about hardware channel allocation and sound buffers

by slytron :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Chris Robinson wrote:

> On Monday 10 November 2008 04:27:07 pm slytron wrote:
>  
>> I realize that most sound cards can only mix 32 or 64 sounds at a time.
>> The question is does a sound card hardware channel get allocated when a
>> buffer is loaded with alBufferData and attached with AL_BUFFER or is the
>> hardware channel only in use while the sound is playing?
>>    
>
> Generally the hardware channel is in use while a buffer is attached to a
> source. So setting a source with alSourcei(source,AL_BUFFER,0); will release
> the hardware channels. Note that this isn't gauranteed by the spec, but AFAIK
> all current hardware drivers behave this way.
>
> The one thing to watch out for though, is that an implementation may only
> generate enough sources for each one to play a mono sound (multichannel
> buffers may take up multiple hardware channels, too). What you'll probably
> have to do is hold a pool of sources, and pick from them as you need one. So,
> at your program's start, you could have:
>
> vector<ALuint> Sources;
> ...
> while(1) {
>     ALuint src;
>     alGenSources(1, &src);
>     if(alGetError() != AL_NO_ERROR)
>         break;
>     Sources.push_back(src);
> }
>
> Since they don't have attached buffers, they won't be taking up hardware
> channels yet. Then when you want to play a sound:
>
> void myObject::PlaySound(const string &name, bool looping
>                          /*, other parameters*/)
> {
>     // Get the buffer based on the given name. If it's the first time it's
>     // used, it can be loaded into an AL buffer then cached globally to be
>     // returned immediately on subsequent calls
>     ALuint buffer = GetBufferByName(name);
>     if(!buffer) // failed to load sound
>         return;
>
>     // Make sure there's a useable source and get it
>     if(Sources.size() == 0)
>     {
>         // if not, you'll have to kill a current sound based on distance,
>         // gain, and priority (find the sound with the lowest priority and is
>         // quietest based on distance and gain; if it has lesser priority, or
>         // equal priority but is quieter, than the sound trying to play, force
>         // it to stop)
>
>         // if there's still no sources (ie. no sounds could be killed), just
>         // skip
>         if(Sources.size() == 0)
>             return;
>     }
>     this->source = Sources.back();
>     Sources.pop_back();
>
>     ...set source properties...
>     alSourcei(this->source, AL_LOOPING, looping?AL_TURE:AL_FALSE);
>     alSourcei(this->source, AL_BUFFER, buffer);
>     if(alGetError() != AL_NO_ERROR)
>     {
>         // failed to setup the sound. return the source to the pool
>         Sources.push_back(this->source);
>         this->source = 0;
>         return;
>     }
>     alSourcePlay(this->source);
>     alGetError();
> }
>
> Then about 20 to 30 times a second, you'll want to update the sound. You can
> check then to make sure the sound is still playing.
>
> void myObject::UpdateSound()
> {
>     if(!this->source) // no sound to update
>         return;
>
>     ALint state;
>     alGetSourcei(this->source, AL_SOURCE_STATE, &state);
>     if(state == AL_STOPPED)
>     {
>         // source stopped playing. free the channel and return the source to
>         // the pool
>         alSourceRewind(this->source);
>         alSourcei(this->source, AL_BUFFER, 0);
>
>         Sources.push_back(this->source);
>         this->source = 0;
>         return;
>     }
>
>     ...update parameters...
> }
>
> This is similar to a method I used in a project, and is rather scalable. It
> works well even with limited sources (32) in high-sound-count environments
> (at least 80 trying to play). The higher-level logic will have to check if
> the object's supposed to be playing a looping sound and make sure it's still
> playing, periodically trying to restart it if its not.
> _______________________________________________
> Openal-devel mailing list
> Openal-devel@...
> http://opensource.creative.com/mailman/listinfo/openal-devel
>
>  
Thanks Chris,
Although I am currently only playing 2 sounds orbiting the listener as a
test it all seams to be working well thanks to your information.
With the info you just gave me I think I can implement a proper sound
management system. I thank all the developers of openal.
I spent a day looking into using the direct x sound and you would think
at version 10+ they would have a decent library but
I would bet it would of taken me 3 or 4 weeks instead of the 2 days with
openal. Plus even though the UI of my game and world editor is in
windows mfc the rest of it can be built in windows or linux. ( squirrel
scripting, irrlicht for graphics, openal for sound and newton game
dynamics for physics )
Thanks again
Brett
_______________________________________________
Openal-devel mailing list
Openal-devel@...
http://opensource.creative.com/mailman/listinfo/openal-devel

Re: Question about hardware channel allocation and sound buffers

by Chris Robinson-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 10 November 2008 09:34:21 pm Brett Jones wrote:
> With the info you just gave me I think I can implement a proper sound
> management system. I thank all the developers of openal.

Not a problem. :)

> I spent a day looking into using the direct x sound and you would think
> at version 10+ they would have a decent library

DirectSound has been rather stagnant since DirectX 8. Doesn't help that
Windows Vista effectively killed it (there is no accelerated DirectSound in
Vista, without something like ALchemy that can wrap it around a hardware
OpenAL driver).
_______________________________________________
Openal-devel mailing list
Openal-devel@...
http://opensource.creative.com/mailman/listinfo/openal-devel