用c语言打印wav头文件

用c语言打印wav头文件,c,wav,C,Wav,嗨,我有这段代码,用于输入一个wav文件,然后将wah头放入一个结构,然后输出它。除了audioFormat和NumChannel之外,其他都很好,但我不明白为什么。例如,它应该输出audioFormat:1和NumChannel:2,但它输出audioFormat:0和NumChannel:1。我不明白为什么会这样 typedef struct wavHeader { byte chunckID[4]; dword chunckSize; byte format[4];

嗨,我有这段代码,用于输入一个wav文件,然后将wah头放入一个结构,然后输出它。除了audioFormat和NumChannel之外,其他都很好,但我不明白为什么。例如,它应该输出audioFormat:1和NumChannel:2,但它输出audioFormat:0和NumChannel: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);
    }
}

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

实际上,您的结构在内存中的布局可能如下所示:

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

旁注:在编写此响应时,我突然想到,您可能还必须注意wave头中多字节值的不同endianness

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

实际上,您的结构在内存中的布局可能如下所示:

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

旁注:在编写此响应时,我突然想到,您可能还必须注意wave头中多字节值的不同endianness

subchunk1Size
应该是一个
dword
,而不是
word
(参见示例)。您的其他块大小声明正确


因为您还需要指定包装,并担心端度。WAV头是16位压缩的,并且是小端。对于
gcc
,我更喜欢在结构声明之前使用
#pragma-pack(push,2)
,在结构声明之后使用
#pragma-pack(pop)
。如果你使用
#include
,你可以使用
le32toh
le16toh
来阅读(以及它们的对应项
htole32
htole16
来写)。

subchunk1Size
应该是
dword
,而不是
单词
(例如,请参见)。您的其他块大小声明正确


因为您还需要指定包装,并担心端度。WAV头是16位压缩的,并且是小端。对于
gcc
,我更喜欢在结构声明之前使用
#pragma-pack(push,2)
,在结构声明之后使用
#pragma-pack(pop)
。如果您
#include
,您可以使用
le32toh
le16toh
来阅读(以及它们对应的
htole32
htole16
来写)。

您是否尝试过使用其他工具查看
.wav
文件的标题?也许您期望的值不正确,但您的程序正在打印正确的值。一个词:对齐。(可能也是:填充)wav文件中的音频格式annd num通道为01 00 02 00。因此0001表示音频格式,0002表示num通道。所以我希望它能输出audioFormat:1和numChannels 2您是否尝试过使用其他工具查看
.wav
文件的标题?也许您期望的值不正确,但您的程序正在打印正确的值。一个词:对齐。(可能也是:填充)wav文件中的音频格式annd num通道为01 00 02 00。因此0001表示音频格式,0002表示num通道。所以我希望它能输出audioFormat:1和numChannels 2TNX,以供其他人使用。我把尺寸从word改为dword,现在一切都好了。我仍然不明白的是,我应该对endianess保持谨慎,但仅仅是我发布的代码,一切都很好。这是因为我在ubuntu linux 12.04上运行它吗?所有linux都是一样的吗?Endianness实际上取决于CPU,而不是操作系统。因此,如果您在x86或x86_64上运行,那么您的CPU已经为little endian设置好了。事实上,现在大端星已经很少见了,一些武器已经安装好了,还有一些斯巴克。它出现在许多嵌入式编程中,但通常不在桌面/移动设备上。不过,当您尝试将代码移植到BE处理器并在以后进行修复时,它确实很糟糕。更多信息:Thnx的回复家伙。我把尺寸从word改为dword,现在一切都好了。我仍然不明白的是,我应该对endianess保持谨慎,但仅仅是我发布的代码,一切都很好。这是因为我在ubuntu linux 12.04上运行它吗?所有linux都是一样的吗?Endianness实际上取决于CPU,而不是操作系统。因此,如果您在x86或x86_64上运行,那么您的CPU已经为little endian设置好了。事实上,现在大端星已经很少见了,一些武器已经安装好了,还有一些斯巴克。它出现在许多嵌入式编程中,但通常不在桌面/移动设备上。不过,当您尝试将代码移植到BE处理器并在以后进行修复时,它确实很糟糕。更多信息: