2

I need to read the header variables from a wave file and display what they are. I am using the following code, but my output has numbers far too large. I've searched for solutions for hours. Help would be much appreciated! Thanks. I got the wave soundfile format from https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

Output: Wav file header information: Filesize 3884 bytes RIFF header RIFF WAVE header WAVE Subchunk1ID fmt Chunk Size (based on bits used) 604962816 Subchunk1Size 268435456 Sampling Rate 288030720 Bits Per Sample 2048 AudioFormat 256 Number of channels 2048 Byte Rate 288030720 Subchunk2ID Subchunk2Size 1684108385

Here is the source:

#include <stdio.h>
#include <stdlib.h>

typedef struct  WAV_HEADER
{
char                RIFF[4];        
int                 ChunkSize;     
char                WAVE[4];       
char                fmt[4];        
int                 Subchunk1Size;                              
short int           AudioFormat;  
short int           NumOfChan;      
int                 SamplesPerSec;  
int                 bytesPerSec;    
short int           blockAlign;    
short int           bitsPerSample;  
int                 Subchunk2Size; 
char                Subchunk2ID[4];
}wav_hdr; 

int getFileSize(FILE *inFile); 
int main(int argc,char *argv[])
{
//check startup conditions
if(argc >= 2); //we have enough arguments -- continue
else { printf("\nUSAGE: program requires a filename as an argument -- please try again\n"); exit(0);}

wav_hdr wavHeader;
FILE *wavFile;
int headerSize = sizeof(wav_hdr),filelength = 0;
wavFile = fopen(argv[1],"r");
if(wavFile == NULL)
{
    printf("Unable to open wave file\n");
    exit(EXIT_FAILURE);
}
fread(&wavHeader,headerSize,1,wavFile);
filelength = getFileSize(wavFile);
fclose(wavFile);
printf("\nWav file header information:\n");
printf("Filesize\t\t\t%d bytes\n",filelength);
printf("RIFF header\t\t\t%c%c%c%c\n",wavHeader.RIFF[0],wavHeader.RIFF[1],wavHeader.RIFF[2],wavHeader.RIFF[3]);
printf("WAVE     header\t\t\t%c%c%c%c\n",wavHeader.WAVE[0],wavHeader.WAVE[1],wavHeader.WAVE[2],wavHeader.WAVE[3]);
     printf("Subchunk1ID\t\t\t%c%c%c%c\n",wavHeader.fmt[0],wavHeader.fmt[1],wavHeader.fmt[2],wavHeader.fmt[3]);
printf("Chunk Size (based on bits used)\t%d\n",wavHeader.ChunkSize);
printf("Subchunk1Size\t\t\t%d\n",wavHeader.Subchunk1Size);
printf("Sampling Rate\t\t\t%d\n",wavHeader.SamplesPerSec); //Sampling frequency of the wav file
printf("Bits Per Sample\t\t\t%d\n",wavHeader.bitsPerSample); //Number of bits used per sample
printf("AudioFormat\t\t\t%d\n",wavHeader.AudioFormat);
printf("Number of channels\t\t%d\n",wavHeader.bitsPerSample);     //Number of channels (mono=1/sterio=2)
printf("Byte Rate\t\t\t%d\n",wavHeader.bytesPerSec);   //Number of bytes per second
printf("Subchunk2ID\t\t\t%c%c%c%c\n",wavHeader.Subchunk2ID[0],wavHeader.Subchunk2ID[1],wavHeader.Subchunk2ID[2],wavHeader.Subchunk2ID[3]);
printf("Subchunk2Size\t\t\t%d\n",wavHeader.Subchunk2Size);
printf("\n");
return 0;
}

int getFileSize(FILE *inFile)
{
int fileSize = 0;
fseek(inFile,0,SEEK_END);
fileSize=ftell(inFile);
fseek(inFile,0,SEEK_SET);
return fileSize;
}`
2
  • And, if you're going to rely on specific layout of structs in memory, we would also need to know what compiler and what options you plan to use to compile it with. Commented Feb 19, 2013 at 2:29
  • UNIX operating system using gcc, left everything off Commented Feb 19, 2013 at 2:38

2 Answers 2

3

So, your code basically works -- if you compile it with the same compiler and O/S that the author of the file format spec was using (32-bit Windows). You're hoping that your compiler has laid out your struct exactly as you need to match the file bytes. For example, I can compile and run it on win32 and read a WAV file perfectly -- right up to the variable part of the header whose variability you failed to code for.

Having written a great deal of code to manipulate a variety of file formats, I would advise you give up on trying to read into structs and instead make a few simple utility functions for things like "read next 4 bytes and turn them into an int".

Notice things like the "extra format bytes". Parts of the file format depend on the values in previous parts of the file format. That's why you generally need to think of it as a dynamic reading process rather than one big read to grab the headers. It's not hard to keep the result highly portable C that will work between operating systems without relying on O/S specific things like stat() or adding library dependencies for things like htonl() -- should portability (even portability to a different compiler or even just different compiler options on the same O/S) be desirable.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! Sheds a lot of insight
0

It seems like you noticed the endian issue, but the way to handle it is with htonl, ntohl, htons, and, ntohs. This is part of your number problem.

Read here:

http://www.beej.us/guide/bgnet/output/html/multipage/htonsman.html

Note there are a lot of other posts here on WAV files. Have you considered reading them?

Also, there are standard ways to get file information, like size, either through the windows API on windows or stat on linux/unix

3 Comments

Why discourage a fairly portable method for obtaining file size like ftell()?
Yes it is a method. Granted. But if it so handy then why was stat() written? Because there is more to file metadata than just how many bytes are in the file.
Thanks, I think this has put me in the right direction. I'll look into it more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.