Beginning SDL 2.0(6) 音频渲染及wav播放
前面几篇关于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播放的更多相关文章
- Beginning SDL 2.0(4) YUV加载及渲染
本文主要内容是基于的“Beginning SDL 2.0(3) SDL介绍及BMP渲染”(以下简称BS3)基础上,将BMP加载及渲染修改为YUV420或I420的原始视频格式.阅读完本部分内容相信你可 ...
- Beginning SDL 2.0(3) SDL介绍及BMP渲染
SDL是一个跨平台的多媒体库.为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface.SDL_Texture.SDL_Renderer ...
- Beginning SDL 2.0(5) 基于MFC和SDL的YuvPlayer
本文是在“Beginning SDL 2.0(4) YUV加载及渲染”(以下简称BS4)基础上做的功能完善,如果你对之间介绍的内容了解不多,麻烦先阅读之前的内容. 本文主要介绍如何完成一个基于MFC和 ...
- Beginning SDL 2.0(2) TwinklebearDev SDL 2.0 Tutorial
本文整理并简要介绍了TwinklebearDev SDL 2.0 Tutorial相关内容(以下简称TDSDLTutorial). 这是作为我学习并了解SDL2.0功能一篇学习总结. TDSDLTut ...
- Beginning SDL 2.0(1) SDL功能简介
原文链接为 http://wiki.libsdl.org/Introduction. 由于近期整理音视频可视化的技术,发现好久不更新的SDL发布了2.0版本,以前也没有过于关注,这里准备尝试下.了解S ...
- Android下基于PCM的音频渲染
环境准备 请按照我之前的文章-Android下基于SDL的位图渲染,安装必要的开发环境. 实践篇 这里主要参考Beginning SDL 2.0(6) 音频渲染及wav播放,只不过将源从WAV文件改成 ...
- (转)在SDL工程中让SDL_ttf渲染汉字
有时候在关于SDL的博文中看到一些评论,说SDL对中文的支持不佳,因为当程序涉及中文时总是输出乱码. 照我个人观点,这里面很多都是误解.下面就根据我在windows下使用SDL的情况,说说我的观点. ...
- vue2.0 之文本渲染-v-html、v-text
vue2.0 之文本渲染-v-html.v-text 1.index.html代码 <!DOCTYPE html> <html> <head> <meta c ...
- COCOS2DX 3.0 优化提升渲染速度 Auto-batching
COCOS2DX 3.0 优化提升渲染速度 Auto-batching 近期在看COCOS2DX 3.0的Auto-batching合批与Auto Culling动态缩减功能以下就来细致看看吧:整合好 ...
随机推荐
- clear session on close of browser jsp
关闭浏览器销毁session <%@ Page Language="C#" AutoEventWireup="true" CodeBehind=" ...
- 简单的Java串口通讯应答示例
java串口通讯第一次使用,找的资料都比较麻烦,一时没有理出头绪,自己在示例的基础上整理了一个简单的应答示例,比较简陋,但演示了java串口通讯的基本过程. package com.garfield. ...
- POJ 3683 Priest John's Busiest Day (2-SAT)
Priest John's Busiest Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6900 Accept ...
- Unicode和UTF的关系
目录结构: contents structure [+] 什么是USC UCS的编码方式 Unicode的来源 为什么需要Unicode Unicode的方式 Unicode和UTF UTF和Unic ...
- 【struts2】继承ActionSupport类
在Struts2中,Action可以不实现任何特殊的接口或者继承特殊的类,仅仅是一个POJO(Plain Old Java Object,简单的Java对象)就可以:也可以实现Xwork2中的Acti ...
- Android App解决卡顿慢之内存抖动及内存泄漏(发现和定位)
内存抖动是指在短时间内有大量的对象被创建或者被回收的现象,内存抖动出现原因主要是频繁(很重要)在循环里创建对象(导致大量对象在短时间内被创建,由于新对象是要占用内存空间的而且是频繁,如果一次或者两次在 ...
- ThinkPHP 3.2 性能优化,实现高性能API开发
需求分析 目前的业务全站使用ThinkPHP 3.2.3,前台.后台.Cli.Api等.目前的业务API访问量数千万,后端7台PHP 5.6,平均CPU使用率20%. 测试数据 真实业务 php5.6 ...
- Python 文件 flush() 方法
描述 Python 文件 flush() 方法是用来把文件从内存buffer(缓冲区)中强制刷新到硬盘中,同时清空缓冲区. 一般情况下,文件关闭后会自动刷新到硬盘中,但有时你需要在关闭前刷新到硬盘中, ...
- sqlserver使用存储过程发送http请求
本文主要向大家介绍了SQLServer数据库访问发送Http请求,通过具体的内容向大家展现,希望对大家学习SQLServer数据库有所帮助. -- 通用读取获取数据存储过程 --开启Sql Serve ...
- 如何将shell的打印日志输入到日志文件
如果shell打印的日志很多,屏幕无法完全显示,需要查看shell执行的情况,这是就需要输入到日值了: 如:echo "2012-6-14" | tee -a my.log -a表 ...