问题
Hi i have this code for taking as input a wav file and then putting the wah header into a struct and then output it. Everything is good except audioFormat and numChannels but i can't understand why.For example it should output audioFormat: 1 and numChannels: 2 but it outputs audioFormat:0 and numChannels: 1 . I can't understand why this happens.
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);
}
}
回答1:
subchunk1Size
should be a dword
, not a word
(see http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html for instance). Your other chunk sizes are declared correctly.
As djf points out you also need to specify the packing and worry about endianness. The WAV header is 16-bit packed, and little-endian. With gcc
, I prefer to use #pragma pack(push, 2)
before the struct declaration, and #pragma pack(pop)
after. And if you #include <endian.h>
you can use le32toh
and le16toh
to read (and their counterparts htole32
and htole16
to write).
回答2:
The reason is that your struct wavHeader
doesn't really look like you think it does. Let me explain. The C compiler is allowed to change the alignment of the fields in a struct. Typically that means fields are aligned at 4-byte or 8-byte-boundaries. See this discussion about C struct memory layout.
In effect your struct might be laid out something like this in memory:
Byte 1 2 3 4
+------+------+------+------+
| chunckID |
+------+------+------+------+
| chunckSize |
+------+------+------+------+
| format |
+------+------+------+------+
| subchunk1ID |
+------+------+------+------+
|subchunk1Size| ~~~~~ ~~~~~ << padding
+------+------+------+------+
| audioFormat | ~~~~~ ~~~~~ << padding
+------+------+------+------+
| numChannels | ~~~~~ ~~~~~ << padding
+------+------+------+------+
....
So you see the fields subchunk1Size
, audioFormat
and numChannels
are not contiguous! However, you can use the directive #pragma pack
to enforce the layout you intended. Like this:
#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)
Sidenote: When writing this response it occurred to me that you probably also have to be careful about different endianness of multibyte values in the wave header.
来源:https://stackoverflow.com/questions/17318685/printing-of-a-wav-header-in-c