SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。
1.SDL_Init()
函数原型: int SDLCALL SDL_Init(Uint32 flags);
初始化SDL系统,其中flag可以选择的选项有:
/**
*
ame SDL_INIT_*
*
* These are the flags which may be passed to SDL_Init(). You should
* specify the subsystems which you will be using in your application.
*//* @{ */
#define SDL_INIT_TIMER 0x00000001
#define SDL_INIT_AUDIO 0x00000010
#define SDL_INIT_VIDEO 0x00000020/**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
#define SDL_INIT_JOYSTICK 0x00000200/**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */
#define SDL_INIT_HAPTIC 0x00001000
#define SDL_INIT_GAMECONTROLLER 0x00002000/**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
#define SDL_INIT_EVENTS 0x00004000
#define SDL_INIT_NOPARACHUTE 0x00100000/**< Don't catch fatal signals */
#define SDL_INIT_EVERYTHING (
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS |
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER
)
/* @} */
可以根据自己代码里面的需求进行选择,例如只有音频播放,则可以选择SDL_INIT_AUDIO
2.SDL_INIT_AUDIO()
函数原型:int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
SDL_AudioSpec * obtained);
根据提供的参数打开音频设备,其中desired 为期望的音频设备参数, obtained为实际的音频设备参数,一般将其置为NULL即可。
结构体参数如下:
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in samples (power of 2) */
Uint16 padding; /**< Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback;
void *userdata;
} SDL_AudioSpec;
主要的参数含义如下:
freq:采样率,例如44K、16K、48K等。
format:音频数据格式,常见的有如下格式:
#define AUDIO_U16SYS AUDIO_U16LSB#define AUDIO_S16SYS AUDIO_S16LSB#define AUDIO_S32SYS AUDIO_S32LSB#define AUDIO_F32SYS AUDIO_F32LSB
Channels:通道数 1 单声道 2 双声道
silence:用于将缓冲区设置为静默的值,由SDL_OpenAudio()计算
Samples:音频缓冲区所需大小,必需是2的n次方
Size:音频缓冲区的大小
Callback:音频回调函数
userdata:作为回调函数的第一个参数传递。
其中,音频回调函数的原型为:
typedefvoid (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream, int len);
当开始播放音频的时候,如果音频设备需要音频数据,就会调用此接口用来获取音频数据,
其中,stream是指向音频数据缓冲区的指针,len则为数据的长度。
另外,在SDL2中必须首先使用SDL_memset()将stream中的数据设置为0。
在这个回调函数中,既可以直接将音频数据赋给stream,也可以调用其他函数进行一些音频操作,例如调用SDL_MixAudio进行混音。
3.SDL_PauseAudio
函数原型: void SDLCALL SDL_PauseAudio(int pause_on);
这个函数用于暂停或者取消暂停音频回调处理,当我们开始播放音频的时候,需要pause_on设置为0即可,当设置为1的时候,则不会调用回调函数,即为静音状态。
三、测试代码
测试代码使用的是雷博的代码,在回调函数中没有采用混音,直接将音频数据赋值给stream。
/**
* 最简单的SDL2播放音频的例子(SDL2播放PCM)
* Simplest Audio Play SDL2 (SDL2 play PCM)
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图
* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层
* API。
*
* 函数调用步骤如下:
*
* [初始化]
* SDL_Init(): 初始化SDL。
* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。
* SDL_PauseAudio(): 播放音频数据。
*
* [循环播放数据]
* SDL_Delay(): 延时等待播放完成。
*
* This software plays PCM raw audio data using SDL2.
* SDL is a wrapper of low-level API (DirectSound).
* Use SDL is much easier than directly call these low-level API.
*
* The process is shown as follows:
*
* [Init]
* SDL_Init(): Init SDL.
* SDL_OpenAudio(): Opens the audio device with the desired
* parameters (In SDL_AudioSpec).
* SDL_PauseAudio(): Play Audio.
*
* [Loop to play data]
* SDL_Delay(): Wait for completetion of playback.
*/#include //#include extern"C"
{
#include "sdl/SDL.h"
};
//Buffer://|-----------|-------------|//chunk-------pos---len-----|static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;
/* Audio Callback
* The audio function callback takes the following parameters:
* stream: A pointer to the audio buffer to be filled
* len: The length (in bytes) of the audio buffer
*
*/void fill_audio(void *udata,Uint8 *stream,int len){
//SDL 2.0
SDL_memset(stream, 0, len);
if(audio_len==0) /* Only play if we have data left */return;
len=(len>audio_len?audio_len:len); /* Mix as much data as possible *///SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);memcpy(stream, audio_pos, len);
audio_pos += len;
audio_len -= len;
}
int main(int argc, char* argv[])
{
//Initif(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf( "Could not initialize SDL - %s
", SDL_GetError());
return -1;
}
//SDL_AudioSpec
SDL_AudioSpec wanted_spec;
wanted_spec.freq = 44100;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = 2;
wanted_spec.silence = 0;
wanted_spec.samples = 1024;
wanted_spec.callback = fill_audio;
if (SDL_OpenAudio(&wanted_spec, NULL)<0){
printf("can't open audio.
");
return -1;
}
FILE *fp=fopen("NocturneNo2inEflat_44.1k_s16le.pcm","rb+");
if(fp==NULL){
printf("cannot open this file
");
return -1;
}
int pcm_buffer_size=4096;
char *pcm_buffer=(char *)malloc(pcm_buffer_size);
int data_count=0;
//Play
SDL_PauseAudio(0);
while(1){
if (fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size){
// Loop
fseek(fp, 0, SEEK_SET);
fread(pcm_buffer, 1, pcm_buffer_size, fp);
data_count=0;
}
printf("Now Playing %10d Bytes data.
",data_count);
data_count+=pcm_buffer_size;
//Set audio buffer (PCM data)
audio_chunk = (Uint8 *) pcm_buffer;
//Audio buffer length
audio_len =pcm_buffer_size;
audio_pos = audio_chunk;
while(audio_len>0)//Wait until finish
SDL_Delay(1);
}
free(pcm_buffer);
SDL_Quit();
return0;
}