在c中打印wav标题

时间:2013-06-26 11:22:35

标签: c wav

您好我有这个代码,用于输入一个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);
    }
}

2 个答案:

答案 0 :(得分:4)

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

实际上你的结构可能在内存中布局了这样的东西:

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

因此,您看到字段subchunk1SizeaudioFormatnumChannels不是连续的!但是,您可以使用指令#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)

旁注:在编写此响应时,我发现您可能还需要注意波头中多字节值的不同字节顺序。

答案 1 :(得分:2)

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

作为djf points out,您还需要指定包装并担心字节顺序。 WAV头是16位打包和little-endian。使用gcc,我更喜欢在结构声明之前使用#pragma pack(push, 2),之后使用#pragma pack(pop)。如果您#include <endian.h>,您可以使用le32tohle16toh阅读(以及他们的同行htole32htole16来撰写)。