OpenAL快速入门教程

来源:互联网 发布:c 常量数组初始化 编辑:程序博客网 时间:2024/06/02 11:54

转发,原文地址:OpenAL快速入门教程


OpenAL快速入门
1. 为什么使用OpenAL
也许你已经用过AudioToolbox框架并用以下代码来播放一个音乐文件:
  1. NSString* path = [[NSBundle mainBundle] pathForResource:@"soundEffect1" ofType:@"caf"];
  2. NSURL * afUrl = [NSURL fileURLWithPath:path];
  3. UInt32 soundID;
  4. AudioServicesCreateSystemSoundID((CFURLRef)afUrl,&soundID);
  5. AudioServicesPlaySystemSound (soundID);
复制代码
这种播放方式很简单,但它每次都需要把音乐文件加载到缓存中,降低了播放的效率。当你需要实时播放的时候,它往往出现延时。而使用OpenAL将最大限度的减少这种延时,提供最佳播放效率。
2. 声音格式转换
为了节省iPhone在播放音乐时进行音频格式转换的时间,你可以手动对文件进行格式转换。
打开终端,输入以下命令:
  1. /usr/bin/afconvert -f caff -d LEI16@44100 inputSoundFile.aiff outputSoundFile.caf
复制代码
上述命令利用afconverter工具将inputSoundFile.aiff转换成了outputSoundFile.caf,采样频率为4.41k。
3. 这是一个快速的入门教程,将教你使用OpenAL播放音乐的最少步骤。
OpenAL主要由3个实体构成:听众Listener, 声源Source, 以及缓存Buffer。
听众Listener:就是你。Listener的位置是可以移动的。
声源Source:类似一个话筒。它发出声音给听众听。和Listener一样,声源的位置也是可以移动的。例如oalTouch中实现了声音远近的控制(近响远轻),就是通过Listener和Source两张图片之间的距离实现的。
缓存Buffer:存着原始声音数据,就是你需要播放的声音。

还有2个重要的对象:设备device和环境context。
设备是播放声音的硬件。
环境是声源和听众所在的空间。

让OpenAL工作所需的最少步骤是:
  1. 1. 得到设备信息
  2. 2. 将环境与设备关联
  3. 3. 在缓存中加入声音数据
  4. 4. 在声源中加入缓存数据
  5. 5. 播放声源
复制代码
以下是相关代码:
  1. -(void)initOpenAL
  2. {
  3.         // Initialization
  4.         mDevice = alcOpenDevice(NULL); // select the "preferred device"
  5.         if (mDevice) {
  6.                 // use the device to make a context
  7.                 mContext=alcCreateContext(mDevice,NULL);
  8.                 // set my context to the currently active one
  9.                 alcMakeContextCurrent(mContext);
  10.         }
  11. }
复制代码
上述代码初始化了设备device和环境context。
接下去要打开声音文件。
  1. // get the full path of the file
  2. NSString* fileName = [[NSBundle mainBundle] pathForResource:@"neatoEffect" ofType:@"caf"];
  3. // first, open the file
  4. AudioFileID fileID = [self openAudioFile:fileName];
复制代码
上述代码打开了一个叫neatoEffect.caf的声音文件,并且得到了它的ID。
openAudioFile方法的实现在哪里?
  1. -(AudioFileID)openAudioFile:(NSString*)filePath
  2. {
  3.         AudioFileID outAFID;
  4.         // use the NSURl instead of a cfurlref cuz it is easier
  5.         NSURL * afUrl = [NSURL fileURLWithPath:filePath];
  6.          OSStatus result = AudioFileOpenURL((CFURLRef)afUrl, kAudioFileReadPermission, 0, &outAFID);
  7.         if (result != 0) NSLog(@"cannot openf file: %@",filePath);
  8.         return outAFID;
  9. }
复制代码
这个方法中调用AudioFileOpenURL得到了一个AudioFileID outAFID。
接下去做什么?把声音数据读出来。

为了读取声音数据,先要知道数据的大小。
可以调用这个方法:
  1. // find out how big the actual audio data is
  2. UInt32 fileSize = [self audioFileSize:fileID];
复制代码
audioFileSize它的实现文件是:
  1. -(UInt32)audioFileSize:(AudioFileID)fileDescriptor
  2. {
  3.         UInt64 outDataSize = 0;
  4.         UInt32 thePropSize = sizeof(UInt64);
  5.         OSStatus result = AudioFileGetProperty(fileDescriptor, kAudioFilePropertyAudioDataByteCount, &thePropSize, &outDataSize);
  6.         if(result != 0) NSLog(@"cannot find file size");
  7.         return (UInt32)outDataSize;
  8. }
复制代码
得到了声音数据的大小,我们可以把数据复制到缓存buffer里了:
  1. // this is where the audio data will live for the moment
  2. unsigned char * outData = malloc(fileSize);

  3. // this where we actually get the bytes from the file and put them
  4. // into the data buffer
  5. OSStatus result = noErr;
  6. result = AudioFileReadBytes(fileID, false, 0, &fileSize, outData);
  7. AudioFileClose(fileID); //close the file

  8. if (result != 0) NSLog(@"cannot load effect: %@",fileName);

  9. NSUInteger bufferID;
  10. // grab a buffer ID from openAL
  11. alGenBuffers(1, &bufferID);

  12. // jam the audio data into the new buffer
  13. alBufferData(bufferID,AL_FORMAT_STEREO16,outData,fileSize,44100);
复制代码
这段有点长,其实还好啦。首先我们为声音数据创建了一个空间outData,然后用AudioFileReadBytes将声音数据读到了这个空间里。接下去,把空间里的数据复制到了缓存buffer里。44100表示音频的采样频率4.41k,STEREO16表示16位立体声格式。

复制完数据,别忘了清空这个outData空间:
  1. // clean up the buffer
  2. if (outData)
  3. {
  4.         free(outData);
  5.         outData = NULL;
  6. }
复制代码
最后我们可以将buffer和声源source绑定了。
  1. // grab a source ID from openAL
  2. alGenSources(1, &sourceID); 
  3. // attach the buffer to the source
  4. alSourcei(sourceID, AL_BUFFER, bufferID);
  5. // set loop sound
  6. if (loops) alSourcei(sourceID, AL_LOOPING, AL_TRUE);
复制代码
差不多完成了,我们播放声源吧:
  1. - (void)playSound:(NSString*)soundKey
  2. {
  3.         alSourcePlay(sourceID);
  4. }
复制代码
要停下怎么办?
  1. - (void)stopSound:(NSString*)soundKey
  2. {
  3.         alSourceStop(sourceID);
  4. }
复制代码
最后,退出前别忘了把所有东西都释放:
  1. -(void)cleanUpOpenAL:(id)sender
  2. {
  3.         // delete the sources
  4.         alDeleteSources(1, &sourceID);
  5.         // delete the buffers
  6.         alDeleteBuffers(1, &bufferID);
  7.         // destroy the context
  8.         alcDestroyContext(mContext);
  9.         // close the device
  10.         alcCloseDevice(mDevice);
  11. }
复制代码
原文网址:
http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/
你们还可以看看这个(同一位作者关于AudioSession的文章):
http://benbritten.com/2009/02/02 ... one/comment-page-1/