linux声音框架alsa的api学习之wav文件解析

一、什么是 WAV 文件格式

WAV 文件是一种常见的无损音频文件格式,它就像是一个装着音频数据的 “盒子”,这个 “盒子” 有特定的结构,规定了音频的各种信息,比如采样率、声道数、音频数据等。我们可以把 WAV 文件想象成一个多层的蛋糕,每一层都有不同的含义和作用。

二、WAV 文件的结构

WAV 文件主要由三个部分组成:
 

文件头(RIFF 块):包含文件类型和整体大小信息。                    RIFF 块通常是 12 字节

格式块(fmt 块) :存储音频的格式参数,如采样率、声道数、采样位数等。 fmt 块通常是 24 字节(对于 PCM 格式)

数据块(data 块):存放实际的音频数据。                          再加上 data 块的 8 字节头部信息

下面我们来详细看看每个部分。

1. 文件头(RIFF 块)

这就像是蛋糕的最顶层,告诉我们这是一个 WAV 文件。它包含了文件的基本信息,比如文件的类型和大小。具体来说,它有以下几个重要的信息:

  • Chunk ID:固定为 "RIFF",表示这是一个 RIFF 格式的文件。
  • Chunk Size:表示整个文件的大小减去 8 字节(Chunk ID 和 Chunk Size 本身的大小)。
  • Format:固定为 "WAVE",表示这是一个 WAV 文件。

下面是一个简单的 C 语言代码示例,用于读取 RIFF 块的信息:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    char chunk_id[4];
    uint32_t chunk_size;
    char format[4];
} RiffHeader;

void read_riff_header(FILE *file) {
    RiffHeader header;
    fread(&header, sizeof(RiffHeader), 1, file);
    printf("Chunk ID: %.*s\n", 4, header.chunk_id);
    printf("Chunk Size: %u\n", header.chunk_size);
    printf("Format: %.*s\n", 4, header.format);
}

int main() {
    FILE *file = fopen("test.wav", "rb");
    if (file == NULL) {
        perror("Failed to open file");
        return 1;
    }
    read_riff_header(file);
    fclose(file);
    return 0;
}
2. 格式块(fmt 块)

格式块就像是蛋糕的中间层,它描述了音频的具体格式信息,比如采样率、声道数、采样位数等。具体信息如下:

  • Subchunk1 ID:固定为 "fmt ",表示这是格式块。
  • Subchunk1 Size:表示格式块的大小,通常为 16 字节(PCM 格式)。
  • Audio Format:表示音频的编码格式,常见的 PCM 格式值为 1。
  • Num Channels:表示声道数,比如 1 表示单声道,2 表示立体声。
  • Sample Rate:表示采样率,即每秒采样的次数,常见的采样率有 44100Hz、48000Hz 等。
  • Byte Rate:表示每秒的数据字节数,可以通过 Sample Rate * Num Channels * Bits Per Sample / 8 计算得到。
  • Block Align:表示每个采样帧的字节数,可以通过 Num Channels * Bits Per Sample / 8 计算得到。
  • Bits Per Sample:表示每个采样点的位数,常见的有 16 位、24 位等。

下面是一个简单的 C 语言代码示例,用于读取格式块的信息:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    char subchunk1_id[4];
    uint32_t subchunk1_size;
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
} FmtHeader;

void read_fmt_header(FILE *file) {
    FmtHeader header;
    fread(&header, sizeof(FmtHeader), 1, file);
    printf("Subchunk1 ID: %.*s\n", 4, header.subchunk1_id);
    printf("Subchunk1 Size: %u\n", header.subchunk1_size);
    printf("Audio Format: %u\n", header.audio_format);
    printf("Num Channels: %u\n", header.num_channels);
    printf("Sample Rate: %u\n", header.sample_rate);
    printf("Byte Rate: %u\n", header.byte_rate);
    printf("Block Align: %u\n", header.block_align);
    printf("Bits Per Sample: %u\n", header.bits_per_sample);
}

int main() {
    FILE *file = fopen("test.wav", "rb");
    if (file == NULL) {
        perror("Failed to open file");
        return 1;
    }
    // 跳过 RIFF 块
    fseek(file, sizeof(RiffHeader), SEEK_SET);
    read_fmt_header(file);
    fclose(file);
    return 0;
}
3. 数据块(data 块)

数据块是蛋糕的最底层,它包含了真正的音频数据。具体信息如下:

  • Subchunk2 ID:固定为 "data",表示这是数据块。
  • Subchunk2 Size:表示音频数据的大小,即数据块的字节数。
  • Data:真正的音频数据,按照格式块中指定的格式存储。

下面是一个简单的 C 语言代码示例,用于读取数据块的信息:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    char subchunk2_id[4];
    uint32_t subchunk2_size;
} DataHeader;

void read_data_header(FILE *file) {
    DataHeader header;
    fread(&header, sizeof(DataHeader), 1, file);
    printf("Subchunk2 ID: %.*s\n", 4, header.subchunk2_id);
    printf("Subchunk2 Size: %u\n", header.subchunk2_size);

    // 读取音频数据
    char *data = (char *)malloc(header.subchunk2_size);
    fread(data, 1, header.subchunk2_size, file);
    // 这里可以对音频数据进行处理
    free(data);
}

int main() {
    FILE *file = fopen("test.wav", "rb");
    if (file == NULL) {
        perror("Failed to open file");
        return 1;
    }
    // 跳过 RIFF 块和 FMT 块
    fseek(file, sizeof(RiffHeader) + sizeof(FmtHeader), SEEK_SET);
    read_data_header(file);
    fclose(file);
    return 0;
}

在标准的 WAV 文件格式中,RIFF 块和 fmt 块的字节数情况如下:

1. RIFF 块

RIFF(Resource Interchange File Format)块是 WAV 文件的文件头部分,其固定大小为 12 字节,各字段及其占用字节数如下:

字段名字节数描述
ChunkID4 字节固定为字符串 "RIFF",用于标识这是一个 RIFF 格式的文件。
ChunkSize4 字节表示整个文件的大小减去 8 字节(ChunkID 和 ChunkSize 本身所占的字节数),是一个 32 位无符号整数。
Format4 字节固定为字符串 "WAVE",表明这是一个 WAV 音频文件。

2. fmt 块

fmt(Format)块描述了音频数据的格式信息,其大小通常有两种情况:

标准 PCM 格式

对于最常见的线性脉冲编码调制(PCM)格式的 WAV 文件,fmt 块的固定大小为 16 字节,各字段及其占用字节数如下:

字段名字节数描述
Subchunk1ID4 字节固定为字符串 "fmt ",用于标识这是 fmt 块。
Subchunk1Size4 字节表示 fmt 块的大小,对于 PCM 格式通常为 16。
AudioFormat2 字节音频编码格式,PCM 格式的值为 1。
NumChannels2 字节声道数,例如 1 表示单声道,2 表示立体声。
SampleRate4 字节采样率,即每秒采样的次数,常见值如 44100Hz、48000Hz 等。
ByteRate4 字节每秒的数据字节数,可通过 SampleRate * NumChannels * BitsPerSample / 8 计算得出。
BlockAlign2 字节每个采样帧的字节数,可通过 NumChannels * BitsPerSample / 8 计算得出。
BitsPerSample2 字节每个采样点的位数,常见的有 8 位、16 位、24 位等。
非标准或扩展格式

当 WAV 文件采用非 PCM 格式(如压缩格式)或者包含额外的扩展信息时,fmt 块的大小会超过 16 字节。例如,当存在扩展参数时,Subchunk1Size 的值可能会是 18 或 40 等,这取决于具体的扩展内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu-Eleven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值