首页 > 其他分享 >11_使用SDL播放WAV

11_使用SDL播放WAV

时间:2022-10-05 17:56:02浏览次数:77  
标签:11 buffer len SDL WAV 播放 data

使用命令播放WAV

对于WAV文件来说,可以直接使用ffplay命令播放,而且不用像PCM那样增加额外的参数。因为WAV的文件头中已经包含了相关的音频参数信息。

ffplay in.wav

接下来演示一下如何使用SDL播放WAV文件。

初始化子系统

// 初始化Audio子系统
if (SDL_Init(SDL_INIT_AUDIO)) {
    qDebug() << "SDL_Init error:" << SDL_GetError();
    return;
}

加载WAV文件

// 存放WAV的PCM数据和数据长度
typedef struct {
    Uint32 len = 0;
    int pullLen = 0;
    Uint8 *data = nullptr;
} AudioBuffer;

// WAV中的PCM数据
Uint8 *data;
// WAV中的PCM数据大小(字节)
Uint32 len;
// 音频参数
SDL_AudioSpec spec;

// 加载wav文件
if (!SDL_LoadWAV(FILENAME, &spec, &data, &len)) {
    qDebug() << "SDL_LoadWAV error:" << SDL_GetError();
    // 清除所有的子系统
    SDL_Quit();
    return;
}

// 回调
spec.callback = pull_audio_data;
// 传递给回调函数的userdata
AudioBuffer buffer;
buffer.len = len;
buffer.data = data;
spec.userdata = &buffer;

如果想要轻松加载MP3、Ogg、FLAC等格式的音频文件,可以使用第三方库:SDL_mixer

打开音频设备

// 打开设备
if (SDL_OpenAudio(&spec, nullptr)) {
    qDebug() << "SDL_OpenAudio error:" << SDL_GetError();
    // 释放文件数据
    SDL_FreeWAV(data);
    // 清除所有的子系统
    SDL_Quit();
    return;
}

开始播放

// 开始播放(0是取消暂停)
SDL_PauseAudio(0);

// 计算一些参数
int sampleSize = SDL_AUDIO_BITSIZE(spec.format);
// 每一个样本的大小
int bytesPerSample = (sampleSize * spec.channels) >> 3;

while (!isInterruptionRequested()) {
    // 只要从文件中读取的音频数据,还没有填充完毕,就跳过
    if(buffer.len > 0) continue;
    
    // 文件数据已经读取完毕
    if (buffer.len <= 0) {
       // 最后一次播放的样本数量
       int samples = buffer.pullLen / bytesPerSample;
       // 最后一次播放的时长
       int ms = samples * 1000 / spec.freq;
       SDL_Delay(ms);
       break;
    }
}

回调函数

// 等待音频设备回调(会回调多次)
void pull_audio_data(void *userdata,
                     // 需要往stream中填充PCM数据
                     Uint8 *stream,
                     // 希望填充的大小(samples * format * channels / 8)
                     int len
                    ) {
    // 清空stream
    SDL_memset(stream, 0, len);

    AudioBuffer *buffer = (AudioBuffer *) userdata;

    // 文件数据还没准备好
    if (buffer->len <= 0) return;

    // 取len、bufferLen的最小值
    buffer->pullLen = (len > (int) buffer->len) ? buffer->len : len;

    // 填充数据
    SDL_MixAudio(stream,
                 buffer->data,
                 buffer->pullLen,
                 SDL_MIX_MAXVOLUME);
    buffer->data += buffer->pullLen;
    buffer->len -= buffer->pullLen;
}

释放资源

// 释放WAV文件数据
SDL_FreeWAV(data);

// 关闭设备
SDL_CloseAudio();

// 清除所有的子系统
SDL_Quit();

代码链接

标签:11,buffer,len,SDL,WAV,播放,data
From: https://www.cnblogs.com/zuojie/p/16756015.html

相关文章

  • 代码随想录day11 | 232.用栈实现队列 225.队列实现栈 20.有效的括号 1047. 删除字符
    232.用栈实现队列题目|文章1.使用两个栈(修改输出)思路1.使用两个栈,用一个栈输入数据,用另一个栈输出数据2.当输出栈为空时,将输入栈的数据转移到输出栈中实现点击查看......
  • 题解【CF1149C Tree Generator】
    CF1149CTreeGenerator™不一定更好的阅读体验。牛逼题&ZROIDay3数据结构选讲。来一波详细的题解。当时和\(\texttt{ys}\),\(\texttt{hy}\)还有小猴子讨论了半......
  • 10_PCM转WAV
    播放器是无法直接播放PCM的,因为播放器并不知道PCM的采样率、声道数、位深度等参数。当PCM转成某种特定的音频文件格式后(比如转成WAV),就能够被播放器识别播放了。本文通过2......
  • 09_使用SDL播放PCM
    通过命令ffpay播放PCM可以使用ffplay播放《08_音频录制02_编程》中录制好的PCM文件,测试一下是否录制成功。播放PCM需要指定相关参数:ar:采样率ac:声道数f:采样格式,sam......
  • GCC Arm 11.3rel1, 12.2编译提示 _close is not implemented and will always fail
    使用GCCArm工具链开发的项目,在11.2下编译正常,但是升级到arm-gnu-toolchain-11.3.rel1以及arm-gnu-toolchain-12.2之后,编译出现警告/opt/gcc-arm/arm-gnu-toolc......
  • 【笨方法学python】ex11 - 提问
    代码如下:点击查看代码#-*-coding:utf-8--*-#提问print"Howoldareyou?",age=raw_input()print"Howtallareyou?",height=raw_input()print"Howmu......
  • 11-RabbitMQ高级特性-消息如何保证100%的投递成功
    消息如何保证100%的投递成功什么是生产端的可靠性投递保障消息的成功发出保障MQ节点的成功接收发送端收到MQ节点(Broker)确认应答完善的消息进行补偿机制BAT/TMD......
  • 从前有个葡萄牙国王,他有三个可爱的女11
    从前有个葡萄牙国王,他有三个可爱的女http://ds.163.com/article/6338aae1d3fdd0000198760e/?2022/10/06_=2022/10/05http://ds.163.com/feed/6338aae1d3fdd0000198760e/?202......
  • 11.设计模式-适配器模式-类适配器
    //1.定义目标被适配类//2.定义适配器接口,期望输出//3.定义适配器类,继承被适配器类,实现适配器接口//4.测试/**被适配类,输出的是220V*/publicclassVoltage220V{p......
  • 帕拉斯雅典娜飞到斯巴达,在国王墨涅拉11
    帕拉斯雅典娜飞到斯巴达,在国王墨涅拉http://ds.163.com/article/6338a5aa85eece000185b5f6/?2022_1005=20221005uhttp://ds.163.com/feed/6338a5aa85eece000185b5f6/?2022_1......