无法让 OpenAL 播放声音

Posted

技术标签:

【中文标题】无法让 OpenAL 播放声音【英文标题】:Cannot get OpenAL to play sound 【发布时间】:2014-08-15 03:10:21 【问题描述】:

我已经搜索过网络,我已经搜索过这里。我找到了可以编译的代码,并且工作正常,但由于某种原因,我的代码不会产生任何声音。我正在将一个旧游戏移植到 PC (Windows) 上,并且我试图让它尽可能真实,所以我想使用生成的波形。我几乎复制并粘贴了工作代码(仅添加多个声音),但它仍然无法工作(即使认为单个声音的完全相同的代码也可以正常工作。)我知道我错过了一些明显的东西,但我就是不知道是什么。任何帮助将不胜感激。

首先是一些笔记...我正在寻找可以让我使用原始方法的东西。最初的系统使用配对字节来播放音乐(声音效果 - 只有 2 个 - 在代码中处理。)每次调用例程时都会倒计时的时间字节,以及播放直到时间为零的音符字节。这是通过修补中断向量来完成的,windows不允许这样做,所以我设置了一个定时器,路由完成同样的事情。计时器启动,更新显示,然后运行音乐序列。我设置了一个定义的时间,这样我只有一个地方可以调整时间(让它尽可能接近原始序列。音乐是一种生成的波形(我已经仔细检查了数学,甚至在调试模式下检查了生成的数据,)看起来不错。序列看起来不错,但实际上并没有发出声音。我先尝试了SDL2,它只播放1个声音的方法对我也不起作用,除非我使样本持续时间非常短(并且以这种方式产生的声音很糟糕,)我无法匹配时间(它通过自己的中断播放整个样本,而不让我进行调整。)此外,混合 3 个声音一起(当它们都以不同的时间运行时)是一团糟。我检查过的大多数其他引擎的工作方式大致相同,他们想使用自己的回调中断并且不允许我适当地调整它。这是为什么我开始使用 OpenAL。它允许多种声音(来源)并允许我自己设定时间。根据几个论坛的建议,我将其设置为样本长度都是完整周期的倍数。 无论如何,这是代码。

int main(int argc, char* argv[])

    FreeConsole();  //Get rid of the DOS console, don't need it
    if (InitLog() < 0) return -1;   //Start logging

    UINT_PTR tim = NULL;
    SDL_Event event;


    InitVideo(false);   //Set to window for now, will put options in later
    curmusic = 5;
    InitAudio();

    SetTimer(NULL,tim,_FREQ_,TimerProc);

    SDL_PollEvent(&event);
    while (event.type != SDL_KEYDOWN) SDL_PollEvent(&event);

    SDL_Quit();
    return 0;


void CALLBACK TimerProc(HWND hWind, UINT Msg, UINT_PTR idEvent, DWORD dwTime)

    RenderOutput();
    PlayMusic();
    //UpdateTimer();
    //RotateGate();
    return;


void InitAudio(void)

    ALCdevice *dev;
    ALCcontext *cxt;

    Log("Initializing OpenAL Audio\r\n");
    dev = alcOpenDevice(NULL);
    if (!dev) 
        Log("Failed to open an audio device\r\n");
        exit(-1);
    
    cxt = alcCreateContext(dev, NULL);
    alcMakeContextCurrent(cxt);
    if(!cxt) 
        Log("Failed to create audio context\r\n");
        exit(-1);
    
    alGenBuffers(4,Buffer);
    if (alGetError() != AL_NO_ERROR) 
        Log("Error during buffer creation\r\n");
        exit(-1);
    
    alGenSources(4, Source);
    if (alGetError() != AL_NO_ERROR) 
        Log("Error during source creation\r\n");
        exit(-1);
    

    return;


void PlayMusic()

    static int oldsong, ofset, mtime[4];
    double freq;
    ALuint srate = 44100;
    ALuint voice, i, note, len, hold;
    short buf[4][_BUFFSIZE_];
    bool test[4] = false, false, false, false;

    if (curmusic != oldsong) 
        oldsong = (int)curmusic;
        if (curmusic > 0)
            ofset = moffset[(curmusic - 1)];
        for (voice = 1; voice < 4; voice++)
            alSourceStop(Source[voice]);
            mtime[voice] = 0;
        return;
    

    if (curmusic == 0) return;
                                            //Only 3 voices for music, but have
    for (voice = 0; voice < 3; voice ++)   // 4 set asside for eventual sound effects
        if (mtime[voice] == 0)                 //is note finished
            alSourceStop(Source[voice]);  //It is, so stop the channel (source)
            mtime[voice] = music[ofset++];      //Get the next duration
            if (mtime[voice] == 0) oldsong = 0; return;  //zero marks end, so restart
            note = music[ofset++];              //Get the next note
            if (note > 127)            //Old HW data was designed for could only
                if (note == 255) note = 127;    //use values 128 - 255 (255 = 127)
                freq = (15980 / (voice + (int)(voice / 3))) / (256 - note);  //freq of note
                len = (ALuint)(srate / freq);   //A single cycle of that freq.
                hold = len;
                while (len < (srate / (1000 / _FREQ_))) len += hold;  //Multiply till 1 interrup cycle
                while (len > _BUFFSIZE_) len -= hold; //Don't overload buffer
                if (len == 0) len = _BUFFSIZE_; //Just to be safe
                for (i = 0; i < len; i++)   //calculate sine wave and put in buffer
                    buf[voice][i] = (short)((32760 * sin((2 * M_PI * i * freq) / srate)));
                alBufferData(Buffer[voice], AL_FORMAT_MONO16, buf[voice], len, srate);
                alSourcei(openAL.Source[i], AL_LOOPING, AL_TRUE);
                alSourcei(Source[i], AL_BUFFER, Buffer[i]);
                alSourcePlay(Source[voice]);
           
         else --mtime[voice];
    

【问题讨论】:

在任何人遇到之前(纠正除以零问题没有帮助 - 最初是语音 1 - 3,为音效留出零。)在更改为 0 - 3 后复制了代码测试目的,但在我纠正除以零问题之前。对此感到抱歉。 TimerProc 被 _beginthread 取代,因为 TimerProc 似乎只想在我的测试等待循环中运行(只是循环直到我按下一个键。)它在那里工作得很好。如果我将正弦波保存到一个文件中,然后用媒体播放器打开它,听起来不错(虽然声音不大),所以我生成了正确的频率,而且我的中断时间非常接近。不过还是发不出声音。 【参考方案1】:

好吧,事实证明我的代码存在 3 个问题。首先,在将缓冲区链接到源之前,您必须将构建的波形缓冲区链接到 AL 生成的缓冲区:

alBufferData(buffer,AL_FORMAT_MONO16,&wave_sample,sample_lenght * sizeof(short),frequency);
alSourcei(source,AL_BUFFER,buffer);

同样在上面的示例中,我将 sample_length 乘以每个样本中的字节数(在本例中为“sizeof(short)”。

最后一个问题是,在更改缓冲区数据之前,您需要从源中取消链接缓冲区

alSourcei(source,AL_BUFFER,NULL);

在我将该行添加到音符更改代码之前,音乐会播放,但不能正确播放。

【讨论】:

抱歉,将取消链接代码更改为“NULL”而不是缓冲区。

以上是关于无法让 OpenAL 播放声音的主要内容,如果未能解决你的问题,请参考以下文章

OpenAL vs AVAudioPlayer vs 其他播放声音的技术

打开 al 声音在来电后不播放,直到应用重新启动

在 Mac 上使用 OpenAL 播放音频时出现随机噪音

OpenAL播放捕获的音频数据c ++

AudioServices (Easy), AVAudioPlayer (Medium), OpenAL (Hard & Overkill?)

iOS OpenAL 声音不是定位的