Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 25 Sep 2008
Rate this:
Please Sign up or sign in to vote.
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:

//
#include <span class="code-string">"Wave.h"</span>
//
//
// 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:

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)

Share

About the Author

darkoman
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

 
QuestionHow can i make it work on Windows 7, working with VS2008? PinmemberMember 1089953924-Jun-14 4:19 
QuestionHow can i make it work on Windows 7, working with VS2010? PinmemberMember 777610429-Dec-12 2:08 
SuggestionNote on use of LPWORD: 16-bit wav is signed PinmemberMember 88193275-Sep-12 18:53 
Question[My vote of 1] Doesn't work under Windows 7 PinmemberSteve Cunningham6-Aug-12 3:28 
GeneralExport this Class to a Dll Pinmember77Chris7720-Jul-12 5:10 
GeneralDev-C++ Error: _T, _tfopen was not declared in this scope Pinmembermirekpl69-Jul-12 4:57 
BugSecond Bug in WaveOut_Proc PinmemberVAndersen10-Aug-11 12:18 
GeneralRe: Second Bug in WaveOut_Proc PinmemberMember 83006348-Oct-11 7:28 
GeneralUrgent, please Pinmemberikyr999911-May-10 0:24 
GeneralError LNK2019:unresolved external symbol.. I appreciate help! PinmemberAnders Branderud31-Mar-10 8:49 
GeneralProblem solved! PinmemberAnders Branderud31-Mar-10 8:59 
GeneralDoesnt work for me Pinmemberalexkx312-Mar-10 8:25 
GeneralNoOutput PinmemberDr Bob.23-Jan-10 8:39 
GeneralRe: NoOutput PinmemberAbil B.29-Jul-10 18:10 
RantLoop problem! PinmemberJeremy Soh19-Jan-10 22:54 
Generalthe code does not play the wavfiles when i click on play Pinmember1s2a3b4a9-Jan-10 9:43 
Generalsome tiny bugs report PinmemberMember 425721529-Nov-09 6:53 
Questioncan MIX work for more than two file? PinmemberMember 790824-Nov-09 1:47 
AnswerRe: can MIX work for more than two file? Pinmemberdarkoman24-Nov-09 11:40 
AnswerRe: can MIX work for more than two file? Pinmemberjimmysheep18-Aug-10 16:19 
QuestionHow to get the finished playing message in order to repeat playing? Pinmemberzhouyigang4-Oct-09 15:53 
Generalquestion about a related project [modified] Pinmemberpblais7-Sep-09 13:23 
GeneralRe: question about a related project Pinmemberdarkoman11-Sep-09 21:52 
GeneralBug in WaveOut_Proc Pinmemberplaymyskay25-Jun-09 23:57 
GeneralRe: Bug in WaveOut_Proc Pinmembergargle2568-Oct-12 1:12 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 25 Sep 2008
Article Copyright 2008 by darkoman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid