Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C++
Article

CWave - A Simple C++ Class to Manipulate WAV Files

Rate me:
Please Sign up or sign in to vote.
4.81/5 (29 votes)
25 Sep 2008CPOL4 min read 244.1K   14.2K   90   33
An article on a simple C++ class for manipulating WAV files
SoundProject - Screenshot

Introduction

This article is about the simple C++ .WAV manipulation class called CWave. This main features of this class are .wav files loading, saving, playing and mixing. It can handle only PCM .wav files (8-bit or 16-bit). It is written just to show the developer how to:

  • Load the .WAV file from the disk into memory (parsing .WAV file's RIFF structure)
  • Save the .WAV file from memory to the disk (creating .WAV file's RIFF structure)
  • Playing the .WAV file using the default WAVE_MAPPER device
  • Offline mixing of the two .WAV files (8-bit and 16-bit mixing not using DirectX)

Background

The main goal here was to find the .WAV files mixing algorithm which would not create artefacts nor distort the original .WAVs. I was using the Google search engine to see the existing solutions, and found - believe it or not just 1 or 2 (?!?). I was really surprised, so I tried to 'fix' the proposed solution to get the best output I could. This class holds the results of my research.

Here on The Code Project, one can find different .WAV files loading and playback solutions, using only Platform SDK and not using DirectX, so please take a look at them too before turning to this class only. Some solutions also provide .WAV files recording...

Using the Code

To use the CWave class, do the following:

C++
//
#include "Wave.h"
//
//
// Load .WAV files from the disk
CWave wave1, wave2;
wave1.Load(_T("Enter first .WAV file path here..."));
wave2.Load(_T("Enter second .WAV file path here..."));
//
// Mix .WAVs
wave1.Mix(wave2);
//
// Start .WAV playback (will run in a separate thread, so your program continues)
wave1.Play();
//
// Wait some time (ie. 10 seconds, for the .WAV file to finish playback)
Sleep(10000);
//
// Save the .WAV file on the disk
wave1.Save(_T("Enter destination .WAV file path here..."));
//

Here is the list of the public methods of the CWave class:

C++
BOOL Load(LPTSTR lpszFilePath);
BOOL Save(LPTSTR lpszFilePath);
BOOL Play();
BOOL Stop();
BOOL Pause();
BOOL Mix(CWave& wave);
BOOL IsValid()				{return (m_lpData != NULL);}
BOOL IsPlaying()			{return (!m_bStopped && !m_bPaused);}
BOOL IsStopped()			{return m_bStopped;}
BOOL IsPaused()				{return m_bPaused;}
LPBYTE GetData()			{return m_lpData;}
DWORD GetSize()				{return m_dwSize;}
SHORT GetChannels()			{return m_Format.channels;}
DWORD GetSampleRate()			{return m_Format.sampleRate;}
SHORT GetBitsPerSample()		{return m_Format.bitsPerSample;}

General Notes About .WAV Files Mixing

Please see the inner structure of the typical .WAV file below:

WAVE file inner structure

So, as you can see, parsing of this file type should not be too difficult. This is called the RIFF structure, built from different 'chunks'. The first 'chunk' is the DESCRIPTOR explaining the RIFF file type. Next if the FORMAT 'chunk' which explains the data format. The .WAV sound data can be 8-bit or 16-bit, mono or stereo, can have a different sampling rate, can be compressed or not, etc. We use this information to initialize the sound input or the sound output devices on the host PC.

The next 'chunk', called the DATA 'chunk' holds the sound data, please see below:

WAVE file sound data

So, actually we work with this sound data which represents the samples of the original audio signal, sampled at some high frequency, typically 11kHz, 22kHz, 44kHz. The data samples can be 8-bit, 16-bit, 24-bit, 32-bit. The data can be uncompressed (like PCM) or compressed (like MP3). The different audio decompressors take care of the compressed sound data, and the different sound output devices can 'play' this data. Also, the sound data can be converted from one format to another using different ACMs (Audio Compression Managers).

The main goal here was to 'make a mixture' of the 2 different .WAV files. The DirectX component (called the DirectSound) can do this easily, but I wanted to use an old fashioned method, by using Platform SDK and old Microsoft winmm.lib library for the sound playback. The two different sound data buffers were mixed using the following equation:

destination = destination + source

Is that simple, or what? Well, it is... almost. This is, however, the main sound mixing equation you would find. Well... if you find, better say. I am sure that sound experts will disagree with my last statement, but there is just no better solution available. Not in the open-source world. So, what will we get with this on the output, in most cases, will be very good (and sometimes even excellent). But, often some artifact could be noticed (heard) on the speakers. It's because of the method itself. It does simple wave superposition. So, if the wave amplitudes differ significantly, the output may be distorted. To avoid this, I used the median value for the 8-bit .WAV files and got good output, with the decreased volume. I have increased the amplitude by the factor of log10(20) which has given better results. For 16-bit .WAV files, I have checked the absolute product of the amplitudes. If it was above 0.5, then I used the simple superposition (with no volume correction). If it was below 0.5, then I used the lower amplitude. The output results were finally good enough for both, mono and stereo .WAV files.

I am, however, sure that this solution is not the best nor the final one. My goal was to give developers a possibility for further research and improvement of the sound data processing technique. I am also hoping that this would be a good starting point for all CodeProject developers who want to improve this section.

Points of Interest

I was always interested in processing of sound data. While working on this article, I learned many things considering the .WAV file format and also about the sound data processing techniques. It was not too easy to understand and implement, but the final results justify the effort taken.

History

  • 24th September, 2008: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Elektromehanika d.o.o. Nis
Serbia Serbia
He has a master degree in Computer Science at Faculty of Electronics in Nis (Serbia), and works as a C++/C# application developer for Windows platforms since 2001. He likes traveling, reading and meeting new people and cultures.

Comments and Discussions

 
QuestionGet length Pin
Member 1364732716-Jun-18 22:18
Member 1364732716-Jun-18 22:18 
QuestionHow can i make it work on Windows 7, working with VS2008? Pin
Member 1089953924-Jun-14 4:19
Member 1089953924-Jun-14 4:19 
QuestionHow can i make it work on Windows 7, working with VS2010? Pin
Member 777610429-Dec-12 2:08
Member 777610429-Dec-12 2:08 
SuggestionNote on use of LPWORD: 16-bit wav is signed Pin
Member 88193275-Sep-12 18:53
Member 88193275-Sep-12 18:53 
Question[My vote of 1] Doesn't work under Windows 7 Pin
SoftwareGuru from Thomaston6-Aug-12 3:28
SoftwareGuru from Thomaston6-Aug-12 3:28 
GeneralExport this Class to a Dll Pin
77Chris7720-Jul-12 5:10
77Chris7720-Jul-12 5:10 
GeneralDev-C++ Error: _T, _tfopen was not declared in this scope Pin
mirekpl69-Jul-12 4:57
mirekpl69-Jul-12 4:57 
BugSecond Bug in WaveOut_Proc Pin
VAndersen10-Aug-11 12:18
VAndersen10-Aug-11 12:18 
GeneralRe: Second Bug in WaveOut_Proc Pin
Member 83006348-Oct-11 7:28
Member 83006348-Oct-11 7:28 
GeneralUrgent, please Pin
ikyr999911-May-10 0:24
ikyr999911-May-10 0:24 
GeneralError LNK2019:unresolved external symbol.. I appreciate help! Pin
Anders Branderud31-Mar-10 8:49
Anders Branderud31-Mar-10 8:49 
GeneralProblem solved! Pin
Anders Branderud31-Mar-10 8:59
Anders Branderud31-Mar-10 8:59 
GeneralDoesnt work for me Pin
alexkx312-Mar-10 8:25
alexkx312-Mar-10 8:25 
GeneralNoOutput Pin
Dr Bob.23-Jan-10 8:39
Dr Bob.23-Jan-10 8:39 
GeneralRe: NoOutput Pin
Devpro AB29-Jul-10 18:10
Devpro AB29-Jul-10 18:10 
RantLoop problem! Pin
Jeremy Soh19-Jan-10 22:54
Jeremy Soh19-Jan-10 22:54 
Generalthe code does not play the wavfiles when i click on play Pin
1s2a3b4a9-Jan-10 9:43
1s2a3b4a9-Jan-10 9:43 
Generalsome tiny bugs report Pin
eraserxinxin29-Nov-09 6:53
eraserxinxin29-Nov-09 6:53 
Questioncan MIX work for more than two file? Pin
Fareed Khatri24-Nov-09 1:47
Fareed Khatri24-Nov-09 1:47 
AnswerRe: can MIX work for more than two file? Pin
darkoman24-Nov-09 11:40
darkoman24-Nov-09 11:40 
AnswerRe: can MIX work for more than two file? Pin
jimmysheep18-Aug-10 16:19
jimmysheep18-Aug-10 16:19 
QuestionHow to get the finished playing message in order to repeat playing? Pin
zhouyigang4-Oct-09 15:53
zhouyigang4-Oct-09 15:53 
Generalquestion about a related project [modified] Pin
pblais7-Sep-09 13:23
pblais7-Sep-09 13:23 
GeneralRe: question about a related project Pin
darkoman11-Sep-09 21:52
darkoman11-Sep-09 21:52 
GeneralBug in WaveOut_Proc Pin
playmyskay25-Jun-09 23:57
playmyskay25-Jun-09 23:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.