Parse the .wav audio file

Now that we have discussed the .wav file format, set up the initial audio components, and opened our .wav file in the app, we can process the .wav file based on the structure we discussed earlier in Structure of a .wav file.

Handle chunk tags

In our calling function, first we find the format tag ("fmt ") using find_tag(). Because non-PCM format uses extra parameter space, we must skip over the length of the format chunk, which is the size of wave_hdr from the current position of the file pointer.

To make it easier to read the tags, we can abstract the set of statements into a function. After we locate the tag structure, we must return the length of the memory block that appears before the tag. Because of the byte order that the fields are stored in, we need to convert the 32-bit (4-byte) length variable to little-endian format to read the field as an unsigned byte order. To perform this conversion, we can use the macro ENDIAN_LE32(), which is declared in gulliver.h.

The find_tag() function below accepts the first parameter, FILE *fp, which is an open file pointer to the .wav file. The second parameter, const char *tag, is a character array that represents the tag that we want to search for. The function returns the little-endian version of the length variable.

int 
find_tag(FILE *fp, const char *tag)
{
    int ret_val = 0;
    riff_tag tag_bfr = { "", 0 };

    /* Keep reading until we find the tag or hit the end of file */
    while (fread((unsigned char *) &tag_bfr, sizeof(tag_bfr), 1, fp)) {

        /* If this is our tag, set the length and break */
        if (strncmp(tag, tag_bfr.tag, sizeof tag_bfr.tag) == 0) {
            ret_val = ENDIAN_LE32(tag_bfr.length);
            break;
        }

        /* Skip ahead the specified number of bytes in the stream */
        fseek(fp, tag_bfr.length, SEEK_CUR);
    }

     /* Return the result of our operation */
    return (ret_val);
}

Handle the .riff chunk descriptor

To read the .riff header, you can write a function similar to the check_hdr() function that appears below. This function determines if we have a .riff file and whether it contains .wav data. The function accepts the parameter FILE * fp, which is a pointer to the .wav file. The function returns 0 if it is successful, otherwise it returns a negative value.

int
check_hdr(FILE * fp)
{
    riff_hdr riff_header = { "", 0 };

    /* Read the header and make sure that this is indeed a 
       Wave file. */
    if (fread((unsigned char *) &riff_header, 
              sizeof(riff_hdr), 1, fp) == 0)
        return 0;

    if (strncmp(riff_header.Riff, riff_id, strlen(riff_id)) ||
        strncmp(riff_header.Wave, wave_id, strlen(wave_id)))
        return -1;

    return 0;
}

Last modified: 2015-03-31



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus