0
votes

I use a struct for reading Wav-Files in audio format 3 (=IEEE FLOAT 32 Bit) with a 58 byte wav-header. The problem: Byte 38 starts with the "fact" chunk. This seems to be ok. DwFactSize should have an offset of 42. Here the problem begins! The offset is 44 !!! First I thought, the problem is in padding bits. So I tried uints, unsigned chars and attribute((packed)). This doesn't change anything.

This is the definition of the wav header:

0 - 3 'RIFF'/'RIFX' Little/Big-endian

4 - 7 wRiffLength length of file minus the 8 byte riff header

8 - 11 'WAVE'

12 - 15 'fmt '

16 - 19 wFmtSize length of format chunk minus 8 byte header

20 - 21 wFormatTag identifies PCM, ULAW etc

22 - 23 wChannels

24 - 27 dwSamplesPerSecond samples per second per channel

28 - 31 dwAvgBytesPerSec non-trivial for compressed formats

32 - 33 wBlockAlign basic block size

34 - 35 wBitsPerSample non-trivial for compressed formats

(until byte 35 like the usual 44 byte header)

36 - 37 wExtSize = 0 the length of the format extension

38 - 41 'fact'

42 - 45 dwFactSize = 4 length of the fact chunk minus 8 byte header

46 - 49 dwSamplesWritten actual number of samples written out

50 - 53 'data'

54 - 57 dwDataLength length of data chunk minus 8 byte header


output:

...

until here ... correct...

Fact[4] 38

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DwFactSize 44

dwSamplesWritten 48

Data[4] 52

dwDataLength 56

Quick hack to show the offset problem:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <cstddef>

typedef struct  WAV_HEADER
{
unsigned char       RIFF[4];        /* RIFF Header      */ //Magic header
unsigned long       ChunkSize;      /* RIFF Chunk Size  */
unsigned char       WAVE[4];        /* WAVE Header      */
unsigned char       fmt[4];         /* FMT header       */
unsigned long       Subchunk1Size;  /* Size of the fmt chunk: 16=PCM, 18=IEEE Float, 40=Extensible                     */
unsigned short      AudioFormat;    /* Audio format 1=PCM, 3=IEEE Float, 6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM, 65534=Extensible */
unsigned short      NumOfChan;      /* Number of channels 1=Mono 2=Stereo                   */
unsigned long       SamplesPerSec;  /* Sampling Frequency in Hz                             */
unsigned long       bytesPerSec;    /* bytes per second */
unsigned short      blockAlign;     /* 2=16-bit mono, 4=16-bit stereo , 6=24-bit stereo,8=32-bit stereo*/
unsigned short      bitsPerSample;  /* Number of bits per sample, inkl. hier=36 bytes  */
unsigned short      wExtSize;       /*  2 byte, wExtSize = 0  the length of the format extension   */
unsigned char       Fact[4];        /* "fact"  string   */
/*Problem here! -> +2bytes*/
unsigned long       DwFactSize;     /* Sampled data length,  inkl. hier bei 44 bytes */
unsigned long       dwSamplesWritten;
unsigned char       Data[4];        /* leerer string falls extensible -> Beginn nicht nach 44 sondern 68!  */
unsigned long       dwDataLength;   /* raw DataLength */
}__attribute__((packed)) wav_hdr;


int getFileSize(FILE *inFile);

int main(int argc,char *argv[])
{
char *file;
file = argv[1];
wav_hdr wavHeader;
FILE *wavFile;
int headerSize = sizeof(wav_hdr),filelength = 0;
wavFile = fopen(file,"r");
if(wavFile == NULL)
{
    printf("\nCan not open wave file. Usage: program [file] \n");
    exit(EXIT_FAILURE);
}

fread(&wavHeader,headerSize,1,wavFile);
filelength = getFileSize(wavFile);
fclose(wavFile);


std::cout << "\nRIFF " << offsetof(WAV_HEADER, RIFF) <<  std::endl;
std::cout << "\nChunkSize " << offsetof(WAV_HEADER, ChunkSize) <<  std::endl;
std::cout << "\nWAVE[4] " << offsetof(WAV_HEADER, WAVE) <<  std::endl;
std::cout << "\nfmt[4] " << offsetof(WAV_HEADER, fmt) <<  std::endl;
std::cout << "\nSubchunk1Size " << offsetof(WAV_HEADER, Subchunk1Size) <<  std::endl;
std::cout << "\nAudioFormat " << offsetof(WAV_HEADER, AudioFormat) <<  std::endl;
std::cout << "\nNumOfChan " << offsetof(WAV_HEADER, NumOfChan) <<  std::endl;
std::cout << "\nSamplesPerSec " << offsetof(WAV_HEADER, SamplesPerSec) <<  std::endl;
std::cout << "\nbytesPerSec " << offsetof(WAV_HEADER, bytesPerSec) <<  std::endl;
std::cout << "\nblockAlign " << offsetof(WAV_HEADER, blockAlign) <<  std::endl;
std::cout << "\nbitsPerSample " << offsetof(WAV_HEADER, bitsPerSample) <<  std::endl;
std::cout << "\nwExtSize (2) " << offsetof(WAV_HEADER, wExtSize) <<  std::endl;
std::cout << "\nFact[4] " << offsetof(WAV_HEADER, Fact) <<  std::endl;

std::cout << "\nDwFactSize " << offsetof(WAV_HEADER, DwFactSize) <<  std::endl;
std::cout << "\ndwSamplesWritten " << offsetof(WAV_HEADER, dwSamplesWritten) <<  std::endl;
std::cout << "\nData[4] " << offsetof(WAV_HEADER, Data) <<  std::endl;
std::cout << "\ndwDataLength " << offsetof(WAV_HEADER, dwDataLength) <<  std::endl;


return 0;
}

int getFileSize(FILE *inFile)
{
int fileSize = 0;
fseek(inFile,0,SEEK_END);
fileSize=ftell(inFile);
fseek(inFile,0,SEEK_SET);
return fileSize;
}

To generate such a 32 Bit Float, 88200 Wav-file: sox input16_44100.wav -b 32 -e float output32F_88200.wav rate -s -a -v -L 88200

1
Off-ish topic (If it was on topic, your offsets would be way, way off) are you absolutely certain of the sizes of short and long? Might be better to use fixed-width integersuser4581301
On-ish topic, what happens if you read the fields one by one rather than counting on your structure's packing to match the writer's?user4581301
Like I wrote, I used unsigned char, uint16_t, uint32_t ... the same after the fact-chunk. This works since years for 44 byte headers ...TJF
@TJF Is by anychance this question was given for a job application?Saeid Yazdani
What about the PEAK header?Ráfagan

1 Answers

1
votes

There's 2 bytes of padding between Fact[] and DwFactSize, obviously.

I suspect it's because you're using a typedef there. Just write it as a regular C++ definition: struct __attribute__((packed)) WAV_HEADER { ...