sdl 打开耳机_SDL 开发实战(七): 使用 SDL 实现 PCM播放器

在上文,我们做了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 structSDL_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

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;staticUint32 audio_len;static Uint8 *audio_pos;void fill_audio(void *udata, Uint8 *stream, intlen) {//SDL 2.0

SDL_memset(stream, 0, len);if (audio_len == 0)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 -1;

}//SDL_AudioSpec

SDL_AudioSpec wanted_spec;

wanted_spec.freq= 48000;

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.\n");return -1;

}

FILE*fp = fopen("test.pcm", "rb+");if (fp ==NULL) {

printf("cannot open this file\n");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.\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 > 0)//Wait until finish

SDL_Delay(1);

}free(pcm_buffer);

SDL_Quit();return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值