【音视频学习】C++将PCM16LE双声道音频采样数据转换为WAVE格式音频数据

接着跟着雷神学,雷神的代码是定义了三个结构体,将WAVE文件头定义为了三个结构体,便于理解,我就继续通过C++拙劣模仿一下,将他们放在了一个结构体一起赋值。WAVE文件头部信息可以看这篇博客WAV头文件详解

代码

#include <iostream>
#include <cstdint>
#include <fstream>
#include <cstring>

using namespace std;

// WAVE文件格式头部信息
struct WAVEHeader {
    char chunkID[4]; // 'RIFF'
    uint32_t chunkSize;
    char format[4]; // 'WAVE'
    char subChunk1ID[4]; // 'fmt '
    uint32_t subChunk1Size;
    uint16_t audioFormat;
    uint16_t numChannels;
    uint32_t sampleRate;
    uint32_t byteRate;
    uint16_t blockAlign;
    uint16_t bitsPerSample;
    char subChunk2ID[4]; // 'data'
    uint32_t subChunk2Size;
};

//将双声道的数据格式转化为WAVE格式音频数据  传入输入文件 输出文件 以及采样数
bool pcm_to_wave(const char* input_file, const char* out_file,uint32_t num_samples) {
    // 打开输入文件
    ifstream infile(input_file, ios::binary);
    if (!infile)
    {
        cout << "input file error!" << endl;
        return false;
    }
    ofstream outfile(out_file, ios::binary);
    if (!outfile)
    {
        cout << "input outfile error!" << endl;
        return false;
    }

    // 计算文件头部信息
    uint32_t num_channels = 2; // 双声道
    uint32_t sample_rate = 44100; // 采样率
    uint16_t bits_per_sample = 16; // 每个采样点占用位数
    uint32_t byte_rate = sample_rate * num_channels * bits_per_sample / 8;
    uint16_t block_align = num_channels * bits_per_sample / 8;
    uint32_t sub_chunk2_size = num_samples * num_channels * bits_per_sample / 8;
    uint32_t chunk_size = 36 + sub_chunk2_size;
    uint32_t sub_chunk1_size = 16;

    // 填充文件头部信息
    WAVEHeader wave_header;
    memcmp(wave_header.chunkID, "RIFF", strlen("RIFF"));
    memcmp(wave_header.format, "WAVE", strlen("WAVE"));
    memcmp(wave_header.subChunk1ID, "fmt", strlen("fmt"));
    memcmp(wave_header.subChunk2ID, "data", strlen("data"));
    wave_header.chunkSize = chunk_size;
    wave_header.subChunk1Size = sub_chunk1_size;
    wave_header.audioFormat = 1; // PCM
    wave_header.numChannels = num_channels;
    wave_header.sampleRate = sample_rate;
    wave_header.byteRate = byte_rate;
    wave_header.blockAlign = block_align;
    wave_header.bitsPerSample = bits_per_sample;
    wave_header.subChunk2Size = sub_chunk2_size;

    // 写入文件头部信息
    outfile.write((char*)&wave_header, sizeof(wave_header));

    // 读取PCM16LE双声道音频采样数据,并写入输出文件
    int16_t sample; // 采样值
    for (uint32_t i = 0; i < num_samples; i++) {
        infile.read((char*)&sample, sizeof(sample));
        outfile.write((char*)&sample, sizeof(sample));
        infile.read((char*)&sample, sizeof(sample));
        outfile.write((char*)&sample, sizeof(sample));
    }

    // 关闭文件
    infile.close();
    outfile.close();

    return true;

}

int main(void)
{
    const char* input_file = "NocturneNo2inEflat_44.1k_s16le.pcm";
    const char* output_file = "output.wav";
    uint32_t num_samples = 44100 * 2; // 1秒钟的采样数

    if (pcm_to_wave(input_file, output_file, num_samples)) {
        cout << "pcm to wave finish" << endl;
    }

    return 0;
}

需要说明的是,这里传入了一秒中的采样数为44100 * 2,因为有左右两个声道。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值