Virtual Developer Workshop: Containerized Development with Docker

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:

  1. CWaveReader: wave file reader. It is used by CWavePlayer;
  2. CWavePlayer: wave file player;
  3. CWaveWriter: wave file writer. It is used by CWaveRecorder;
  4. CWaveRecorder: the sound recorder.

To play a wave file, you need to:

  1. Use CWaveReader to open the wave file. For example:
  2. CWaveReader * reader = new CWaveReader("c:\sample\scream.wav");
  3. Create a new CWavePlayer object. For example:
  4. CWavePlayer player = new CWavePlayer();
  5. Associate the player with the wave reader created in Step 1. The code is:
  6. player.Open(reader);
  7. Ask the player to start. For example:
  8. 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:

  1. Use CWaveWriter to careat a new wave file. For example:
  2. CWaveWriter * writer = new CWaveWriter ("c:\sample\new_scream.wav");
  3. Create a new CWaveRecorder object. For example:
  4. CWaveRecorder player = new CWaveRecorder ();
  5. Associate the recorder with the wave writer created in Step 1. The code is:
  6. recorder.Open(writer);
  7. Ask the recorder to start. For example:
  8. 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:

  1. Open(): Associate the player with a wave reader;
  2. Start(): You must call Start() to begin playing a wave file after Open();
  3. Pause(): Pause playing a wave file. Call Resume() to continue playing. (Calling Start() will have no effect.);
  4. Resume(): Resume playing a paused wave file;
  5. Reset(): Reset the wave file to its beginning and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
  6. FastForward(): Fast forward the wave file and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
  7. FastReverse(): Fast reverse the wave file and stop playing. Call Start() to continue playing. (Calling Resume() will have no effect.);
  8. 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.
  9. 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

  1. CWaveFile—a Class for Working with and Representing Data from WAVEs, Alexander Beletsky.
  2. Playing Audio in Windows using waveOut Interface, David Overton
  3. Microsoft MSDN Multimedia Functions, Microsoft



  • Pls advise to record sound under PCM 13bit uniform

    Posted by newer1983 on 06/03/2009 01:10pm

    Hi 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,

    • GSM

      Posted by LEE GI BEMO on 01/27/2010 04:08am

      GSM 06.10

  • Sending WAV FILES to parallel port to control LIGHTs

    Posted by andersonfobr on 03/31/2009 01:52am

    Hi 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?

  • Bugfix for the threading

    Posted by texasjack on 11/07/2007 11:34am

    m_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.

  • help plz,

    Posted by mohahhh on 01/29/2006 09:52pm

    hi 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

    • MFC is not needed

      Posted by cgsprinter on 02/01/2006 12:26am

      I was using STL not MFC in my code so I guess it should be OK using the lib without MFC. Thanks!

  • increasing thread count

    Posted by evian on 10/21/2005 09:06pm

    I am using this lib in my application to generate audio alerts , what I noticed was for every alert being generated it was starting a new thread , hence if the application runs over a time it creates a problem. 
    It is suggested to use  close() on both player & reader after start(), and finally quit().

  • regarding using wav files

    Posted by awalanchal on 07/05/2005 03:53pm

    i 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

  • can any body suggust a way to make it full duplex

    Posted by iftahg on 06/11/2005 09:11am

    hi 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

    • sdas

      Posted by wu99yu on 10/22/2007 05:18am


    • and what if the data is striming, say in packt

      Posted by iftahg on 07/17/2005 06:24pm

      hi, 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.

    • About the fullduplex

      Posted by cgsprinter on 06/11/2005 02:55pm

      Hi 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!

  • Doesn't work for all wave files.

    Posted by cosmin1 on 05/06/2005 04:40pm

    Doesn't work for all wave files. See "start.wav" or "windows xp information bar.wav" from windows media directory.

    • at my end(on my XP) it works fine

      Posted by iftahg on 06/11/2005 09:06am

      hi 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 .

    • comment

      Posted by bonjour on 06/10/2005 12:31pm

      when i record i can't hear my voice..it doesn't look like record program of winXP... you can modify it?

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date