openal教程(三)

来源:互联网 发布:阿蒂仙 梵音藏心 知乎 编辑:程序博客网 时间:2024/05/12 23:12

原文:http://bbs.gameres.com/thread_12728.html

openal教程(三)
   多源
   
   你好,在这一章中,我们将在上一章的例程中加入一些元素,使他能同时
   播放超过一种的音乐。
   通常在一个优秀的游戏中有各种不同的音夹(clip),这是怎样实现的呢?
   下面将介绍。
   #include <conio.h>
#include <time.h>
#include <stdlib.h>
#include <al/al.h>
#include <al/alc.h>
#include <al/alu.h>
#include <al/alut.c>

// 我们需要的最大的数据缓冲.
#define NUM_BUFFERS 3

// 我们需要放三种声音.
#define NUM_SOURCES 3

// 缓冲和源标志.
#define BATTLE      0
#define GUN1        1
#define GUN2        2

// 存储声音数据.
ALuint Buffers[NUM_BUFFERS];

// 用于播放声音.
ALuint Sources[NUM_SOURCES];

// 源声音的位置.
ALfloat SourcesPos[NUM_SOURCES][3];

// 源声音的速度.
ALfloat SourcesVel[NUM_SOURCES][3];


// 听者的位置.
ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };

// 听者的速度.
ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };

// 听者的方向 (first 3 elements are "at", second  3 are "up")
ALfloat ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };

在这一章中,唯一的不同是多了3种将导入Openal系统的不同的声音效果 。

ALboolean LoadALData()
{
    // 载入变量.

    ALenum format;
    ALsizei size;
    ALvoid* data;
    ALsizei freq;
    ALboolean loop;

    // 载入WAV数据.

    alGenBuffers(NUM_BUFFERS, Buffers);

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

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

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

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

    // 捆绑源.

    alGenSources(NUM_SOURCES, Sources);

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

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

    alSourcei (Sources[GUN1], AL_BUFFER,   Buffers[GUN1]  );
    alSourcef (Sources[GUN1], AL_PITCH,    1.0            );
    alSourcef (Sources[GUN1], AL_GAIN,     1.0            );
    alSourcefv(Sources[GUN1], AL_POSITION, SourcePos[GUN1]);
    alSourcefv(Sources[GUN1], AL_VELOCITY, SourceVel[GUN1]);
    alSourcei (Sources[GUN1], AL_LOOPING,  AL_FALSE       );

    alSourcei (Sources[GUN2], AL_BUFFER,   Buffers[GUN2]  );
    alSourcef (Sources[GUN2], AL_PITCH,    1.0            );
    alSourcef (Sources[GUN2], AL_GAIN,     1.0            );
    alSourcefv(Sources[GUN2], AL_POSITION, SourcePos[GUN2]);
    alSourcefv(Sources[GUN2], AL_VELOCITY, SourceVel[GUN2]);
    alSourcei (Sources[GUN2], AL_LOOPING,  AL_FALSE       );

    // 做错误检测并返回

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

    return AL_TRUE;
}
首先,我们导入文件数据到3个缓冲区,然后把3个缓冲区和3个源锁在
一起。唯一的不同是文件“battle.wav”在不停止时循环。
void SetListenervalues()
{
    alListenerfv(AL_POSITION,    ListenerPos);
    alListenerfv(AL_VELOCITY,    ListenerVel);
    alListenerfv(AL_ORIENTATION, ListenerOri);
}

void KillALData()
{
    alDeleteBuffers(NUM_BUFFERS, &Buffers[0]);
    alDeleteSources(NUM_SOURCES, &Sources[0]);
    alutExit();
}
在这段代码中,我们没有改变。
int main(int argc, char *argv[])
{
    // Initialize OpenAL and clear the error bit.
    alutInit(NULL, 0);
    alGetError();

    // Load the wav data.
    if (LoadALData() == AL_FALSE)
        return 0;

    SetListenervalues();

    // Setup an exit procedure.
    atexit(KillALData);

    // Begin the battle sample to play.
    alSourcePlay(Sources[BATTLE]);

    // Go through all the sources and check that they are playing.
    // Skip the first source because it is looping anyway (will always be playing).
    ALint play;

    while (!kbhit())
    {
        for (int i = 1; i < NUM_SOURCES; i++)
        {
                alGetSourcei(Sources[i], AL_SOURCE_STATE, &play);

                if (play != AL_PLAYING)
                {
                    // Pick a random position around the listener to play the source.

                double theta = (double) (rand() % 360) * 3.14 / 180.0;

                SourcePos[i][0] = -float(cos(theta));
                SourcePos[i][1] = -float(rand()%2);
                SourcePos[i][2] = -float(sin(theta));

                alSourcefv(Sources[i], AL_POSITION, SourcePos[i] );

                alSourcePlay(Sourcev[i]);
            }
        }
    }

    return 0;
}
这段是这篇文章最有趣的地方。我们在这里将播放。如果他不播放,我们将
在3D空间中选一个点播放(点击)。
And bang! We are done. As most of you have probably seen, 
you don't have to do anything special to play more than one source at a time. 
OpenAL will handle all the mixing features to get the sounds right for their 
respective distances and velocities. And when it comes right down to it, 
isn't that the beauty of OpenAL?
You know that was a lot easier than I thought. I don't know why I waited so long
 to write it. Anyway, if anyone reading wants to see something specific in future 
tutorials (not necessarily pertaining to OpenAL, I have quite an extensive knowledge base)
 drop me a line at lightonthewater@hotmail.com I plan to do tutorials on sharing 
buffers and the Doppler effect in some later tutorial unless there is request for 
something else. Have fun with the code!