Chinaunix首页 | 论坛 | 博客
  • 博客访问: 283679
  • 博文数量: 48
  • 博客积分: 2931
  • 博客等级: 少校
  • 技术积分: 720
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-19 22:12
文章分类

全部博文(48)

文章存档

2012年(1)

2011年(6)

2010年(33)

2009年(5)

2008年(3)

我的朋友

分类:

2010-01-05 13:03:00

Openal教程(六)

Openal教程(六)
高级导入和错误处理
虽然现在,我们能做出一些漂亮的东西,但是这些都没有要求我们精确
的处理他们。原因是我们写的代码是为了便于学习。因此,我们将移进
一些高级的东西。最重要的是我们将学习更高级的处理错误的方法。我们
也将重新改写载入声音数据的方法。
我们首先考虑这些函数将做什么。
string GetALErrorString(ALenum err);
/*
* 1) 识别错误代码
* 2)返回错误
*/


ALuint LoadALBuffer(string path);
/*
* 1) 建立缓冲区
* 2) 导入WAV文件
* 3) 返回缓冲区ID
*/

ALuint GetLoadedALBuffer(string path);
/*
* 1) 检测文件是否载入
* 2) 如果载入,返回缓冲区ID
* 3) 如果失败,重新载入并返回缓冲区ID
*/

ALuint LoadALSample(string path, bool loop);
/*
* 1) 建立源
* 2) 调用‘GtLoadedALBuffer' 中的’PATH‘加载文件?
* 3)返回源ID
*/

void KillALLoadedData();
/*
* 1)释放数据?
*/

bool LoadALData();
/*
* 1) 载入所有的源和缓冲区
*/

void KillALData();
/*
* 1) 释放所有的缓冲区
* 2) 释放所有的源
*/

vector LoadedFiles; // 文件路径
vector Buffers; // 缓冲区.
vector Sources; // 源.

看一下这个函数,想一下他做什么。我们试着建立一个关于缓冲区和源
的系统。我们能调用来自文件的源并且系统能处理缓冲区的建立,因此,
我们不用复制缓冲区。系统将处理缓冲区并且将有效的处理资源。

string GetALErrorString(ALenum err)
{
    switch(err)
    {
        case AL_NO_ERROR:
            return string("AL_NO_ERROR");
        break;

        case AL_INVALID_NAME:
            return string("AL_INVALID_NAME");
        break;

        case AL_INVALID_ENUM:
            return string("AL_INVALID_ENUM");
        break;

        case AL_INVALID_value:
            return string("AL_INVALID_value");
        break;

        case AL_INVALID_OPERATION:
            return string("AL_INVALID_OPERATION");
        break;

        case AL_OUT_OF_MEMORY:
            return string("AL_OUT_OF_MEMORY");
        break;
    };
}
函数的功能是转换错误代码为字符。OPENAL SDK说返回'AL_OUT_OF_MEMORY'
是错误的,我们应认真对待所有错误,使我们的代码用最新的版本处理
数据。
string GetALCErrorString(ALenum err)
{
    switch(err)
    {
        case ALC_NO_ERROR:
            return string("AL_NO_ERROR");
        break;

        case ALC_INVALID_DEVICE:
            return string("ALC_INVALID_DEVICE");
        break;

        case ALC_INVALID_CONTEXT:
            return string("ALC_INVALID_CONTEXT");
        break;

        case ALC_INVALID_ENUM:
            return string("ALC_INVALID_ENUM");
        break;

        case ALC_INVALID_value:
            return string("ALC_INVALID_value");
        break;

        case ALC_OUT_OF_MEMORY:
            return string("ALC_OUT_OF_MEMORY");
        break;
    };
}
这个函数的功能是说明ALC错误。OPENAL和ALC共享ID,但是他们在一些功能上
不相等。
函数 'alGetError'应注意:OPENAL SDK定义一次只能得到一个错误。
当函数被调用时,他返回他得到的第一个错误,并且清错误为'AL_NO_ERROR'
ALuint LoadALBuffer(string path)
{
    // Variables to store data which defines the buffer.
    ALenum format;
    ALsizei size;
    ALvoid* data;
    ALsizei freq;
    ALboolean loop;

    // 缓冲区ID和错误检测变量
    ALuint buffer;
    ALenum result;

    // 产生缓冲区,看他是否成功建立.
    alGenBuffers(1, &buffer);

    if ((result = alGetError()) != AL_NO_ERROR)
        throw GetALErrorString(result);

    // 读WAV数据,检测是否成功。
    alutLoadWAVFile(szFilePath, &format, &data, &size, &freq, &loop);

    if ((result = alGetError()) != AL_NO_ERROR)
        throw GetALErrorString(result);

    // 装载WAV数据,检测是否成功
    alBufferData(buffer, format, data, size, freq);

    if ((result = alGetError()) != AL_NO_ERROR)
        throw GetALErrorString(result);

    // 出去临时数据
    alutUnloadWAV(format, data, size, freq);

    if ((result = alGetError()) != AL_NO_ERROR)
        throw GetALErrorString(result);

    //返回缓冲区ID
    return buffer;
}

在导入数据时,我们做了错误检测。没有任何错误将通过。当数据导入时,
没有足够的内存,WAV文件可能不退出,或者OPENAL函数中的错误数据
将产生错误。
ALuint GetLoadedALBuffer(string path)
{
    int count = 0; // 'count' 表明缓冲区列表

    ALuint buffer; // 用于导入缓冲区的缓冲区ID


    // 重复列表中的每个文件
    for(vector::iterator iter = LoadedFiles.begin(); iter != LoadedFiles.end(); ++iter, count++)
    {
        // 如果文件已经导入,返回他的缓冲区ID.
        if(*iter == path)
            return Buffers[count];
    }

    // 如果文件是新的,我们将为他建立缓冲区.
    buffer = LoadALBuffer(path);

    // 添加缓冲区到列表,记录他已添加.
    Buffers.push_back(buffer);

    LoadedFiles.push_back(path);

    return buffer;
}
人们的麻烦通常在这里,但他确实不是很复杂。我们通过包含文件路径的列表
来检索。如果其中一个符合要求,我们直接返回他的ID到缓冲区。我们通过
这个函数导入我们的文件,这样就避免了复制时的浪费。每个文件应该保证
在自己的列表中。'Buffers'表类士于'LoadedFiles'表。
ALuint LoadALSample(string path, bool loop)
{
    ALuint source;
    ALuint buffer;
    ALenum result;

    // 得到文件缓冲区ID
    buffer = GetLoadedALBuffer(path);

    // 产生源.
    alGenSources(1 &source);

    if ((result = alGetError()) != AL_NO_ERROR)
        throw GetALErrorString(result);

    // 设置源属性.
    alSourcei (source, AL_BUFFER,   buffer   );
    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,  loop     );

    // 保存源ID.
    Sources.push_back(source);

    // 返回源ID.
    return source;
}

现在我们已经建立处理缓冲区的系统,我们需要得到源的伸展。在这里,我们
得到了导入文件的缓冲区ID。这个缓冲区是一个新源,我们保存他并返回。
void KillALLoadedData()
{
    LoadedFiles.clear();
}
'gLoadedFilesv'存储在导入缓冲区的WAV文件的路径下,我们要处理他。
// 源ID's.

ALuint phaser1;
ALuint phaser2;

void LoadALData()
{
    // 你的应用在这里,不用担心缓冲区。
    phaser1 = LoadALSample("wavdata/phaser.wav", false);
    phaser2 = LoadALSample("wavdata/phaser.wav", true);

    KillLoadedALData();
}
他表示用于程序的所有的WAV应用的程序。我们能调用导入相同的WAV文件到不同的源,
'phaser.wav' 的缓冲区建立了一次,'gPhaser1' and 'gPhaser2' 用于背景
音乐的缓冲区。不用处理缓冲区因为系统会自动处理。
void KillALData()
{
    // 释放所有的缓冲区数据.
    for (vector::iterator iter = Buffers.begin(); iter != Buffers.end(); ++iter)
        alDeleteBuffers(1, iter);

    // 释放所有的源数据.
    for (vector::iterator iter = Sources.begin(); iter != Sources.end(); ++iter)
        alDeleteBuffers(1, iter);

    // 清除列表.
    Buffers.clear();
    Sources.clear();
}
我们已完成了前述的工作。然后就是释放他们。
try
    {
        InitOpenAL();

        LoadALData();
    }
    catch(string err)
    {
        cout << "OpenAL error: " << err.c_str() << endl;
    }
如果导入源时出错,我们将改正他。这将借助程序返回的报告。
阅读(1346) | 评论(0) | 转发(0) |
0

上一篇:OpenAL教程(五)

下一篇:OpenAL教程(七)

给主人留下些什么吧!~~