Wave Player & Recorder Library
Here, I will introduce an easy-to-use wave IO library. It can be used to play existing PCM encoded wave files or record sound. I am trying my best to make my explaination clear and I hope you find this library helpful. I used some lines of Alexander Beletsky's code to read wave files. A lot of thanks here.
1. Library Overview
There are four classes in this library that can be used directly in your program:
- CWaveReader: wave file reader. It is used by CWavePlayer;
- CWavePlayer: wave file player;
- CWaveWriter: wave file writer. It is used by CWaveRecorder;
- CWaveRecorder: the sound recorder.
To play a wave file, you need to:
- Use CWaveReader to open the wave file. For example:
- Create a new CWavePlayer object. For example:
- Associate the player with the wave reader created in Step 1. The code is:
- Ask the player to start. For example:
CWaveReader * reader = new CWaveReader("c:\sample\scream.wav");
CWavePlayer player = new CWavePlayer();
player.Open(reader);
player.Start();
Then, you can call the Pause(), Resume(), FastForward(), FastReverse(), Reset() functions provided by the CWavePlayer to do various things on the player.
To record sound, the steps are just the same:
- Use CWaveWriter to careat a new wave file. For example:
- Create a new CWaveRecorder object. For example:
- Associate the recorder with the wave writer created in Step 1. The code is:
- Ask the recorder to start. For example:
CWaveWriter * writer = new CWaveWriter ("c:\sample\new_scream.wav");
CWaveRecorder player = new CWaveRecorder ();
recorder.Open(writer);
recorder.Start();
The only difference is that the recorder does not provide FastForward and FastReverse functions.
2. Library Anatomy
The most important class in this library is CWaveIOBase. It is the base class of CWavePlayer and CWaveRecorder.
This class maintains three queues. One queue contains wave data (called 'ready wave headers') waiting to be sent to the wave device; another queue maintains wave data (called 'in use headers') that have been sent to the wave device; the last one contains empty buffers (called 'free headers') waiting to be filled with wave data.
The CWaveIOBase creates two threads to manage these three queues (see Figure 1).
Thread 1 manages the "free headers" and "in use headers" queues. If there is any element in the "free headers" queue, this thread takes it out and calls the virtual function PrepareFreeHeader(...), which is to be implemented by CWavePlayer and CWaveRecorder, to have it filled with wave data. Then, this thread sends the element to the "ready wave headers" queue.
The first thread also checks the "In Use Headers" queue to see whether there are any elements that have been consumed by the wave device. If there are, this thread takes them out, calls the virtual function FreeReturnedHeader(...) to free them, and at last sends them to the "Free Headers" queue.
Thread 2 manages the "Ready Headers" queue. If there are any elements in this queue, this thread calls the virtual function SendToSoundDevice(...) to send them to the wave device.
Another important class in this library is CWaveDataStore, the base class of CWaveReader and CWaveWriter. CWaveDataStore provides interfaces for wave data reading (used by player) or writing (recorder).
CWaveDataStore declares four virual member functions (see Figure 2).
The StoreData(...) function is implemented by the wave writer to save recorded wave data; the wave reader implements the FetchData(...) function to read wave data from, for example, a wave file. The GetWavePara(...) virtual function tells a wave player (or wave recorder) the properties of the wave data to play (or record); for example, the sample rate, number of channels, and bits per sample. The last virtual function, Seek(...), moves reading or writing wave data pointers.
3. Player/Recorder Operations
The following operations are provided by CWavePlayer:
- Open(): Associate the player with a wave reader;
- Start(): You must call Start() to begin playing a wave file after Open();
- Pause(): Pause playing a wave file. Call Resume() to continue playing. (Calling Start() will have no effect.);
- Resume(): Resume playing a paused wave file;
- Reset(): Reset the wave file to its beginning and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
- FastForward(): Fast forward the wave file and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
- FastReverse(): Fast reverse the wave file and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
- Close(): De-associate the wave reader with the player. It is your own responsiblity to close the wave reader after calling Close() on the player. The player does not close the reader for you.
- Quit(): Quit the player. All threads will exit and queues cleared, which mean the player will not work any more.
Figure 3 describes these operations (Open() and Close() not included).
The arrowed lines mean that, if you call an operation at the beginning of a line, you need to call the operation at the end of the same line to make the player continue to work. For example, if you call Start() directly after Pause(), you will hear no sound. But if you call Reset() after the Pause(), and then the Start(), the player will run.
CWaveRecorder has the same set of operations except FastForward and FastReverse. Note that calling Reset on a CWaveRecorder means all previously recorded data is lost.
4. Others
The library is included in the demo project for downloading. Remember to use a multithreaded runtime library in your project.
If you find bugs or have any questions on using this library, please feel free to let me know. Thanks again for reading this article.
5. References
- CWaveFile—a Class for Working with and Representing Data from WAVEs, Alexander Beletsky.
- Playing Audio in Windows using waveOut Interface, David Overton
- Microsoft MSDN Multimedia Functions, Microsoft

Comments
Pls advise to record sound under PCM 13bit uniform
Posted by newer1983 on 06/03/2009 06:10amHi cgsprinter, Your project is very wonderful. I'm researching about record sound from microphone under PCM 13bit uniform (or GSM standard). Pls advise me how to do it, Thanks a lot! Regards,
-
ReplyGSM
Posted by LEE GI BEMO on 01/26/2010 08:08pmGSM 06.10
ReplySending WAV FILES to parallel port to control LIGHTs
Posted by andersonfobr on 03/30/2009 06:52pmHi I was just wondering if I could use this with a specially formatted wav file: L channel with music and R channel with commands for my parallel-port controlled light effects machine. I use this light effects machine in parties (I have sixty-four 500W light cannons). I would edit wav files with a special editor, then I would send L channel to audio output and R channel to parallel port, whit the light effetct machine connected to it. This way, I would be able to control lights with total synchronism with music. And I would add a GUI to the editor to facilitate creation of the light effects. WOuld this be possible with this lib?
ReplyBugfix for the threading
Posted by texasjack on 11/07/2007 03:34amm_wsuspended,m_ssuspended,m_quit,m_suspend in WaveIOBase.h must be made volatile in order to make this example work ok without pure luck.
Replyhelp plz,
Posted by mohahhh on 01/29/2006 01:52pmhi is it possible to use just the "WaveIOLib"files without the whole code in visual c++,without the mfc interface if yes plz how,cos when i do so it gives me errors thanks in advance
-
ReplyMFC is not needed
Posted by cgsprinter on 01/31/2006 04:26pmI was using STL not MFC in my code so I guess it should be OK using the lib without MFC. Thanks!
Replyincreasing thread count
Posted by evian on 10/21/2005 02:06pmregarding using wav files
Posted by awalanchal on 07/05/2005 08:53ami m newbie to vc++ and dont know how to use the above said library with my project.. moreover there is no .lib file in the .zip file above .. plz help me and tell me how can i use it.. thanks
Replycan any body suggust a way to make it full duplex
Posted by iftahg on 06/11/2005 02:11amhi you all, can anybody suggust a way for making this grate code work in fullduplex. the pb', the way i see it is that: it uses Cwavwwriter class which writes the wave to a file. and then you cannt acsses it from the player. there is got to by a way for making it work with a regelar say 160 sampales packt type insted of working with files. can anybody help my with this. thank's , iftah
-
-
-
Replysdas
Posted by wu99yu on 10/21/2007 10:18pmasdsad
Replyand what if the data is striming, say in packt
Posted by iftahg on 07/17/2005 11:24amhi, cgsprinter what if the data is striming, say in packt, lets say about 160 byte's per packt. how would you sugust to takel this one?? thank's, iftah.
ReplyAbout the fullduplex
Posted by cgsprinter on 06/11/2005 07:55amHi ifahg, I realized the problem that the code is not fullduplex. I was short-sighted when I was required to design the code. Sorry for that. And the code can only process PCM wave (you need to write your CWaveReader to decompresss other format Wave files) One possible solution to make it full-duplex is in the function CWaveRecorder::FreeReturnedHDr, where recorded data is returned by the device, adding some code to send it to sound device again. But I am not sure whether it would work or not. Anybody knows there is a flag or something to turn on the sound device so that it would be automatically fullduplex? Thanks!
ReplyDoesn't work for all wave files.
Posted by cosmin1 on 05/06/2005 09:40amDoesn't work for all wave files. See "start.wav" or "windows xp information bar.wav" from windows media directory.
-
-
Replyat my end(on my XP) it works fine
Posted by iftahg on 06/11/2005 02:06amhi all, i have chaked it and it's grate, he keapt it simple it rich and very elagent. about your pb' with the start.wav and co'.... if i'll look at the base class's open function, you'll see that the format's tag is by default 1 wich meens linar PCM format and the no of chanels and smpale rate and all that other format are fixed so, mybe, just mybe the recorded files are in a difrent format, so from that resone it mythe not work. tray recording a file say c:\test.wav, and then play it as is and it will work fine .
Replycomment
Posted by bonjour on 06/10/2005 05:31amwhen i record i can't hear my voice..it doesn't look like record program of winXP... you can modify it?
Reply