Cannot get OpenAL to play sound
我已经搜索了网络,我已经搜索了这里。我找到了可以编译的代码,并且可以正常运行,但是由于某种原因,我的代码无法发出任何声音。我正在将旧游戏移植到PC(Windows)上,并且试图使其尽可能地真实,因此我想使用生成的波形。我已经复制并粘贴了有效的代码(仅添加了多种声音),但仍然无法正常工作(甚至认为对于单个声音使用完全相同的代码也能正常工作。)我知道我丢失了显而易见的东西,但是我无法弄清楚是什么。任何帮助将不胜感激谢谢。
首先要注意的是...我正在寻找可以使我使用原始方法的东西。原始系统使用成对的字节来播放音乐(声音效果-只有2个-用代码处理)。一个时间字节在每次调用该例程时都会递减计数,而一个音符字节将一直播放到时间达到零为止。这是通过修补中断向量来完成的,Windows不允许这样做,所以我设置了一个计时器来完成相同的任务。计时器开始计时,更新显示,然后运行音乐序列。我将其设置为规定的时间,这样我就只能在一个位置调整时间(使其尽可能接近原始音序。音乐是一种产生的波形(我已经仔细检查了数学,甚至在调试模式下检查了生成的数据),它看起来不错。序列看起来不错,但实际上并没有产生声音。我首先尝试了SDL2,而它只播放1种声音的方法却没有同样,这对我也不起作用,除非我使采样持续时间非常短(并且以这种方式产生的声音很糟糕),否则我无法匹配时间(它会通过自己的中断播放整个采样而不会让我此外,将这三种声音混合在一起(当它们都以不同的时间运行时)也很混乱。我检查过的大多数其他引擎的工作方式几乎相同,他们想使用自己的回调中断并赢得\\我不允许对其进行适当的调整。这就是为什么我开始使用OpenAL的原因。它允许多种声音(来源)并允许我自己设定时间。根据几个论坛的建议,我对其进行了设置,以使样本长度全部为完整周期的倍数。
无论如何,这是代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 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\ \ "); dev = alcOpenDevice(NULL); if (!dev) { Log("Failed to open an audio device\ \ "); exit(-1); } cxt = alcCreateContext(dev, NULL); alcMakeContextCurrent(cxt); if(!cxt) { Log("Failed to create audio context\ \ "); exit(-1); } alGenBuffers(4,Buffer); if (alGetError() != AL_NO_ERROR) { Log("Error during buffer creation\ \ "); exit(-1); } alGenSources(4, Source); if (alGetError() != AL_NO_ERROR) { Log("Error during source creation\ \ "); 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]; } } |
好吧,事实证明我的代码有3个问题。首先,必须将内置的wave缓冲区链接到AL生成的缓冲区" before ",然后将缓冲区链接到源:
1 2 | alBufferData(buffer,AL_FORMAT_MONO16,&wave_sample,sample_lenght * sizeof(short),frequency); alSourcei(source,AL_BUFFER,buffer); |
同样在上面的示例中,我将sample_length乘以每个样本中的字节数(在本例中为" sizeof(short)"。
最后的问题是,在更改缓冲区数据之前,需要先断开缓冲区与源的链接
1 | alSourcei(source,AL_BUFFER,NULL); |
音乐会播放,但是要正确播放,直到我将该行添加到音符更改代码中为止。