【问题标题】:printing of a wav header in c在 c 中打印 wav 标头
【发布时间】:2013-06-26 11:22:34
【问题描述】:

您好,我有此代码用于将 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);
    }
}

【问题讨论】:

  • 您是否尝试过使用任何其他工具查看您的.wav 文件的标题?也许您期望的值不正确,但您的程序正在打印正确的值。
  • 一个字:对齐。 (也许也是:填充。)
  • 在 wav 文件中的音频格式和通道数为 01 00 02 00。因此 0001 用于音频格式,0002 用于通道数。所以我期待它输出 audioFormat: 1 和 numChannels 2

标签: c wav


【解决方案1】:

原因是您的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)

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

【讨论】:

    【解决方案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 &lt;endian.h&gt; 你可以使用 le32tohle16toh 来阅读(以及他们的对应物 htole32htole16 来写)。

    【讨论】:

    • 谢谢各位的回复。我将 subchunk1Size 从 word 更改为 dword,现在一切都很好。我仍然不明白的是,我想对字节序要小心,但只有我发布的代码一切都很好。这是因为我在 ubuntu linux 12.04 上运行它的原因吗?是不是所有的linux都一样?
    • 字节顺序实际上取决于 CPU,而不是操作系统。因此,如果您在 x86 或 x86_64 上运行,您的 CPU 已经设置为 little-endian。实际上,现在大端非常罕见,一些 ARM 设置为 BE,一些 SPARC。它出现在嵌入式编程中,但通常不会出现在桌面/移动设备上。但是,当您尝试将代码移植到 BE 处理器并且必须稍后修复它时,它确实很糟糕。更多信息:en.wikipedia.org/wiki/Endianness
    猜你喜欢
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 2021-01-12
    相关资源
    最近更新 更多