SDL在默认情况下,只支持WAV格式,如果要播放其他格式的文件我们能采用SDL_mixer,他支持WAV,MP3,MIDI,OGG,MOD,如果要支持更多的文件格式,我们就不得不采用其他库了.
一. SDL 下播放WAV 格式的声音文件.
1 步骤:
(1) 打开WAV文件,将WAV文件中的声音数据全部拷贝到内存.
(2) 设置播放参数(采样率,比特数,声道),分配内存,将(1)中获得的数据转换成前面设置格式,将转换后的数据保存到所分配的内存中.
(3) 关闭声音文件.
(4) 打开声音设备,并设置参数,这里的参数跟(2)中设置的播放参数一致,并设置回掉函数,回调函数用于在播放每一帧数据之前,对其进行处理.
(5) 开始播放
(6) 播放完成后释放(2)中所分配的内存.
(7) 关闭声音设备.
example:
#define NUM_SOUNDS 2 struct sample { Uint8 *data; Uint32 dpos; Uint32 dlen; } sounds[NUM_SOUNDS]; //this is callback function,it is executed in separate thread. void mixaudio(void *unused, Uint8 *stream, int len) { int i; Uint32 amount; for ( i=0; i len ) { amount = len; } //convert original sound data from wav file to destnation format SDL_MixAudio(stream, &sounds.data[sounds.dpos], amount, SDL_MIX_MAXVOLUME); sounds.dpos += amount; } } int Open_Audio() { SDL_AudioSpec fmt; //open audio device and set properties fmt.freq = 22050; fmt.format = AUDIO_S16; fmt.channels = 2; fmt.samples = 512; fmt.callback = mixaudio; fmt.userdata = NULL; if ( SDL_OpenAudio(&fmt, NULL) < 0 ) { debug("无法打开音频: %s\n", SDL_GetError()); return -1; } //begin play SDL_PauseAudio(0); } void PlaySound(char *file) { int index; SDL_AudioSpec wave; Uint8 *data; Uint32 dlen; SDL_AudioCVT cvt; //find an empty sound port for ( index=0; index<NUM_SOUNDS; ++index ) { if ( sounds[index].dpos == sounds[index].dlen ) { break; } } if ( index == NUM_SOUNDS ) return; //load wav file, and copy sound data to buffer if ( SDL_LoadWAV(file, &wave, &data, &dlen) == NULL ) { debug("call SDL_LoadWAV failed\n"); return; } //build audio convertion struct SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq,AUDIO_S16,2,22050); //build cvt.buf, and copy sound data to this buffer,then free sound data buffer cvt.buf = (Uint8 *)malloc(dlen*cvt.len_mult); memcpy(cvt.buf, data, dlen); cvt.len = dlen; SDL_ConvertAudio(&cvt); SDL_FreeWAV(data); //free history sound buffer,it is equal to cvt.buf if ( sounds[index].data ) { free(sounds[index].data); } //protect resource which will be used in thread mixaudio SDL_LockAudio(); sounds[index].data = cvt.buf; sounds[index].dlen = cvt.len_cvt; sounds[index].dpos = 0; SDL_UnlockAudio(); //open audio to play Open_Audio(); }
播放时,调用函数PlaySound()即可,如:
PlaySound("test.wav);
注意:
(1) 由于回调函数是在一个独立的线程中执行的,所以要注意保护资源,本例中的SDL_LockAudio,SDL_UnlockAudio正是起这样的作用
(2) 由于SDL一次将WAV文件中全部数据都拷贝到内存中,所以这种播放方式只适合较小的WAV文件的播放.
二. SDL_mixer.
前面说了,SDL默认情况下只支持WAV格式的声音文件,如果要播放更多格式的生硬文件,我们可以采用SDL_mixer库,他虽然只支持WAV, MP3,MIDI,OGG,MOD这几种格式,但对于我们平常作游戏,普通界面,完全够用了.
1. 操作步骤.
其实,SDL_mixer的操作步骤非常简单,甚至比直接用SDL播放WAV文件都要简单的多.
(1) 打开声音设备,设置播放参数(采样率,帧格式--位数,声道--单声道双声道,帧队列的数量)
(2) 打开声音文件.
(3) 播放.播放是异步的,它在一个单独的线程中执行.在播放过程中,我们可以暂停,恢复,重新播放,快进快退,停止播放.可以以渐强的方式开始播放,以渐弱的声音停止播放.
(4) 关闭声音设备
example
int Sound_Init() { const int TMP_FREQ = MIX_DEFAULT_FREQUENCY; const Uint16 TMP_FORMAT = MIX_DEFAULT_FORMAT; const int TMP_CHAN = 2; const int TMP_CHUNK_SIZE = 512; return Mix_OpenAudio(TMP_FREQ,TMP_FORMAT,TMP_CHAN,TMP_CHUNK_SIZE); } int Sound_Play(const char *file_name) { Mix_Music *mix_music; if((mix_music = Mix_LoadMUS(file_name)) == NULL) { printf("call Mix_LoadMUS failed:%s/n",Mix_GetError()); return -1; } if(Mix_PlayMusic(mix_music,-1) == -1) { printf("call Mix_PlayMusic failed/n"); return -1; } printf("after call Mix_PlayMusic/n"); return 0; }
播放时调用
Sound_Init();
Sound_Play("123.mp3");
即可,
3.同时播放多个声音.
在游戏中,我们经常遇到的是一边在播放背景音,当执行某些操作时(如射击,翻车等),又有一个响应的声音,用SDL_mixer也可以做到这一点,就是用 Music和Channel,同时播放两种声音.这种情况下,声音设备只需打开一次.比如,背景音乐以Music形式播放,用Mix_LoadMUS打开,Mix_PlayMusic(或其他同等功能的函数)播放,其他声音全部以Channel的形式.用Mix_LoadWAV打开多个文件,再用Mix_AllocateChannels分配多个通道(Channels),然后用Mix_PlayChannel(或其他同等功能的函数),在不同的通道上播放,每个通道对应一个文件(前面用Mix_LoadWAV打开的文件),这样,就可以同时播放多个(>2)个声音
注意:
(1) 如果需要播放mp3文件,那么在安装SDL_mixer之前,需要安装SMPEG(SDL MPEG),可以从这里ftp://sunsite.auc.dk/pub/os/linux/loki/open-source/smpeg/下载,
安装方式是:
./configure
make LIBS="${LIBS} -lstdc++ -lSDL -lpthread"
(2) 如果需要播放midi文件,需要安装插件timididy,可以从这里http://www.libsdl.org/projects/mixer/timidity/timidity.tar.gz下载,将解压后的文件夹timidity直接拷贝到/usr/local/lib/下即可.
(3) 如果要播放ogg文件,需要安装libogg,可以从这里http://www.xiph.org/ogg/下载
(3) SDL_mixer的安装方法.
a. X86下, ./configure;make;sudo make install;很简单的.但必须先安装SDL.
b. ARM下,自动配置的脚本如下,在配置之前,我们需要修改SDL_PATH,OGG_PATH及PREFIX的值.
#!/bin/sh
SDL_PATH=/apps/src/paragui/paragui_static/install/
PREFIX=/apps/src/paragui/useful_lib/install
OGG_PATH=${PREFIX}
VORBIAS_PATH=${PREFIX}
./configure /
--prefix=${PREFIX} /
--host=arm-linux /
--enable-music-ogg /
--enable-music-wave /
--disable-music-mp3 /
--with-sdl-prefix=${SDL_PATH} /
CC=arm-linux-gcc /
CXX=arm-linux-g++ /
CFLAGS="-I${SDL_PATH}/include /
-I${OGG_PATH}/include/ -I${VORBIAS_PATH}/include/" /
LDFLAGS="-L${SDL_PATH}/lib/ /
-L${OGG_PATH}/lib/ -L${VORBIAS_PATH}/lib/"
然后make;sudo make install即可