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!
Locate your song in the Windows Media Player library. Right-click the album title and select "Find Album Info."
Though a WAV file can contain compressed audio, the most common WAV audio format is uncompressed audio in the linear pulse-code modulation (LPCM) format. LPCM is also the standard audio coding format for audio CDs, which store two-channel LPCM audio sampled at 44,100 Hz with 16 bits per sample.
FLAC, AIFF and MP3 formats take full advantage of metadata whereas WAV files only allow a little metadata input, so not as helpful for browsing your library. It's important if you want to locate and play music around your home. Network players like our CXN use metadata to browse and play your music.
The data is stored "in the raw" with no preprocessing. The WAV format is a Microsoft proprietary format, and is a special case of the RIFF (Resource Interchange File Format) format. A WAV file contains three chunks of information: the RIFF chunk (12 bytes) identifies the file as a WAV file.
This image is taken from a Stanford course
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.
I know this is an old post, but your fread parameters are switched, here is a more correct version (requires g++-4.7 or higher with -std=c++11 flag like this "g++ -std=c++11 WaveReader.cpp -o WaveReader").
#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>
using std::cin;
using std::cout;
using std::endl;
using std::fstream;
using std::string;
typedef struct WAV_HEADER
{
/* RIFF Chunk Descriptor */
uint8_t RIFF[4]; // RIFF Header Magic header
uint32_t ChunkSize; // RIFF Chunk Size
uint8_t WAVE[4]; // WAVE Header
/* "fmt" sub-chunk */
uint8_t fmt[4]; // FMT header
uint32_t Subchunk1Size; // Size of the fmt chunk
uint16_t AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
uint16_t NumOfChan; // Number of channels 1=Mono 2=Sterio
uint32_t SamplesPerSec; // Sampling Frequency in Hz
uint32_t bytesPerSec; // bytes per second
uint16_t blockAlign; // 2=16-bit mono, 4=16-bit stereo
uint16_t bitsPerSample; // Number of bits per sample
/* "data" sub-chunk */
uint8_t Subchunk2ID[4]; // "data" string
uint32_t Subchunk2Size; // Sampled data length
} wav_hdr;
// Function prototypes
int getFileSize(FILE* inFile);
int main(int argc, char* argv[])
{
wav_hdr wavHeader;
int headerSize = sizeof(wav_hdr), filelength = 0;
const char* filePath;
string input;
if (argc <= 1)
{
cout << "Input wave file name: ";
cin >> input;
cin.get();
filePath = input.c_str();
}
else
{
filePath = argv[1];
cout << "Input wave file name: " << filePath << endl;
}
FILE* wavFile = fopen(filePath, "r");
if (wavFile == nullptr)
{
fprintf(stderr, "Unable to open wave file: %s\n", filePath);
return 1;
}
//Read the header
size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
cout << "Header Read " << bytesRead << " bytes." << endl;
if (bytesRead > 0)
{
//Read the data
uint16_t bytesPerSample = wavHeader.bitsPerSample / 8; //Number of bytes per sample
uint64_t numSamples = wavHeader.ChunkSize / bytesPerSample; //How many samples are in the wav file?
static const uint16_t BUFFER_SIZE = 4096;
int8_t* buffer = new int8_t[BUFFER_SIZE];
while ((bytesRead = fread(buffer, sizeof buffer[0], BUFFER_SIZE / (sizeof buffer[0]), wavFile)) > 0)
{
/** DO SOMETHING WITH THE WAVE DATA HERE **/
cout << "Read " << bytesRead << " bytes." << endl;
}
delete [] buffer;
buffer = nullptr;
filelength = getFileSize(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 from 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;
}
fclose(wavFile);
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With