来源:https://docs.fileformat.com/audio/wav/
1. WAV File Header
WAV 文件头占用44字节。
貌似第 5-8
字节和第 41-44
字节是0,也不影响 chrome 准确解析 WAV 文件。
WAV 的文件部分应该是 PCM
数据。也就是未压缩的音频数据。
The header of a WAV (RIFF) file is 44 bytes long and has the following format:
Positions | Sample Value | Description |
---|---|---|
1 - 4 | “RIFF” | Marks the file as a riff file. Characters are each 1 byte long. |
5 - 8 | File size (integer) | Size of the overall file - 8 bytes, in bytes (32-bit integer). Typically, you’d fill this in after creation. |
9 -12 | “WAVE” | File Type Header. For our purposes, it always equals “WAVE”. |
13-16 | “fmt " | Format chunk marker. Includes trailing null |
17-20 | 16 | Length of format data as listed above |
21-22 | 1 | Type of format (1 is PCM) - 2 byte integer |
23-24 | 2 | Number of Channels - 2 byte integer |
25-28 | 44100 | Sample Rate - 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz. |
29-32 | 176400 | (Sample Rate * BitsPerSample * Channels) / 8. |
33-34 | 4 | (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo |
35-36 | 16 | Bits per sample |
37-40 | “data” | “data” chunk header. Marks the beginning of the data section. |
41-44 | File size (data) | Size of the data section. |
Sample values are given above for a 16-bit stereo source.
2. 读取 header 信息
#include <stdio.h>
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s files [...]\n", argv[0]);
return 1;
}
for(int i = 1; i < argc; i++) {
const char * filename = argv[i];
FILE *fp = fopen(filename, "rb");
if(!fp) {
printf("open file failed: %s\n", filename);
continue;
}
char byte[64] = {0};
if(fread(byte, 1, sizeof(byte), fp) < 44) {
printf("file is not a WAV file: %s\n", filename);
fclose(fp);
}
printf("magic: ");
for(int i = 0; i < 4; i++) {
printf("%c", byte[i]);
}
printf("\n");
int size = ((int*)(byte + 4))[0];
printf("file size: %d\n", size + 8);
int type = ((short int*)(byte + 20))[0];
printf("format type: %d\n", type);
int fmtlen = ((int*)(byte + 16))[0];
printf("format data length: %d\n", fmtlen);
int channel_number = ((short int*)(byte + 22))[0];
printf("channel number: %d\n", channel_number);
int sample_rate = ((int*)(byte + 24))[0];
printf("sample rate: %d\n", sample_rate);
int bitrate = ((int*)(byte + 28))[0];
printf("bit rate: %d\n", bitrate);
int bitstereo = ((short int*)(byte + 32))[0];
printf("bit stereo: %d\n", bitstereo);
int bits_per_sample = ((short int*)(byte + 34))[0];
printf("Bits per sample: %d\n", bits_per_sample);
int datasize = ((int*)(byte + 40))[0];
printf("data size: %d\n", datasize);
fclose(fp);
}
}
3. 合并多个 WAV 文件
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <strings.h>
int main(int argc, char *argv[]) {
if(argc < 3) {
printf("Usage: %s out.wav Ina.wav Inb.wav [Inc.wav ...]\n", argv[0]);
return 1;
}
const char *outfile = argv[1];
if(access(outfile, F_OK) == 0) {
printf("file already exists: %s\n", outfile);
return 1;
}
FILE *fout = fopen(outfile, "wb");
if(!fout) {
printf("create file fialed: %s\n", outfile);
return 1;
}
int heapsize = sizeof(char) * (1 << 20) * 10; //50MB
char *heapmem = (char*)malloc(heapsize);
bzero(heapmem, heapsize);
char header[44] = {0};
bzero(header, sizeof(header));
int datacount = 0;
for(int i = 2; i < argc; i++) {
const char * infile = argv[i];
FILE *fin = fopen(infile, "rb");
if(!fin) {
printf("open file failed: %s\n", infile);
break;
}
if(header[0] == 0) {
int fcount = fread(header, 1, sizeof(header), fin);
if(fcount != sizeof(header)) {
printf("read wav header from file failed, please check file size: %s\n", infile);
fclose(fin);
break;
}
fwrite(header, 1, 44, fout);
}
fseek(fin, 0L, SEEK_END);
int fsize = ftell(fin);
int datasize = fsize - 44;
if(datasize > heapsize) { //WAV header 44B
printf("data size is great than %d\n", heapsize);
fclose(fin);
break;
}
fseek(fin, 44L, SEEK_SET);
if(fread(heapmem, 1, datasize, fin) != datasize) {
printf("read file failed: %s\n", infile);
fclose(fin);
break;
}
printf("current offset: %d\n", ftell(fout));
if(fwrite(heapmem, 1, datasize, fout) != datasize) {
printf("write to file failed: %s\n", outfile);
fclose(fin);
break;
}
datacount += datasize;
printf("concat file %s to %s success \n", infile, outfile);
}
free(heapmem);
datacount = 0; // XXX
fseek(fout, 40L, SEEK_SET);
fwrite(&datacount, 1, sizeof(datacount), fout);
fseek(fout, 0L, SEEK_END);
int fsize = ftell(fout) - 8;
fsize = 0; // XXX
fseek(fout, 4L, SEEK_SET);
fwrite(&fsize, 1, sizeof(fsize), fout);
fclose(fout);
return 0;
}