So far, we’ve worked only with raw audio data. However, most sound is handled in file types that store not only the raw data but also a header containing information about how the data is formatted. Two of the commonly-used file formats are WAV and AIFF. If you want to read or write a WAV file without the help of an existing library of functions, you need to know the required format.
In WAV and AIFF, data are grouped in chunks. Let’s look at the WAV format as an example. The format chunk always comes first, containing information about the encoding format, number of channels, sampling rate, data transfer rate, and byte alignment. The samples are stored in the data chunk. The way in which the data is stored depends on whether the file is compressed or not and the bit depth of the file. Optional chunks include the fact, cue, and playlist chunks. To see this format firsthand, you could try taking a RAW audio file, converting it to WAV or AIFF, and then see if it plays in an audio player.
More often, however, it is more to-the-point to use a higher level library that allows you to read and write WAV and AIFF audio files. The libsndfile library serves this purpose. If you install this library, you can read WAV or AIFF files into your C++ programs, manipulate them, and write them back to permanent storage as WAV or AIFF files without needing to know the detail of endian-ness or file formats. The website for libsndfile has example programs for you to follow. Program 5.3 demonstrates the library with a simple program that opens a sound file (e.g., WAV), reads the contents, reduces the amplitude by half, and writes the result back in the same format.
//Give the input and output file names on the command line #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <sndfile.h> #include <iostream> using namespace std; #define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof (x [0]))) #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MIN(x,y) ((x) < (y) ? (x) : (y)) void reduceAmplitude (SNDFILE *, SNDFILE *) ; sf_count_t sfx_read_double (SNDFILE *, double *, sf_count_t); int main (int argc, char ** argv) { SNDFILE *infile, *outfile ; SF_INFO sfinfo ; double buffer [1024] ; sf_count_t count ; if (argc != 3) { printf("\nUsage :\n\n <executable name> <input file> <output file>\n") ; exit(0); } memset (&sfinfo, 0, sizeof (sfinfo)) ; if ((infile = sf_open (argv [1], SFM_READ, &sfinfo)) == NULL) { printf ("Error : Not able to open input file '%s'\n", argv [1]); sf_close (infile); exit (1) ; } if ((outfile = sf_open (argv [2], SFM_WRITE, &sfinfo)) == NULL) { printf ("Error : Not able to open output file '%s'\n", argv [argc - 1]); sf_close (infile); exit (1); } while ((count = sf_read_double (infile, buffer, ARRAY_LEN (buffer))) > 0) { for (int i = 0; i < 1024; i++) buffer[i] *= 0.5; sf_write_double (outfile, buffer, count); } sf_close (infile) ; sf_close (outfile) ; return 0 ; }
Program 5.3 Reading a formatted sound file using the libsndfile library