首页 > 代码库 > SDL2.0例子代码分析---循环播放wav loopwav

SDL2.0例子代码分析---循环播放wav loopwav

SDL2.0中循环播放一段声音文件 ,并且添加上注释。

/*  加载并且循环播放一个WAV文件*/

/* loopwaves.c is much more robust in handling WAVE files --
	This is only for simple WAVEs
	*/
#include "SDL_config.h"

#include <stdio.h>
#include <stdlib.h>

#if HAVE_SIGNAL_H
#include <signal.h>
#endif

#include "SDL.h"
#include "SDL_audio.h"

//sdl 播放缓冲区定义
struct
{
	SDL_AudioSpec spec;
	Uint8 *sound;               /*指向声音数据指针 */
	Uint32 soundlen;            /* Length of wave data */
	int soundpos;               /* Current play position */
} wave;


/* 调用这个函数退出SDL子系统 */
static void
quit(int rc)
{
	SDL_Quit();
	exit(rc);
}


void SDLCALL
fillerup(void *unused, Uint8 * stream, int len)
{
	Uint8 *waveptr;
	int waveleft;

	/*设置当前声音指针
	声音指针+当前播放的位置
	*/
	waveptr = wave.sound + wave.soundpos;
	//剩余声音数据   声音数据长度-当前播放的位置 
	waveleft = wave.soundlen - wave.soundpos;

	/* 如果剩余数据<需要的长度 */
	while (waveleft <= len)
	{
		//拷贝剩余数据到音频缓冲区
		SDL_memcpy(stream, waveptr, waveleft);
		//音频缓冲区stream指针后移
		stream += waveleft;
		//len=len-waveleft
		len -= waveleft;
		//拷贝玩剩余数据
		//waveptr指向 声音数据开头  
		waveptr = wave.sound;
		//长度等于len 
		waveleft = wave.soundlen;
		//位置等于len
		wave.soundpos = 0;
	}
	//重新拷贝内存到 音频设备缓冲区  
	//也就是循环播放
	SDL_memcpy(stream, waveptr, len);  
	//当前播放的位置 +=len
	wave.soundpos += len;
}

static int done = 0;
//退出信号 
void
poked(int sig)
{
	done = 1;
}

int
main(int argc, char *argv[])
{
	int i;
	char filename[4096];

	/* Enable standard application logging */
	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

	/* 初始化SDL音频库 */
	if (SDL_Init(SDL_INIT_AUDIO) < 0) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
		return (1);
	}

	//拷贝文件名字 到 filename 缓冲区
	if (argc >= 1) {
		SDL_strlcpy(filename, argv[1], sizeof(filename));
	}
	else {
		SDL_strlcpy(filename, "D:\\vs2010_pro\\ffmpeg_test\\Output\\audio.aac", sizeof(filename));
	}
	/* 加载声音文件到内存 */
	if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", argv[1], SDL_GetError());
		quit(1);
	}
	//音频回调 在回调函数中填充音频缓冲区 需求的大小的数据 
	wave.spec.callback = fillerup;
#if HAVE_SIGNAL_H
	/* Set the signals */
#ifdef SIGHUP
	signal(SIGHUP, poked);
#endif
	signal(SIGINT, poked);
#ifdef SIGQUIT
	signal(SIGQUIT, poked);
#endif
	signal(SIGTERM, poked);
#endif /* HAVE_SIGNAL_H */

	/* Show the list of available drivers */
	SDL_Log("Available audio drivers:");
	//打印电脑上的所有音频驱动
	for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
		SDL_Log("%i: %s", i, SDL_GetAudioDriver(i));
	}

	/*初始化音频设备  并且打开 因为我们输出的wav有头部信息所有 我们不需要设置参数*/
	if (SDL_OpenAudio(&wave.spec, NULL) < 0) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
		SDL_FreeWAV(wave.sound);
		quit(2);
	}

	//打印当前音频设备
	SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());

	/*开始播放声音  这个时候 SDL以异步线程的方式不停的回调 来取数据  */
	SDL_PauseAudio(0);
	//如果当前正在播放 那么 主线程 Delay 1s 
	//或者有退出信号 那么退出
	while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING))
		SDL_Delay(1000);

	/* 关闭音频 */
	SDL_CloseAudio();
	//释放分配的声音数据内存
	SDL_FreeWAV(wave.sound); 
   //退出程序 和SDL
	SDL_Quit();
	return (0);
}



SDL2.0例子代码分析---循环播放wav loopwav