美文网首页
播放 WAV

播放 WAV

作者: 村口大白杨 | 来源:发表于2021-04-04 22:00 被阅读0次
一、使用命令行播放
$ ffplay test.wav
二、使用 SDL2 API 播放

1、创建 Qt 工程,参考 Mac开发环境搭建

2、在 .pro 文件添加 SDL2 头文件和静态库路径,

macx {
    INCLUDEPATH += /usr/local/Cellar/sdl2/2.0.14_1/include
    LIBS += -L /usr/local/Cellar/sdl2/2.0.14_1/lib -lSDL2
}

3、导入 SDL 头文件

#include <SDL2/SDL.h>

4、初始化 SDL2 子系统,我们仅仅播放音频,参数只传入 SDL_INIT_AUDIO 即可。

if (SDL_Init(SDL_INIT_AUDIO)) {
    qDebug() << "初始化音频子系统失败";
    return;
}

5、加载 WAV 文件,SDL2 提供了加载 WAV 的方法

if (!SDL_LoadWAV(WAV_FILE_NAME, &spec, &data, &len)) {
    qDebug() << "加载 WAV 文件失败:" << WAV_FILE_NAME << SDL_GetError();
    SDL_Quit();
    return;
}

SDL_LoadWAV 是一个便利宏,作用是读取音频数据格式并且把全部音频数据加载进内存:

#define SDL_LoadWAV(file, spec, audio_buf, audio_len) \
    SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)

参数:

file:加载的 WAV 文件名称;

spec:SDL_AudioSpec 结构体地址,函数调用成功 spec 的 freq、channels、format等成员变量会被赋值成 WAV 文件中音频数据的参数;
audio_buffer:加载进内存的全部音频数据;
audio_len:音频数据长度,单位字节;
实际调用的函数是 SDL_LoadWAV_RW( ):

SDL_AudioSpec* SDL_LoadWAV_RW(SDL_RWops * src,
                              int freesrc,
                              SDL_AudioSpec * spec,
                              Uint8 ** audio_buf,
                              Uint32 * audio_len);

参数:
src:加载的 WAV 文件名称;
freesrc:如果非0,函数返回前自动关闭释放资源文件,此处传1即可;
spec:同上;
audio_buffer:同上;
audio_len:同上;

6、打开音频设备

if (SDL_OpenAudio(&spec, nullptr)) {
    qDebug() << "打开音频设备失败";
    SDL_FreeWAV(data);
    SDL_Quit();
    return;
}

7、开始播放

SDL_PauseAudio(0);

参数:
pause_on:打开音频设备后传入0开始播放音频,1暂停播放;

参数 pause_on 设置为0开始调用回调函数:

// 等待音频设备回调,调用多次,
void fill_audio(void *userdata, Uint8 * stream, int len)
{
    qDebug() << "fill_audio len:" << len;
    AudioBuffer *buffer = (AudioBuffer *) userdata;
    SDL_memset(stream, 0, len);
    if (buffer->len <= 0) return;
    buffer->pullLen = buffer->len > len ? len : buffer->len;
    SDL_MixAudio(stream, buffer->data, buffer->pullLen, SDL_MIX_MAXVOLUME);
    buffer->data += buffer->pullLen;
    buffer->len -= buffer->pullLen;
}

8、播放结束释放音频数据,关闭音频设备,清除 SDL 子系统:

// 释放 WAV 数据
SDL_FreeWAV(data);
// 关闭音频设备
SDL_CloseAudio();
// 清除所有子系统
SDL_Quit();

完整代码:

#include <SDL2/SDL.h>
#include <QFile>
#include <QDebug>

#define WAV_FILE_NAME "/Users/mac/Downloads/music/test.wav"

typedef struct AudioBuffer {
    int len = 0;
    int pullLen = 0;
    uint8_t *data = nullptr;
} AudioBuffer;

// 等待音频设备回调,调用多次,

void fill_audio(void *userdata, Uint8 * stream, int len)
{
    qDebug() << "fill_audio len:" << len;
    AudioBuffer *buffer = (AudioBuffer *) userdata;
    SDL_memset(stream, 0, len);
    if (buffer->len <= 0) return;
    buffer->pullLen = buffer->len > len ? len : buffer->len;
    SDL_MixAudio(stream, buffer->data, buffer->pullLen, SDL_MIX_MAXVOLUME);
    buffer->data += buffer->pullLen;
    buffer->len -= buffer->pullLen;
}

PlayThread::PlayThread(QObject *parent) : QThread(parent)
{
    connect(this, &PlayThread::finished, this, &PlayThread::deleteLater);
}

PlayThread::~PlayThread()
{
    requestInterruption();
    quit();
    wait();
    qDebug() << "PlayThread 析构了~";
}

void PlayThread::run()
{
    // 初始化 SDL 音频子系统
    if (SDL_Init(SDL_INIT_AUDIO)) {
        qDebug() << "初始化音频子系统失败";
        return;
    }

    Uint8 *data;
    Uint32 len;
    SDL_AudioSpec spec;

    // 加载 WAV 文件
    if (!SDL_LoadWAV(WAV_FILE_NAME, &spec, &data, &len)) {
        qDebug() << "加载 WAV 文件失败:" << WAV_FILE_NAME << SDL_GetError();
        SDL_Quit();
        return;
    }

    AudioBuffer buffer;
    buffer.data = data;
    buffer.len = len;
    spec.userdata = &buffer;
    spec.callback = fill_audio;

    // 打开音频设备
    if (SDL_OpenAudio(&spec, nullptr)) {
        qDebug() << "打开音频设备失败";
        SDL_FreeWAV(data);
        SDL_Quit();
        return;
    }

    // 开始播放
    SDL_PauseAudio(0);

    while (!isInterruptionRequested()) {
        if (buffer.len > 0) continue;
        // 每一个样本大小
        int size = SDL_AUDIO_BITSIZE(spec.format) * spec.channels / 8;
        // 剩余样本数量
        int leftSample = buffer.pullLen / size;
        // 剩余样本播放时间ms
        int ms = leftSample * 1000 / spec.freq;
        SDL_Delay(ms);
        break;
    }

    // 释放 WAV 数据
    SDL_FreeWAV(data);
    // 关闭音频设备
    SDL_CloseAudio();
    // 清除所有子系统
    SDL_Quit();
}

相关文章

  • 11_使用SDL播放WAV

    播放WAV 对于WAV文件来说,可以直接使用ffplay命令播放,而且不用像PCM那样增加额外的参数。因为WAV的...

  • 播放 WAV

    一、使用命令行播放 二、使用 SDL2 API 播放 1、创建 Qt 工程,参考 Mac开发环境搭建[everno...

  • WAV的播放

    1.命令行播放 从终端输出可以看到已经成功播放了。从前面得知WAV文件是对PCM文件的深一层封装,里面已经包含了声...

  • 转码

    ios 不能播放amr格式。ios 录制的音频位wav格式。 wav转amr可以使用opencore框架

  • 思必驰语音唤醒,录音机噪音数据的处理

    写入的音频文件需要加wav头部信息才能使用普通的播放过器播放,参考 Wav数据格式的44个字节头部信息汇总 and...

  • Android AudioRecord录音 并用 websock

    Android AudioRecord录音 并用 websocket实时传输,AudioTrack 播放wav 音...

  • FFmpeg播放PCM, WAV

    播放PCM步骤 初始化SDL SDL_Init(SDL_INIT_AUDIO) 设置SDL音频参数 SDL_Aud...

  • AudioTooBox

    系统音频播放 震动 播放系统声音 播放自定义音频 自定义音频支持.mp3,.wav等格式,但是音频长度建议在30秒...

  • FPGA使用Delta-sigma ADC实现PDM音频输出【D

    文章代码托管在Delta-sigma-ADC-verilog。quartus目录内包含SDcard .wav播放示...

  • android音视频学习之路任务二

    使用AudioRecord录制音频,并转化成Wav格式,再播放 一 、了解AudioRecord AudioRec...

网友评论

      本文标题:播放 WAV

      本文链接:https://www.haomeiwen.com/subject/crqrkltx.html