前面几篇关于SDL的文章介绍的是以画面为主,这里介绍下SDL中针对音频播放提供的机制,以及如何应用。

对于音频而言,有几个概念需要事先了解下,采样率、声道数、量化位数,如果你不清楚的话,麻烦先了解下这几本参数的概念。

常用的采样率有8kHz(语音、电话)、48kHz(电视),声道数常用的是双声道或5.1声道,量化位数8bit或16bit。

SDL提供了音频设备、音频输入/输出的控制机制。

比较常规的做法是先创建音频设备,然后按照你的实际需求进行音频输入输出。

由于音频处理相对简单,这里仅在一个cpp中实现所有wav播放的功能。

工程创建

为了演示期间,我们在vs10中创建控制台程序,并包含SDL头文件和库的路径。,工程名为3_wav_play。我从网上下了一个wav音频,名字为“congtouzailai.wav”。(音量比较大的,播放的时候注意下)

wav文件加载

SDL提供了SDL_LoadWAV函数,用于加载wav文件,加载的代码如下:

    SDL_AudioSpec wav_spec;
Uint32 wav_length;
Uint8 *wav_buffer; /* Load the WAV */
if (SDL_LoadWAV("congtouzailai.wav", &wav_spec, &wav_buffer, &wav_length) == NULL)
{
fprintf(stderr, "Could not open test.wav: %s\n", SDL_GetError());
return -;
}

函数调用成功之后,就可以获得wav文件中的音频参数,比如采样率、声道数、量化位数等,其中原始的音频数据(PCM)存储在wav_buffer中,长度为wav_length。

创建回调参数上下文

struct AudioPlayContext
{
Uint8 * data; // pcm buffer
int offset; // current read pos
int data_len; // left data length
bool is_exit; // is audio play buffer empty?
};

提供这个参数,只是为了提供数据从主函数到回调函数传递参数的机制。

创建音频设备

    AudioPlayContext context;
context.data = wav_buffer;
context.offset = ;
context.data_len = wav_length;
context.is_exit = false; // open audio device
SDL_AudioSpec want, have; want = wav_spec;
want.callback = MyAudioCallback; // you wrote this function elsewhere.
want.userdata = &context; if (SDL_OpenAudio(&want, &have) < )
{
printf("Failed to open audio: %s\n", SDL_GetError());
return -;
} if (have.format != want.format)
printf("We didn't get Float32 audio format.\n");

这里最主要的结构体SDL_AudioSpec的初始化,这里的回调函数MyAudioCallback,提供了向播放设备写入音频数据的方式。

播放音频数据

在主线程中,我们启动播放,并等待当前wav文件播放完成。代码如下

    SDL_PauseAudio();  // start audio playing.
// wait for the end
while(!context.is_exit)
{
SDL_Delay();
}

在回调函数中我们需要将数据填充到音频设备的播放缓冲中,并设置是否播放完成的标志位,代码如下

void MyAudioCallback(void* userdata, Uint8* stream, int len)
{
AudioPlayContext * context = reinterpret_cast<AudioPlayContext *>(userdata);
int copy_len = __min(len, context->data_len);
memcpy(stream, context->data+context->offset, copy_len);
context->data_len -= copy_len;
context->offset += copy_len;
if (context->data_len <= )
{
context->is_exit = true;
} if (copy_len < len)
{
memset(stream+copy_len, , len-copy_len);
}
}

反初始化操作

程序退出时,别忘记释放wav文件加载时的数据。

    SDL_CloseAudio();
/* Do stuff with the WAV data, and then... */
SDL_FreeWAV(wav_buffer);
SDL_Quit();

上面几个合并在一起就是最简单的wav文件播放器。

相关代码可以从我的git下载,url如下:https://git.oschina.net/Tocy/SampleCode.git,位于TocySDL2VisualTutorial目录下。

Beginning SDL 2.0(6) 音频渲染及wav播放的更多相关文章

  1. Beginning SDL 2.0(4) YUV加载及渲染

    本文主要内容是基于的“Beginning SDL 2.0(3) SDL介绍及BMP渲染”(以下简称BS3)基础上,将BMP加载及渲染修改为YUV420或I420的原始视频格式.阅读完本部分内容相信你可 ...

  2. Beginning SDL 2.0(3) SDL介绍及BMP渲染

    SDL是一个跨平台的多媒体库.为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface.SDL_Texture.SDL_Renderer ...

  3. Beginning SDL 2.0(5) 基于MFC和SDL的YuvPlayer

    本文是在“Beginning SDL 2.0(4) YUV加载及渲染”(以下简称BS4)基础上做的功能完善,如果你对之间介绍的内容了解不多,麻烦先阅读之前的内容. 本文主要介绍如何完成一个基于MFC和 ...

  4. Beginning SDL 2.0(2) TwinklebearDev SDL 2.0 Tutorial

    本文整理并简要介绍了TwinklebearDev SDL 2.0 Tutorial相关内容(以下简称TDSDLTutorial). 这是作为我学习并了解SDL2.0功能一篇学习总结. TDSDLTut ...

  5. Beginning SDL 2.0(1) SDL功能简介

    原文链接为 http://wiki.libsdl.org/Introduction. 由于近期整理音视频可视化的技术,发现好久不更新的SDL发布了2.0版本,以前也没有过于关注,这里准备尝试下.了解S ...

  6. Android下基于PCM的音频渲染

    环境准备 请按照我之前的文章-Android下基于SDL的位图渲染,安装必要的开发环境. 实践篇 这里主要参考Beginning SDL 2.0(6) 音频渲染及wav播放,只不过将源从WAV文件改成 ...

  7. (转)在SDL工程中让SDL_ttf渲染汉字

    有时候在关于SDL的博文中看到一些评论,说SDL对中文的支持不佳,因为当程序涉及中文时总是输出乱码. 照我个人观点,这里面很多都是误解.下面就根据我在windows下使用SDL的情况,说说我的观点. ...

  8. vue2.0 之文本渲染-v-html、v-text

    vue2.0 之文本渲染-v-html.v-text 1.index.html代码 <!DOCTYPE html> <html> <head> <meta c ...

  9. COCOS2DX 3.0 优化提升渲染速度 Auto-batching

    COCOS2DX 3.0 优化提升渲染速度 Auto-batching 近期在看COCOS2DX 3.0的Auto-batching合批与Auto Culling动态缩减功能以下就来细致看看吧:整合好 ...

随机推荐

  1. 快排法求第k大

    快排法求第k大,复杂度为O(n) import com.sun.media.sound.SoftTuning; import java.util.Arrays; import java.util.Ra ...

  2. 常用Raspberry Pi周边传感器的使用教程(转)

    转:http://bbs.xiaomi.cn/thread-7797152-1-1.html 在Raspberry Pi 的使用和开发过程中,你可能时常需要一些硬件和传感器等来支持你的开发工作,例如, ...

  3. javascript with关键字简单用法

    1.简要说明         with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性.要给对象创建新的属性,必须明确地引用该对象. 2.语法格式 with(object ...

  4. linux sshd ssh 服务的启动和使用

    这里使用sshd服务登录到linux系统的方法,不少同学走了弯路,包括我,我一直使用vmware虚拟linux学习使用的,后来windows病毒的原因转入到linux系统中使用 1,sshd服务安装 ...

  5. Python学习笔记(九)—— 函数

    一.函数调用: 1.python内部函数查询:http://docs.python.org/3/library/functions.html#abs 2.注意调用函数的参数个数和类型. 3.函数名其实 ...

  6. POJ 2676 Sudoku (DFS)

    Sudoku Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11694   Accepted: 5812   Special ...

  7. 【HTML】HTML之marquee详解

    该标签不是HTML3.2的一部分,并且只支持MSIE3以后内核,所以如果你使用非IE内核浏览器(如:Netscape)可能无法看到下面一些很有意思的效果该标签是个容器标签语法: <marquee ...

  8. 会动的Tabbar

    项目搭建 一.设计模式首先呢,小Q采用传统的MVC的设计模式,优点我们再来啰嗦一下啊:1.多个视图可以对应一个模型.按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发 ...

  9. golang学习笔记 --switch

    switch的例子: switch coinflip() { case "heads": heads++ case "tails": tails++ defau ...

  10. [javase学习笔记]-7.2 构造函数与一般函数的差别

    这一节我们简单学习一下构造函数与一般函数之间的差别所在. 那么它们有什么差别呢,结合上一节,我们能够总结出下面两点差别: 第一个差别: 构造函数:对象创建时,就会调用与之相应的构造函数,对对象进行初始 ...