Razgriz Razgriz - 1 month ago 19
C++ Question

C++ Reading the Data part of a WAV file

I plan to create a program that will visualize the audio waveform of a .wav file.

So far, I have started by properly reading the header part of the said wav file. The code I use would be this:

#include <iostream>
#include <string>
#include <fstream>

using namespace std;
using std::string;
using std::fstream;

typedef struct WAV_HEADER{
char RIFF[4]; // RIFF Header Magic header
unsigned long ChunkSize; // RIFF Chunk Size
char WAVE[4]; // WAVE Header
char fmt[4]; // FMT header
unsigned long Subchunk1Size; // Size of the fmt chunk
unsigned short AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
unsigned short NumOfChan; // Number of channels 1=Mono 2=Sterio
unsigned long SamplesPerSec; // Sampling Frequency in Hz
unsigned long bytesPerSec; // bytes per second
unsigned short blockAlign; // 2=16-bit mono, 4=16-bit stereo
unsigned short bitsPerSample; // Number of bits per sample
char Subchunk2ID[4]; // "data" string
unsigned long Subchunk2Size; // Sampled data length

}wav_hdr;

// Function prototypes
int getFileSize(FILE *inFile);

int main(int argc,char *argv[]){
wav_hdr wavHeader;
FILE *wavFile;
int headerSize = sizeof(wav_hdr),filelength = 0;

string answer;

do{
string input;
string answer;

const char* filePath;

cout << "Pick wav file from the Windows Media File: ";
cin >> input;
cin.get();

cout << endl;

path = "C:\\Windows\\Media\\" + input + ".wav";
filePath = path.c_str();

wavFile = fopen( filePath , "r" );

if(wavFile == NULL){
printf("Can not able to open wave file\n");
//exit(EXIT_FAILURE);
}

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

cout << "File is :" << filelength << " bytes." << endl;

cout << "RIFF header :" << wavHeader.RIFF[0]
<< wavHeader.RIFF[1]
<< wavHeader.RIFF[2]
<< wavHeader.RIFF[3] << endl;

cout << "WAVE header :" << wavHeader.WAVE[0]
<< wavHeader.WAVE[1]
<< wavHeader.WAVE[2]
<< wavHeader.WAVE[3]
<< endl;

cout << "FMT :" << wavHeader.fmt[0]
<< wavHeader.fmt[1]
<< wavHeader.fmt[2]
<< wavHeader.fmt[3]
<< endl;

cout << "Data size :" << wavHeader.ChunkSize << endl;

// Display the sampling Rate form the header
cout << "Sampling Rate :" << wavHeader.SamplesPerSec << endl;
cout << "Number of bits used :" << wavHeader.bitsPerSample << endl;
cout << "Number of channels :" << wavHeader.NumOfChan << endl;
cout << "Number of bytes per second :" << wavHeader.bytesPerSec << endl;
cout << "Data length :" << wavHeader.Subchunk2Size << endl;
cout << "Audio Format :" << wavHeader.AudioFormat << endl;
// Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM


cout << "Block align :" << wavHeader.blockAlign << endl;

cout << "Data string :" << wavHeader.Subchunk2ID[0]
<< wavHeader.Subchunk2ID[1]
<< wavHeader.Subchunk2ID[2]
<< wavHeader.Subchunk2ID[3]
<< endl;

cout << endl << endl << "Try something else? (y/n)";
cin >> answer;
//cin.get();
cout << endl << endl;

}while( answer == "y" );


getchar();
return 0;
}
// find the file size
int getFileSize(FILE *inFile){
int fileSize = 0;
fseek(inFile,0,SEEK_END);

fileSize=ftell(inFile);

fseek(inFile,0,SEEK_SET);
return fileSize;
}


I've tried it several times and the data it gives seems consistent through different wav files in the Media folder in the Windows folder.

The next step then would be storing the actual data of the wav file in a vector. However, I'm quite clueless on how to do this. Online solutions that I found only went as far as reading the header file.

Any ideas on how to store (and hopefully display) the actual data of the wav file?
Thanks!

Answer

This image is taken from a Stanford course

WAV File Format

So you can see that the audio data occurs immediately after the headers you already read and there will be Subchunk2Size bytes of audio data.

The pseudocode for this would be

ReadRIFF();
ReadFMT();
int32 chunk2Id = Read32(BigEndian);
int32 chunk2Size = Read32(LittleEndian);
for (int i = 0; i < chunk2Size; i++)
{
    audioData[i] = ReadByte();
}

If the audio is stereo you'll have two audio streams in data. If the audio is compressed (mp3, aac, etc) you'll have to decompress it first.