Sound is one of the important parts of computer science and programming. The correct use of sound can add excitement to recreational apps such as games or it can act to alert the user to an important event or state change in a utility or business-focused program. We have many different sound formats to play sound files in our applications or mostly in our games, or sometimes we need to edit them to analyze or to apply some filters. Games, MIDI Apps, Sound Editors, Music Studio Apps, Engineering Apps, AI Applications (such as voice recognition from sound or movie files), etc. Waveform Audio File Format (shortly *.WAVE or *.WAV files) are the oldest and they are still useful to play them from memory and it is easy to edit them. In this post, we explain how we can read the WAV Waveform Audio File Format in C++.
Table of Contents
What is the WAV waveform audio file format in C++?
Audio files have different audio formats – ways of storing the analog sound in a variety of digital representations. The most used formats are MP3, OG, and FLAC files and these audio formats have compression techniques to make audio files smaller. The most known raw version is a WAV file. Wave format (*.wav or *wave) is a recorded digital form of sound whose volume changes data across a timeline. In C++ Builder it is easy to use recording wav files on Windows. To record a sound in Multi-Device applications we must use FMX.Media.hpp header.
How can we record a WAV waveform audio file format in C++?
Recording WAV sound is well explained in our Learn How To Easily Record Sound In Powerful Modern C++ On Windows post.
How can we read the WAV waveform audio file format in C++?
If you are reading a binary file, first you should know its structure type and so on. Waveform Audio File Format (WAVE or WAV) is an audio file format standard to record audio bitstream on a memory or on a drive as a file. Here are two images that show the header of the WAVE format.
How can we read the WAV waveform audio file format in C++?
WAW header can be defined as a structure as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// WAVE file header structure struct Twavheader { char chunk_ID[4]; // 4 riff_mark[4]; uint32_t chunk_size; // 4 file_size; char format[4]; // 4 wave_str[4]; char sub_chunk1_ID[4]; // 4 fmt_str[4]; uint32_t sub_chunk1_size; // 4 pcm_bit_num; uint16_t audio_format; // 2 pcm_encode; uint16_t num_channels; // 2 sound_channel; uint32_t sample_rate; // 4 pcm_sample_freq; uint32_t byte_rate; // 4 byte_freq; uint16_t block_align; // 2 block_align; uint16_t bits_per_sample; // 2 sample_bits; char sub_chunk2_ID[4]; // 4 data_str[4]; uint32_t sub_chunk2_size; // 4 sound_size; }; // 44 bytes TOTAL |
Now let’s create a read_wav_file()
function to read this struct. We can read this WAV header as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
void read_wav_file(std::string fname) { // Open the WAV file std::ifstream wavfile(fname, std::ios::binary); if(wavfile.is_open()) { // Read the WAV header Twavheader wav; wavfile.read(reinterpret_cast<char*>(&wav), sizeof(Twavheader)); // If the file is a valid WAV file if (std::string(wav.format, 4) != "WAVE" || std::string(wav.chunk_ID, 4) != "RIFF") { wavfile.close(); std::cerr << "Not a WAVE or RIFF!" << std::endl; return; } // Properties of WAV File std::cout << "FileName:" << fname << std::endl; std::cout << "File size:" << wav.chunk_size+8 << std::endl; std::cout << "Resource Exchange File Mark:" << std::string(wav.chunk_ID, 4) << std::endl; std::cout << "Format:" << std::string(wav.format, 4) << std::endl; std::cout << "Channels: " << wav.num_channels << std::endl; std::cout << "Sample Rate: " << wav.sample_rate << " Hz" << std::endl; std::cout << "Bits Per Sample: " << wav.bits_per_sample << " bits" << std::endl; // Read wave data std::vector<int16_t> audio_data( wav.sub_chunk2_size / sizeof(int16_t) ); wavfile.read(reinterpret_cast<char*>( audio_data.data() ), wav.sub_chunk2_size ); wavfile.close(); // Close audio file // Display some audio samples const size_t numofsample = 20; std::cout <<"Listin first " << numofsample << " Samples:" << std::endl; for (size_t i = 0; i < numofsample && i < audio_data.size(); ++i) { std::cout << i << ":" << audio_data[i] << std::endl; } std::cout << std::endl; } } |
finally, we can read and display like so:
1 2 3 |
read_wav_file("D:\\sample.wav"); |
Is there a full C++ example to read the WAV waveform audio file format in C++?
Here is the full C++ example to read a file which uses the WAV waveform audio file format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <iostream> #include <fstream> #include <vector> #include <cstdint> // WAV file header structure struct Twavheader { char chunk_ID[4]; // 4 riff_mark[4]; uint32_t chunk_size; // 4 file_size; char format[4]; // 4 wave_str[4]; char sub_chunk1_ID[4]; // 4 fmt_str[4]; uint32_t sub_chunk1_size; // 4 pcm_bit_num; uint16_t audio_format; // 2 pcm_encode; uint16_t num_channels; // 2 sound_channel; uint32_t sample_rate; // 4 pcm_sample_freq; uint32_t byte_rate; // 4 byte_freq; uint16_t block_align; // 2 block_align; uint16_t bits_per_sample; // 2 sample_bits; char sub_chunk2_ID[4]; // 4 data_str[4]; uint32_t sub_chunk2_size; // 4 sound_size; }; // 44 bytes TOTAL //------------------------------------------------------------------------------ void read_wav_file(std::string fname) { // Open the WAV file std::ifstream wavfile(fname, std::ios::binary); if(wavfile.is_open()) { // Read the WAV header Twavheader wav; wavfile.read(reinterpret_cast<char*>(&wav), sizeof(Twavheader)); // If the file is a valid WAV file if (std::string(wav.format, 4) != "WAVE" || std::string(wav.chunk_ID, 4) != "RIFF") { wavfile.close(); std::cerr << "Not a WAVE or RIFF!" << std::endl; return; } // Properties of WAV File std::cout << "FileName:" << fname << std::endl; std::cout << "File size:" << wav.chunk_size+8 << std::endl; std::cout << "Resource Exchange File Mark:" << std::string(wav.chunk_ID, 4) << std::endl; std::cout << "Format:" << std::string(wav.format, 4) << std::endl; std::cout << "Channels: " << wav.num_channels << std::endl; std::cout << "Sample Rate: " << wav.sample_rate << " Hz" << std::endl; std::cout << "Bits Per Sample: " << wav.bits_per_sample << " bits" << std::endl; // Read wave data std::vector<int16_t> audio_data( wav.sub_chunk2_size / sizeof(int16_t) ); wavfile.read(reinterpret_cast<char*>( audio_data.data() ), wav.sub_chunk2_size ); wavfile.close(); // Close audio file // Display some audio samples const size_t numofsample = 20; std::cout <<"Listing first " << numofsample << " Samples:" << std::endl; for (size_t i = 0; i < numofsample && i < audio_data.size(); ++i) { std::cout << i << ":" << audio_data[i] << std::endl; } std::cout << std::endl; } } //------------------------------------------------------------------------------ int main() { read_wav_file("D:\\sample.wav"); system("pause"); return 0; } |
The output will be as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
FileName:D:\sample.wav File size:563756 Resource Exchange File Mark:RIFF Format:WAVE Channels: 2 Sample Rate: 44100 Hz Bits Per Sample: 16 bits Listing first 20 Samples: 0:-1934 1:-1934 2:-1276 3:-1276 4:-241 5:-241 6:598 7:598 8:282 9:282 10:242 11:242 12:314 13:314 14:208 15:208 16:-128 17:-128 18:-1226 19:-1226 |
Note that this struct can be used in C applications too. As you see, in modern C++, we can easily read WAV wave files, now you can display or edit wave files.
C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.