1

嗨,我有此代码用于将 wav 文件作为输入,然后将 wah 标头放入结构中,然后将其输出。一切都很好,除了 audioFormat 和 numChannels 但我不明白为什么。例如它应该输出 audioFormat: 1 和 numChannels: 2 但它输出 audioFormat:0 和 numChannels: 1 。我不明白为什么会这样。

typedef struct wavHeader
{
    byte chunckID[4];
    dword chunckSize;
    byte format[4];
    byte subchunk1ID[4];
    word subchunk1Size;
    word audioFormat;
    word numChannels;
    dword sampleRate;
    dword byteRate;
    word blockAlign;
    word bitsPerSample;
    byte subchunk2ID[4];
    dword subchunk2Size;
}wav_header;

int check_file_name(char *filename);

void list(char **array) //argv
{
    wav_header wavHeader;
    FILE *pFile;
    if(check_file_name(array[2]) == 0)
    {
        printf("wrong file name\n");
        exit(1);
    }
    pFile = fopen (array[2] ,"r");
    if( pFile != NULL)
    {
        fread(&wavHeader, sizeof(wav_header), 1, pFile);
        fclose(pFile);
        printf("ChunkID: %c%c%c%c\n",wavHeader.chunckID[0],wavHeader.chunckID[1],wavHeader.chunckID[2],wavHeader.chunckID[3]);
        printf("ChunkSize: %d\n",wavHeader.chunckSize);
        printf("Format: %c%c%c%c\n",wavHeader.format[0],wavHeader.format[1],wavHeader.format[2],wavHeader.format[3]);
        printf("SubChunk1ID: %c%c%c%c\n",wavHeader.subchunk1ID[0],wavHeader.subchunk1ID[1],wavHeader.subchunk1ID[2],wavHeader.subchunk1ID[3]);
        printf("Subchunk1Size: %d\n",wavHeader.subchunk1Size);
        printf("AudioFormat: %d\n",wavHeader.audioFormat);
        printf("NumChannels: %d\n",wavHeader.numChannels); 
        printf("SampleRate: %d\n",wavHeader.sampleRate);
        printf("ByteRate: %d\n",wavHeader.byteRate);     
        printf("BlockAlign: %d\n",wavHeader.blockAlign);   
        printf("BitsPerSample: %d\n",wavHeader.bitsPerSample);
        printf("Subchunk2ID: %c%c%c%c\n",wavHeader.subchunk2ID[0],wavHeader.subchunk2ID[1],wavHeader.subchunk2ID[2],wavHeader.subchunk2ID[3]);
        printf("Subchunk2Size: %d\n",wavHeader.subchunk2Size);
    }
    else
    {
        printf("This file doesn't exit\n");
        exit(1);
    }
}
4

2 回答 2

4

原因是你struct wavHeader看起来并不像你想象的那样。让我解释。允许 C 编译器更改结构中字段的对齐方式。通常这意味着字段在 4 字节或 8 字节边界处对齐。请参阅有关C 结构内存布局的讨论。

实际上,您的结构可能会在内存中布置如下:

Byte  1       2      3      4
   +------+------+------+------+
   |          chunckID         |
   +------+------+------+------+
   |         chunckSize        |
   +------+------+------+------+ 
   |           format          |
   +------+------+------+------+
   |        subchunk1ID        |
   +------+------+------+------+
   |subchunk1Size| ~~~~~ ~~~~~   << padding
   +------+------+------+------+   
   | audioFormat | ~~~~~ ~~~~~   << padding
   +------+------+------+------+
   | numChannels | ~~~~~ ~~~~~   << padding
   +------+------+------+------+
   ....

所以你看到的领域subchunk1SizeaudioFormat并不numChannels连续!但是,您可以使用该指令#pragma pack来强制执行您想要的布局。像这样:

#pragma pack(push, 1) // exact fit - align at byte-boundary, no padding

typedef struct wavHeader
{
    byte chunckID[4];
    dword chunckSize;
    byte format[4];
    byte subchunk1ID[4];
    word subchunk1Size;
    word audioFormat;
    word numChannels;
    dword sampleRate;
    dword byteRate;
    word blockAlign;
    word bitsPerSample;
    byte subchunk2ID[4];
    dword subchunk2Size;
} wavHeader;

#pragma pack(pop)

旁注:在编写此响应时,我想到您可能还必须注意波头中多字节值的不同字节顺序。

于 2013-06-26T11:44:46.687 回答
2

subchunk1Size应该是 a dword,而不是 a word(例如参见http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html)。您的其他块大小已正确声明。

正如djf 指出的那样,您还需要指定打包并担心字节顺序。WAV 标头是 16 位压缩的,并且是 little-endian。使用gcc,我更喜欢#pragma pack(push, 2)在结构声明之前和#pragma pack(pop)之后使用。如果你#include <endian.h>可以使用le32tohle16toh阅读(以及他们的对应物htole32htole16写作)。

于 2013-06-26T12:01:52.870 回答