接着跟着雷神学,雷神的代码是定义了三个结构体,将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,因为有左右两个声道。