目录
本文主要是在QT中基于SDL2库实现音频播放功能,原因之一是因为QT实现界面功能更加的简单,如果直接采用SDL2库实现界面功能和音频播放功能的话会更加的复杂。在之前我们已经使用QT中自带的mediamulti实现了音频播放,并且代码看起来更加简洁,为什么还要使用SDL2实现音频播放呢?原因是SDL2可以支持不仅仅是音频,还支持键盘,鼠标,操纵杆等操作。参考SDL3例子 以及参考例子 ,建议读者先直接看本文的讲解以及源码。
SDL2 | SDL2支持平台 | SDL2支持语言 |
---|---|---|
Simple DirectMedia Layer 是一个跨平台开发库,旨在通过 OpenGL 和 Direct3D 提供对音频、键盘、鼠标、操纵杆和图形硬件的低级访问。它被于视频播放软件、模拟器和热门游戏。 | SDL 正式支持 Windows、macOS、Linux、iOS 和 Android。 | SDL 是用 C 编写的,可以与 C++ 直接配合使用,并且还有几种其他语言的绑定,包括 C# 和 Python |
注:关于怎么编译源码以及涉及几种方式,请看以下链接:(本文是直接用的编译好的源码)https://mydreamambitious.blog.csdn.net/article/details/140998529
1.导入编译好的SDL2依赖库以及头文件
注:如果这个添加库的流程看的不是很明白,请看链接https://mydreamambitious.blog.csdn.net/article/details/140998529
2.导入编译SDL2源码之后的依赖库以及头文件
编译SDL2源码的视频链接请看文章最开头
实现思路
- 定义QT主界面,用于打开,播放音频以及关闭程序。
- 播放音频核心功能采用多线程实现,播放音频的同时也能显示主界面。
- 继承QThread基类;
- 初始化子系统SDL_Init;
- 加载音频文件SDL_LoadWAV_RW;
- 定义播放音频相关参数以及播放音频的回调函数;
- 计算音频文件总时长;
- 打开音频设备SDL_OpenAudioDevice;
- 播放音频SDL_PauseAudioDevice;
- 如果关闭程序,则调用析构函数回收所有的资源,包括播放音频所申请的资源;如果当前音频播放完毕需要继续,则继续打开文件播放音频。
第一步:初始化子系统
SDL_INIT_TIMER: 初始化定时器子系统。
SDL_INIT_AUDIO: 初始化音频子系统。
SDL_INIT_VIDEO: 初始化视频子系统。
SDL_INIT_JOYSTICK: 初始化游戏手柄子系统。
SDL_INIT_HAPTIC: 初始化触觉设备子系统。
SDL_INIT_GAMECONTROLLER: 初始化游戏控制器子系统。
SDL_INIT_EVENTS: 初始化事件系统(通常不需要单独初始化,因为它是其他子系统的一部分)。
SDL_INIT_NOPARACHUTE: 关闭 SDL 的“降落伞”机制,即在崩溃时不自动创建一个核心转储。
第二步:加载音频WAV文件
第三步:定义播放音频相关参数以及播放音频的回调函数
//定义相关参数
audio_spec.callback = audioCallback; //定义播放音频的回调函数
audio_spec.channels = 2; //1-表示单色声 2-表示立体声
audio_spec.freq = 44100; //频率(基本为这个)
audio_spec.format = AUDIO_S16LSB; //音频格式或者AUDIO_S16SYS
audio_spec.samples = 4096; //以采样帧为单位的音频缓冲区大小(总采样数除以通道数)
audio_spec.userdata = this -> userdata; //传给回调函数的数据
SDL_AudioFormat
是一个用于表示音频数据格式的枚举类型。它定义了音频数据的采样格式、位深度、通道数等信息。SDL2 支持的主要音频格式:
-
AUDIO_S8:
- 8 位单声道音频(1字节)。
- 有符号 PCM(Pulse Code Modulation)。
-
AUDIO_U8:
- 8 位单声道音频(1字节)。
- 无符号 PCM。
-
AUDIO_S16LSB:
- 16 位单声道音频(2字节)。
- 以小端序(Least Significant Byte First)的方式存储的有符号 PCM。
-
AUDIO_S16MSB:
- 16 位单声道音频(2字节)。
- 以大端序(Most Significant Byte First)的方式存储的有符号 PCM。
-
AUDIO_S32LSB:
- 32 位单声道音频(4字节)。
- 以小端序存储的有符号 PCM。
-
AUDIO_S32MSB:
- 32 位单声道音频(4字节)。
- 以大端序存储的有符号 PCM。
-
AUDIO_F32LSB:
- 32 位浮点音频(小端序)(4字节)。
- 使用浮点数表示音频数据。
-
AUDIO_F32MSB:
- 32 位浮点音频(大端序)(4字节)。
- 使用浮点数表示音频数据。
-
AUDIO_S16SYS:
- 16 位音频格式,系统的字节序(大端或小端,取决于平台)(2字节)。
-
AUDIO_S32SYS:
- 32 位音频格式,系统的字节序(4字节)。
-
AUDIO_F32SYS:
- 32 位浮点数音频格式,系统的字节序(4字节)。
void audioCallback(void *userdata, Uint8 * stream,int len){
userData * data = (userData*)userdata; //将传回的数据格式转换
if(data -> audio_len == 0)return; //如果音频播放完毕就不再继续操作
data -> curr_len += len; //记录当前已经播放的进度
if(data -> audio_len < (Uint32)len){ //如果当前剩余的长度小于固定播放长度,就按照剩余长度来计算
len = data -> audio_len;
SDL_memcpy(stream,data -> audio_buf + data -> curr_len,len);//就是类似纯C语言中的memcpy函数
}else{
SDL_memcpy(stream,data -> audio_buf + data -> curr_len,len);
}
data -> audio_len -= len;
}
第四步:计算音频文件总时长
注:关于PCM音频的位长,看SDL_AudioFormat支持格式。
第五步:打开音频设备SDL_OpenAudioDevice
const char *device: 要打开的音频设备的名称。如果为 NULL,则使用默认设备。
int iscapture: 指示设备的类型。如果是捕获设备(输入设备),则设置为非零值。否则,设置为 0 以打开
播放设备(输出设备)。
const SDL_AudioSpec *wanted: 指向 SDL_AudioSpec 结构的指针,该结构包含你希望使用的音频格式、通
道数、采样率等设置。
可以设置以下字段:
freq: 采样率(例如 44100 Hz)。
format: 音频格式(例如 AUDIO_S16SYS、AUDIO_F32SYS 等)。
channels: 通道数(例如 1 = 单声道,2 = 立体声)。
silence: 静音值(通常为 0)。
samples: 缓冲区的样本数(例如 4096)。
callback: 回调函数(如果使用非阻塞音频),如果不需要传递数据,则可以设置为 NULL。
SDL_AudioSpec *obtained: 指向 SDL_AudioSpec 结构的指针,用于返回设备实际使用的音频格式
和参数。可以在打开设备后查看实际配置的音频设置。
Uint32 allowed_changes: 指定 SDL 可以更改的音频参数。它的值可以是以下常量的按位或组合:
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE: 允许更改采样率。
SDL_AUDIO_ALLOW_FORMAT_CHANGE: 允许更改音频格式。
SDL_AUDIO_ALLOW_CHANNELS_CHANGE: 允许更改通道数。
SDL_AUDIO_ALLOW_SAMPLES_CHANGE: 允许更改缓冲区的样本数。
第六步:播放音频SDL_PauseAudioDevice
QT 6.6.0基于SDL2实现音频播放功能