WAV文件格式

WAV是一种常用的音频文件格式, 主要有信息头+数据构成, 数据一般是PCM(脉冲编码调制), 这个信息头就是对PCM数据的描述, 包括采样率、数据长度、通道数、每个通道的字节数等等信息, 播放器依靠这些信息才能正确播放PCM内容.

PCM数据采集

一般的输入设备, 如麦克风提供PCM格式的数据输出,PCM格式的数据是无损的, 基本上所有的播放设备都支持播放, 因为是原始的声音信息, 由模拟信号转换而来,数据中存在大量时间冗余和空间冗余。数据量比较大。

PCM生成WAV

WAV 格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <ctype.h>

#pragma pack(1)
typedef unsigned char byte;
typedef struct WAVHeader {
// big endian
char no[4];
// little endian
uint32_t size;
// big endian
char format[4];
char formatTag[4];
// little endian
uint32_t formatTagSize;
// little endian
uint16_t audioFormat;
uint16_t audioChannel;
uint32_t audioSampleRate;
uint32_t audioByteRate;
uint16_t audioBlockAlign;
uint16_t audioBitsPerSample;

// big endian
char dataTag[4];
uint32_t dataTagSize;
} WAVHeader;
#pragma pack()

// #define s2l(s) (s << 8 & 0xFF00) | (s >> 8 & 0xFF)
// #define i2l(i) \
// (i >> 24 & 0xFF) | (i >> 8 & 0xFF00) | (i << 8 & 0xFF0000) | \
// (i << 24 & 0xFF000000)
#define s2l(s) s
#define i2l(i) i

int main(int argc, char ** argv) {
if (argc != 3) {
printf("Usage: ./wav <pcm-file-path> <save-wav-file-path>\n");
return -1;
}

const char * wavPath = argv[2];
FILE * file = fopen(wavPath, "w+b");
if (!file) {
fprintf(stderr, "error occur %s\n", strerror(errno));
return -1;
}

const char * dataPath = argv[1];
FILE * pcmFile = fopen(dataPath, "r");
if (!pcmFile) {
fprintf(stderr, "error occur %s\n", strerror(errno));
return -1;
}

struct stat pcmFileStat;
fstat(pcmFile->_file, &pcmFileStat);
size_t dataSize = pcmFileStat.st_size;
printf("pcm file size %ld\n", dataSize);

WAVHeader header = {.no = {'R', 'I', 'F', 'F'},
.size = i2l((dataSize + 36)),
.format = {'W', 'A', 'V', 'E'},
.formatTag = {'f', 'm', 't', ' '},
.formatTagSize = i2l(16),
.audioFormat = s2l(1),
.audioChannel = s2l(1),
.audioSampleRate = i2l(44100),
.audioByteRate = i2l(88200),
.audioBlockAlign = s2l(4),
.audioBitsPerSample = s2l(16),
.dataTag = {'d', 'a', 't', 'a'},
.dataTagSize = i2l(dataSize)};

fwrite(&header, sizeof(WAVHeader), 1, file);
byte * buff = new byte[128];
int sizeRead = 0;
while ((sizeRead = fread(buff, 1, 128, pcmFile)) != 0) {
fwrite(buff, 1, sizeRead, file);
}
delete[] buff;
fclose(pcmFile);
fclose(file);
return 0;
}

参考链接