OpenAL Lesson 5: Sources Sharing Buffers(转载)

转自http://www.devmaster.net/articles/openal-tutorials/lesson5.php

At this point in the OpenAL series I will show one method of having your buffers be shared among many sources. This is a very logical and natural step, and it is so easy that some of you may have already done this yourself. If you have you may just skip this tutorial in total and move on. But for those keeners who want to read all of the info I've got to give, you may find this interesting. Plus, we will be implementing the Alc layer directly so that we can use some of that knowledge gained in lesson 4. On top of that we will create a program you might even use!

Well, here we go. I've decided to only go over bits of the code that are significant, since most of the code has been repeated so far in the series. Check out the full source code in the download. One more thing: this tutorial will be using vectors from the Standard Template Library, so make sure you have it installed and have at least a little knowledge of it's operation. I will not cover the STL here because this is an OpenAL tutorial.

 
 
//  These index the buffers.
#define  THUNDER     0
#define  WATERDROP   1
#define  STREAM      2
#define  RAIN        3
#define  CHIMES      4
#define  OCEAN       5
#define  NUM_BUFFERS 6


//  Buffers hold sound data.
ALuint Buffers[NUM_BUFFERS];

//  A vector list of sources for multiple emissions.
vector < ALuint >  Sources;

First I've written out a few macros that we can use to index the buffer array. We will be using several wav files so we need quite a few buffers here. Instead of using an array for storing the sources we will use an STL vector. We chose to do this because it allows us to have a dynamic number of sources. We can just keep adding sources to the scene until OpenAL runs out of them. This is also the first tutorial where we will deal with sources as being a resource that will run out. And yes, they will run out; they are finite.

 
 
ALboolean InitOpenAL()
{
    ALCdevice
* pDevice;
    ALCcontext
* pContext;
    ALCubyte
* deviceSpecifier;
    ALCubyte deviceName[] 
= "DirectSound3D";

    
// Get handle to device.
    pDevice = alcOpenDevice(deviceName);

    
// Get the device specifier.
    deviceSpecifier = alcGetString(pDevice, ALC_DEVICE_SPECIFIER);

    printf(
"Using device '%s'. ", szDeviceSpecifier);

    
// Create audio context.
    pContext = alcCreateContext(pDevice, NULL);

    
// Set active context.
    alcMakeContextCurrent(pContext);

    
// Check for an error.
    if (alcGetError() != ALC_NO_ERROR)
        
return AL_FALSE;

    
return AL_TRUE;
}

This is some sample code from what we learned in the last tutorial. We get a handle to the device "DirectSound3D", and then obtain a rendering context for our application. This context is set to current and the function will check if everything went smoothly before we return success.

 
 
void  ExitOpenAL()
{
    ALCcontext
* pCurContext;
    ALCdevice
* pCurDevice;

    
// Get the current context.
    pCurContext = alcGetCurrentContext();

    
// Get the device used by that context.
    pCurDevice = alcGetContextsDevice(pCurContext);

    
// Reset the current context to NULL.
    alcMakeContextCurrent(NULL);

    
// Release the context and the device.
    alcDestroyContext(pCurContext);
    alcCloseDevice(pCurDevice);
}

This will do the opposite we did in the previous code. It retrieves the context and device that our application was using and releases them. It also sets the current context to NULL (the default) which will suspend the processing of any data sent to OpenAL. It is important to reset the current context to NULL or else you will have an invalid context trying to process data. The results of doing this can be unpredictable.

If you are using a multi-context application you may need to have a more advanced way of dealing with initialization and shutdown. I would recommend making all devices and contexts global and closing them individually, rather than retrieving the current context.

 
 
ALboolean LoadALData()
{
    
// Variables to load into.
    ALenum format;
    ALsizei size;
    ALvoid
* data;
    ALsizei freq;
    ALboolean loop;

    
// Load wav data into buffers.
    alGenBuffers(NUM_BUFFERS, Buffers);

    
if(alGetError() != AL_NO_ERROR)
        
return AL_FALSE;

    alutLoadWAVFile(
"wavdata/thunder.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[THUNDER], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    alutLoadWAVFile(
"wavdata/waterdrop.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[WATERDROP], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    alutLoadWAVFile(
"wavdata/stream.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[STREAM], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    alutLoadWAVFile(
"wavdata/rain.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[RAIN], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    alutLoadWAVFile(
"wavdata/ocean.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[OCEAN], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    alutLoadWAVFile(
"wavdata/chimes.wav"&format, &data, &size, &freq, &loop);
    alBufferData(Buffers[CHIMES], format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

    
// Do another error check and return.
    if (alGetError() != AL_NO_ERROR)
        
return AL_FALSE;

    
return AL_TRUE;
}

We've totally removed the source generation from this function. That's because from now on we will be initializing the sources separately.

 
 
void  AddSource(ALint type)
{
    ALuint source;

    alGenSources(
1&source);

    
if (alGetError() != AL_NO_ERROR)
    
{
        printf(
"Error generating audio source.");
        exit(
-1);
    }


    alSourcei (source, AL_BUFFER,   Buffers[type]);
    alSourcef (source, AL_PITCH,    
1.0          );
    alSourcef (source, AL_GAIN,     
1.0          );
    alSourcefv(source, AL_POSITION, SourcePos    );
    alSourcefv(source, AL_VELOCITY, SourceVel    );
    alSourcei (source, AL_LOOPING,  AL_TRUE      );

    alSourcePlay(source);

    Sources.push_back(source);
}

Here's the function that will generate the sources for us. This function will generate a single source for any one of the loaded buffers we generated in the previous source. Given the buffer index 'type', which is one of the macros we created right from the start of this tutorial. We do an error check to make sure we have a source to play (like I said, they are finite). If a source cannot be allocated then the program will exit.

 
 
void  KillALData()
{
    
for (vector<ALuint>::iterator iter = Sources.begin(); iter != Sources.end(); ++iter)
        alDeleteSources(
1, iter);
    Sources.clear();
    alDeleteBuffers(NUM_BUFFERS, Buffers);
    ExitOpenAL();
}

This function has been modified a bit to accommodate the STL list. We have to delete each source in the list individually and then clear the list which will effectively destroy it.

 
 
    ALubyte c  =   '   ' ;

    
while  (c  !=   ' q ' )
    
{
        c 
= getche();

        
switch (c)
        
{
            
case 'w': AddSource(WATERDROP); break;
            
case 't': AddSource(THUNDER);   break;
            
case 's': AddSource(STREAM);    break;
            
case 'r': AddSource(RAIN);      break;
            
case 'o': AddSource(OCEAN);     break;
            
case 'c': AddSource(CHIMES);    break;
        }
;
    }

Here is the programs inner loop taken straight out of our main. Basically it waits for some keyboard input and on certain key hits it will create a new source of a certain type and add it to the audio scene. Essentially what we have created here is something like one of those nature tapes that people listen to for relaxation. Ours is a little better since it allows the user to customize which sounds that they want in the background. Pretty neat eh? I've been listening to mine while I code. It's a Zen experience (I'm listening to it right now).

The program can be expanded for using more wav files, and have the added feature of placing the sources around the scene in arbitrary positions. You could even allow for sources to play with a given frequency rather than have them loop. However this would require GUI routines that go beyond the scope of the tutorial. A full featured "Weathering Engine" would be a nifty program to make though. ;)

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值