使用 c 语言读取 wav 文件的 header 头信息 拼接 wav 文件

创建日期: 2024-01-11 17:21 | 作者: 风波 | 浏览次数: 13 | 分类: C++

来源: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;
}
13 浏览
9 爬虫
0 评论