在上文,我们做了YUV播放器,这样我们就入门了SDL播放视频。下面我们来做一个PCM播放,即使用SDL播放PCM数据。

下面说明一下使用SDL播放PCM音频的基本流程,主要分为两大部分:初始化SDL、循环播放数据。

1. 初始化SDL

1). 初始化SDL

执行的方法为SDL_Init(SDL_INIT_AUDIO)

2). 打开音频设备

使用SDL_OpenAudio()打开音频设备。该函数需要传入一个SDL_AudioSpec的结构体。

这里SDL_OpenAudio() 函数的原型为:

int SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained);

它的参数是两个SDL_AudioSpec结构体,它们的含义:
desired:期望的参数。
obtained:实际音频设备的参数,一般情况下设置为NULL即可。

其中SDL_AudioSpec结构体如下:

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:音频数据的采样率。常用的有48000,44100等。
  • format:音频数据的格式。举例几种格式:
  • AUDIO_U16SYS:Unsigned 16-bit samples
  • AUDIO_S16SYS:Signed 16-bit samples
  • AUDIO_S32SYS:32-bit integer samples
  • AUDIO_F32SYS:32-bit floating point samples
  • channels:声道数。例如单声道取值为1,立体声取值为2。
  • silence:设置静音的值。
  • samples:音频缓冲区中的采样个数,要求必须是2的n次方。
  • padding:考虑到兼容性的一个参数。
  • size:音频缓冲区的大小,以字节为单位。
  • callback:填充音频缓冲区的回调函数。
  • userdata:用户自定义的数据。

在这里说明一下填充音频缓冲区的回调函数的作用。当音频设备需要更多数据的时候会调用该回调函数。

回调函数的格式要求如下:

void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream, int len);

回调函数的参数含义如下:

  • userdata:SDL_AudioSpec结构中的用户自定义数据,一般情况下可以不用。
  • stream:该指针指向需要填充的音频缓冲区。
  • len:音频缓冲区的大小(以字节为单位)。

在回调函数中可以使用SDL_MixAudio()完成混音等工作。注意:SDL2中必须首先使用SDL_memset()将stream中的数据设置为0。

2. 循环播放数据

1) 播放音频数据。

使用SDL_PauseAudio()可以播放音频数据。SDL_PauseAudio() 函数的原型如下:

void SDLCALL SDL_PauseAudio(int pause_on)

当pause_on设置为0的时候即可开始播放音频数据。设置为1的时候,将会播放静音的值。

2) 延时等待播放完成。

使用像SDL_Delay()这样的延时函数即可。

实战

// SDL.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include "pch.h"
#include <iostream> extern "C" {
#include "SDL.h"
} /**
*
* 使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层API。
*
* 函数调用步骤如下:
*
* [初始化]
* SDL_Init(): 初始化SDL。
* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。
* SDL_PauseAudio(): 播放音频数据。
*
* [循环播放数据]
* SDL_Delay(): 延时等待播放完成。
*
* [播放音频的基本原则]
* 声卡向你要数据而不是你主动推给声卡
* 数据的多少是由音频参数决定的
*/ //Buffer:
//|-----------|-------------|
//chunk-------pos---len-----| static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos; void fill_audio(void *udata, Uint8 *stream, int len) {
//SDL 2.0
SDL_memset(stream, , len);
if (audio_len == )
return;
len = (len > audio_len ? audio_len : len); SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
audio_pos += len;
audio_len -= len;
} int main(int argc, char* argv[])
{
//Init
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -;
}
//SDL_AudioSpec
SDL_AudioSpec wanted_spec;
wanted_spec.freq = ;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = ;
wanted_spec.silence = ;
wanted_spec.samples = ;
wanted_spec.callback = fill_audio; if (SDL_OpenAudio(&wanted_spec, NULL) < ) {
printf("can't open audio.\n");
return -;
} FILE *fp = fopen("test.pcm", "rb+"); if (fp == NULL) {
printf("cannot open this file\n");
return -;
}
int pcm_buffer_size = ;
char *pcm_buffer = (char *)malloc(pcm_buffer_size);
int data_count = ; //Play
SDL_PauseAudio(); while () {
if (fread(pcm_buffer, , pcm_buffer_size, fp) != pcm_buffer_size) {
// Loop
fseek(fp, , SEEK_SET);
fread(pcm_buffer, , pcm_buffer_size, fp);
data_count = ;
}
printf("Now Playing %10d Bytes data.\n", 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 > )//Wait until finish
SDL_Delay();
}
free(pcm_buffer);
SDL_Quit();
return ;
}

SDL 开发实战(七): 使用 SDL 实现 PCM播放器的更多相关文章

  1. SDL 开发实战(二):SDL 2.0 核心 API 解析

    在上一篇文章 SDL 开发实战(一):SDL介绍及开发环境配置 中,我们配置好了SDL的开发环境,并成功运行了SDL的Hello World 代码.但是可能大部分人还是读不太明白具体Hello Wol ...

  2. SDL 开发实战(三):使用 SDL 绘制基本图形

    在上文 SDL 开发实战(二):SDL 2.0 核心 API 解析 我们讲解了SDL最核心的API,并结合Hello World代码了解了SDL渲染画面的基本原理. 本文我们来讲一下,如何使用SDL的 ...

  3. 【C语言探索之旅】 第三部分第一课:SDL开发游戏之安装SDL

    内容简介 1.课程大纲 2.第三部分第一课: SDL开发游戏之安装SDL 3.第三部分第二课预告: SDL开发游戏之创建窗口和画布 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会 ...

  4. iOS开发拓展篇—音频处理(音乐播放器1)

    iOS开发拓展篇—音频处理(音乐播放器1) 说明:该系列文章通过实现一个简单的音乐播放器来介绍音频处理的相关知识点,需要重点注意很多细节的处理. 一.调整项目的结构,导入必要的素材 调整后的项目结构如 ...

  5. iOS开发拓展篇—音频处理(音乐播放器2)

    iOS开发拓展篇—音频处理(音乐播放器2) 说明:该文主要介绍音乐播放界面的搭建. 一.跳转 1.跳转到音乐播放界面的方法选择 (1)使用模态跳转(又分为手动的和自动的) (2)使用xib并设置跳转 ...

  6. iOS开发拓展篇—音频处理(音乐播放器3)

    iOS开发拓展篇—音频处理(音乐播放器3) 说明:这篇文章主要介绍音频工具类和播放工具类的封装. 一.控制器间数据传递 1.两个控制器之间数据的传递 第一种方法:self.parentViewCont ...

  7. iOS开发拓展篇—音频处理(音乐播放器4)

    iOS开发拓展篇—音频处理(音乐播放器4) 说明:该文主要介绍音乐播放器实现过程中的一些细节控制. 实现的效果: 一.完整的代码 YYPlayingViewController.m文件 // // Y ...

  8. iOS开发拓展篇—音频处理(音乐播放器5)

    iOS开发拓展篇—音频处理(音乐播放器5) 实现效果: 一.半透明滑块的设置 /** *拖动滑块 */ - (IBAction)panSlider:(UIPanGestureRecognizer *) ...

  9. iOS开发拓展篇—音频处理(音乐播放器6)

    iOS开发拓展篇—音频处理(音乐播放器6) 一.图片处理 说明: Aspect表示按照原来的宽高比进行缩放. Aspectfit表示按照原来的宽高比缩放,要求看到全部图片,后果是不能完全覆盖窗口,会留 ...

随机推荐

  1. MapReduce词频统计

    自定义Mapper实现 import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; impor ...

  2. hadoop2.x HDFS HA linux环境搭建

    HDFS High Availability Using the Quorum Journal Manager 准备3台机器可以更多   NN  DN  ZK  ZKFC  JN  RM  DM  n ...

  3. golang http.client 遇到了 Connection reset by peer 问题

    最近一个 golang 写的 http.client 的,获取远程服务器数据,有时候会报错,尤其在数量很大的时候,老是收到 Connection reset by peer 这样的 提醒,都有点想用重 ...

  4. asp:GridView控件使用FindControl方法获取控件的问题

    一.使用带cells的指定列 e.Item.Cells[1].Controls[1]只指定第二列的第二个控件 二.不使用带cells的指定类e.Item.FindControl("ID&qu ...

  5. MySql恢复密码的过程

    密码是一个非常重要的东西,所以往往设置的很复杂,也往往一不小心.......就忘了  : ( 很多童鞋在Linux下看到一堆命令行往往都是一脸懵逼,不知从何下手,这里记录了下基本的恢复操作以备不时之需 ...

  6. VS2017打包注册IE插件及修改IE安全选项设置

    前言 最近项目需要在浏览器环境下读取员工身份证信息,要实现网页与硬件设备通信,考虑了几种实现方式: 1.借助ActiveX插件,通过程序库直接与设备通信. 优点:厂家提供了IE插件,开发简单 缺点:只 ...

  7. P1113 杂务 拓扑排序

    题目描述 John的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它.比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作.尽早将所有杂务完成是必要的,因为 ...

  8. Windows 运行命令大全,装逼必备哦!

    以下已整理,以字母先后排序: appwiz.cpl:程序和功能 cliconfg:SQL SERVER 客户端网络实用工具 cmd:CMD命令提示符 comexp.msc或者dcomcnfg:组件服务 ...

  9. PCA:利用PCA(四个主成分的贡献率就才达100%)降维提高测试集辛烷值含量预测准确度并《测试集辛烷值含量预测结果对比》—Jason niu

    load spectra; temp = randperm(size(NIR, 1)); P_train = NIR(temp(1:50),:); T_train = octane(temp(1:50 ...

  10. [Log函数]C++log函数使用

    先引入头文件#include<cmath> 以e为底:log(exp(n)) 以10为底:log10(n) 以m为底:log(n)/log(m)