WAVE音频文件格式分析--实现C语言读写文件头

本文将详细分析WAVE音频文件的格式,并通过C语言对wave文件头进行读写操作。


WAVE音频文件格式分析–实现C语言读写文件头

WAVE音频文件

WAVE文件格式是一种由微软和IBM联合开发的用于音频数字存储的标准, 它采用RIFF(Resource Interchange File Format,资源交换文件标准)文件格式结构文件的扩展名为“WAV”, 所有的WAV都有一个文件头, 数据本身的格式为PCM或压缩型.

WAVE文件头

WAVE文件分成两部分:文件头和数据块. WAV格式文件主要有两种文件头: 标准的44字节文件头和经过了一些软件处理的58字节文件头.
WAVE文件头包含RIFF数据块,一个“fmt”数据块和一个“data”数据块

本文所介绍的WAV文件头是标准的44字节文件头.

WAVE文件格式

wave format

纠正: ByteRate应该为每秒存储的字节数

通过WAVE文件头信息,我们可以计算出播放时长:

1
文件播放时长 = Subchunk2Size/ByteRate

C语言实现对WAVE文件头的读写

这里我提供了几个接口供大家使用,handle_wave.chandle_wave.h.

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
#ifndef _HANDLE_WAVE_H
#define _HANDLE_WAVE_H
typedef struct
{
char riff_id[4]; //"RIFF"
int riff_datasize; // RIFF chunk data size,exclude riff_id[4] and riff_datasize,total - 8
char riff_type[4]; // "WAVE"
char fmt_id[4]; // "fmt "
int fmt_datasize; // fmt chunk data size,16 for pcm
short fmt_compression_code; // 1 for PCM
short fmt_channels; // 1(mono) or 2(stereo)
int fmt_sample_rate; // samples per second
int fmt_avg_bytes_per_sec; // sample_rate * channels * bit_per_sample / 8
short fmt_block_align; // number bytes per sample, bit_per_sample * channels / 8
short fmt_bit_per_sample; // bits of each sample(8,16,32).
char data_id[4]; // "data"
int data_datasize; // data chunk size,pcm_size - 44
}WaveHeader_t;
void init_wavheader(WaveHeader_t *wavheader);
int read_wavheader(FILE *fp,WaveHeader_t *wavheader);
int write_wavheader(FILE *fp,WaveHeader_t wavheader);
void print_wavheader(WaveHeader_t wavheader);
#endif

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <stdio.h>
#include <stdlib.h>
#include "handle_wave.h"
/* read and write integer from file stream */
static int get_int(FILE *fp)
{
char *s;
int i;
s = (char *)&i;
size_t len = sizeof(int);
int n = 0;
for(;n < len;n++)
{
s[n]=getc(fp);
//printf("%x\n",s[n]);
}
return i;
}
static int put_int(int i,FILE *fp)
{
char *s;
s=(char *)&i;
size_t len = sizeof(int);
int n = 0;
for(;n < len;n++)
{
putc(s[n],fp);
//printf("%x\n",s[n]);
}
return i;
}
static short int get_sint(FILE *fp)
{
char *s;
short int i;
s = (char *)&i;
size_t len = sizeof(short);
int n = 0;
for(;n < len;n++)
{
s[n]=getc(fp);
//printf("%x\n",s[n]);
}
return i;
}
static short int put_sint(short int i,FILE *fp)
{
char *s;
s=(char *)&i;
size_t len = sizeof(short);
int n = 0;
for(;n < len;n++)
{
putc(s[n],fp);
//printf("%x\n",s[n]);
};
return i;
}
void init_wavheader(WaveHeader_t *wavheader)
{
sprintf(wavheader->riff_id,"RIFF");
wavheader->riff_datasize = -1;
sprintf(wavheader->riff_type,"WAVE");
sprintf(wavheader->fmt_id,"fmt ");
wavheader->fmt_datasize = 16;
wavheader->fmt_compression_code = 1;
wavheader->fmt_channels = -1;
wavheader->fmt_sample_rate = -1;
wavheader->fmt_avg_bytes_per_sec = -1;
wavheader->fmt_block_align = -1;
wavheader->fmt_bit_per_sample = 16;
sprintf(wavheader->data_id,"data");
wavheader->data_datasize = -1;
}
int read_wavheader(FILE *fp,WaveHeader_t *wavheader)
{
if (fp ==NULL)
return -1;
fread(wavheader->riff_id,4,1,fp);
wavheader->riff_datasize = get_int(fp);
fread(wavheader->riff_type,4,1,fp);
fread(wavheader->fmt_id,4,1,fp);
wavheader->fmt_datasize = get_int(fp);
wavheader->fmt_compression_code = get_sint(fp);
wavheader->fmt_channels = get_sint(fp);
wavheader->fmt_sample_rate = get_int(fp);
wavheader->fmt_avg_bytes_per_sec = get_int(fp);
wavheader->fmt_block_align = get_sint(fp);
wavheader->fmt_bit_per_sample = get_sint(fp);
fread(wavheader->data_id,4,1,fp);
wavheader->data_datasize = get_int(fp);
return 0;
}
int write_wavheader(FILE *fp,WaveHeader_t wavheader)
{
if (fp ==NULL)
return -1;
fwrite(wavheader.riff_id,4,1,fp);
put_int(wavheader.riff_datasize,fp);
fwrite(wavheader.riff_type,4,1,fp);
fwrite(wavheader.fmt_id,4,1,fp);
put_int(wavheader.fmt_datasize,fp);
put_sint(wavheader.fmt_compression_code,fp);
put_sint(wavheader.fmt_channels,fp);
put_int(wavheader.fmt_sample_rate,fp);
put_int(wavheader.fmt_avg_bytes_per_sec,fp);
put_sint(wavheader.fmt_block_align,fp);
put_sint(wavheader.fmt_bit_per_sample,fp);
fwrite(wavheader.data_id,4,1,fp);
put_int(wavheader.data_datasize,fp);
return 0;
}
void print_wavheader(WaveHeader_t wavheader)
{
printf("wavheader.riff_id: %c%c%c%c\n",wavheader.riff_id[0],wavheader.riff_id[1],wavheader.riff_id[2],wavheader.riff_id[3]);
printf("wavheader.riff_datasize: %d\n",wavheader.riff_datasize);
printf("wavheader.riff_type: %c%c%c%c\n",wavheader.riff_type[0],wavheader.riff_type[1],wavheader.riff_type[2],wavheader.riff_type[3]);
printf("wavheader.fmt_id: %c%c%c%c\n",wavheader.fmt_id[0],wavheader.fmt_id[1],wavheader.fmt_id[2],wavheader.fmt_id[3]);
printf("wavheader.fmt_datasize: %d\n",wavheader.fmt_datasize);
printf("wavheader.fmt_compression_code: %hd\n",wavheader.fmt_compression_code);
printf("wavheader.fmt_channels: %hd\n",wavheader.fmt_channels);
printf("wavheader.fmt_sample_rate: %d\n",wavheader.fmt_sample_rate);
printf("wavheader.fmt_avg_bytes_per_sec: %d\n",wavheader.fmt_avg_bytes_per_sec);
printf("wavheader.fmt_block_align: %hd\n",wavheader.fmt_block_align);
printf("wavheader.fmt_bit_per_sample: %hd\n",wavheader.fmt_bit_per_sample);
printf("wavheader.data_id: %c%c%c%c\n",wavheader.data_id[0],wavheader.data_id[1],wavheader.data_id[2],wavheader.data_id[3]);
printf("wavheader.data_datasize: %d\n",wavheader.data_datasize);
}

About me

forthebadge

Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。