Audio Classes Library w/ n-Channel Real-Time Mixer demo
<You can right-click on the channel for a context menu that includes displaying the spectrum graph.>
Environment: Win 98/NT/2000, Visual C++ 6
The AudioClasses Library demonstrates the following:
- Loading a wave file manually. (thanks to Timothy J. Weber's Rifffile code)
- The Audio Compression Manager API
- Mixing n-channels of stereo audio
- Waveform Audio API : Outputing audio data to sound device
- Implimenting a Spectrum Analyzer and Spectrum Analyzer (peak-valley) Graph
- Fast Fourier Transforms
- Mixer Control : Implimenting a custom listbox
The AudioClasses library simplifies much of the work involved in playing from a compressed sound source and includes mixing of many sources at once in real-time into a single sound stream. The library is based on audio streams. You can connect stream objects together like a chain to perform the desired operation.
There are two base types of streams, PlayStream and FilterStream. A PlayStream is meant to be a source of audio data, usually from a file but can be from another source such as a database. A PlayStream class impliments the 'WaveBuffer GetBuffer()' virtual method providing a chunk of audio data (a WaveBuffer) to the requesting object. The requesting object can be another input stream, the player, or a custom object. The WaveStream (loads a wave file) is an implimentation of a PlayStream.
A FilterStream is derived from PlayStream but also accepts an input PlayStream. FilterStreams are used to perform some operation on the input stream before passing its audio data to the requesting object through the 'WaveBuffer GetBuffer()' virtual method. The ConversionStream (uses the ACM API) is an implimentation of a FilterStream. The SpectrumAnalyzer is also a FilterStream that passes the input directly to the output but performs Fast Fourier Transformation on the audio data so it can be graphed as a spectrum analyzer. The Mixer is also a form of a FilterStream although it accepts many input streams and thus is derived from PlayStream.
Derive your own class from PlayStream or FilterStream and they will be compatible with the library and can be inserted into the stream chain at any point. For example, you may create your own FilterStream to perform echo cancellation on an input stream, or create a PlayStream that loads audio data from a database.
In the mixer demo, audio data starts from the wave source stream (WaveStream) into the Audio Compression Manager (ACM) stream (ConversionStream) then into the mixer stream (PlayStream), then the output of the mixer stream is connected to the Player. The Player requests buffers from its input stream, it is the end of the stream and is thus the consumer. The requests are directed through the stream chain as they are requested from the consumer.

NOTICE: Code from the FFTW Project has been used in the making of this project. This excellent code is used to generate the Spectrum Analyzer for the AudioClasses library. Here is the introductory statement found on the FFTW web site:
- 'FFTW is a C subroutine library for computing the Discrete Fourier Transform (DFT) in one or more dimensions, of both real and complex data, and of arbitrary input size. We believe that FFTW, which is free software, should become the FFT library of choice for most applications.'
Using the AudioClasses Library:
First, you must declare a mixer object to contain the mixing sources and a player to send the mixed audio to the sound device.
/* the mixer target : the sound card */ Player m_player; /* our mixer control that contains the mixer stream */ CMixerListBox m_channels;
Following is the relevant code in the mixer demo that initializes the mixer:
/* set channel listctrl icons */ m_channels.SetVolumeIcon(AfxGetApp()->LoadIcon(IDI_VOLUME), AfxGetApp()->LoadIcon(IDI_MUTEDVOLUME)); /* set channels custom listctrl to point to mixer */ m_channels.Popup(IDR_MIXERPOPUP); /* set the mixer as the play stream */ m_player << m_channels;
You can load some files into the mixer with the following, or use the AddStream if you have an existing stream:
/* load some files into the mixer */
m_channels.Load("c:\\sample1.wav");
m_channels.Load("c:\\sample2.wav");
m_channels.Load("c:\\sample3.wav");
Now you can start playing the mix:
/* start playing */
player.Play();
Updates
November 28, 2001- Memory leak causing application to freeze.
- Some 'missing file reports' due to bad links in project file.
Downloads
Download demo project - 2,575 KbDownload source - 88 Kb

Comments
Detected memory leaks!
Posted by HpyWho on 04/04/2006 10:13amwhen i run, i detected memory leaks,can you help me? very thanks.
ReplyProducing a single *.wav file output
Posted by cain2143 on 11/30/2004 11:09pmAfter mixing or adding all the *.wav files into the Player object, how may I use the AudioClasses to output a single *.wav file from the Player?
ReplyI found a problem when re-plug the USB audio device.
Posted by dbckdrb on 07/19/2004 08:14amIf you have a USB audio device, then you can make the same situations. Here is a steps. 1. Load a wave files. 2. Unplug the USB audio device while playing 3. Wait while play stops. 4. Plug the USB audio device. 5. Check! Is that mixer device list up? (My system can't shows the mixer but shows device) Is this problem out of bound of this program? (maybe)
ReplyHow to convert Level value to dB ?
Posted by Legacy on 01/21/2004 12:00amOriginally posted by: wyw
Hi,
Is there a way to convert the Level value return by the Mixer into dB ?
Thank You,
wyw
-
Replyis very easy
Posted by alainstgt on 12/07/2005 11:10amthe dB value is 10*log10(level/reference level). In acoustics the refence sound pressure is 0.00002 Pa (Pascal), the reference level the square of that value. Since an addition is performed much faster than a division, you can change the formula like following: 10*(log10(level)-log10(reference level)). With rhe previous mentioned value, you get log10(reference level)= 93,9794 dB, which is usually rounded to 94 dB. So thr formula to get the dB level is: dB = 10*log10(sound pressure level) - 94! thats all. Note that what is commonly named the level, is in a strenght way not the level, but I used your terminology to not confuse.
ReplyGetting Left/Right channel level values
Posted by Legacy on 01/20/2004 12:00amOriginally posted by: wyw
Hi,
How do you go about extracting the individual left and right channel peak level value from a playing wave file?
m_channels.level //This seem to be the combined result of left and right
Thank You,
Replywyw
Help with wave mixing algorithm
Posted by Legacy on 01/19/2004 12:00amOriginally posted by: Ashley McGilvery
Hi would you be able to describe in words the algorithm for mixing the waves. The one I am using at home is to add the samples and devide by the number of tracks. This works although the volume seems to be belong unity level.
ReplyProblem compiling with Visual Studio 7
Posted by Legacy on 01/10/2004 12:00amOriginally posted by: cslick
Hi Colin,
I see that you created your project with Visual C++ 6, but I'm trying to build in VC++ 7 and getting an error: "error C3803: 'bool:Property::AsString()': property has a type which is incompatible with one of its accessors 'CString&Property::asstring(void)'. The problem is on line 56 of "Property.h". I am very new to windows programming - any clue how to fix this error? Thanks.
ReplyMixing properties
Posted by Legacy on 09/21/2003 12:00amOriginally posted by: Lee
Thanks for your short tutorial on compiling.
A few days ago you replied to my request for help on the filterstream(echoes) & I hope you can help me once again.
I wanted to create an echo that is one second later. So I altered the getbuffer virtual method of wavestream by reading data from the audio file twice & putting them in 2 different buffers:
1)fread from file into buffer.data (of wavebuffer buffer)
2)fseek -11*RequestSize from SEEK_CUR (1 sec offset)
- fread from file into buffer1.data(of wavebuffer buffer1)
3)fseek 10*RequestSize from SEEK_CUR(return to original pos)
4)return buffer2 (which mixes buffer & buffer1)
I have created 3 buffers- buffer which contains the current audio data, and buffer 1 which contains audio data 1 secs back. buffer 2 is supposed to be a mix of the 2 buffers.
I have read how u mix the streams in the mixer & frankly it was difficult for me to understand (I am still a beginner). Do you mind giving me advice on how I can combine the 2 buffers' data & store them into buffer2 ?
Please help me in this.
Thanks a million.
regards,
Lee
ReplyCan you help me...
Posted by Legacy on 09/16/2003 12:00amOriginally posted by: Lee
Hi,
So sorry to trouble you. Previously I was doing a project using your audio classes. What I did was just copy the header files for the various classes into my external dependencies & the dAudiolib.lib.It worked. However I find I have trouble trying to add more functions to the program.
I was trying to add the function waveOutSetPitch in Player.cpp but cannot find it in my project directories. So I copy it over & edited it. However there is a "unexpected end of file while looking for precompiled header directive" problem when I was compiling Player.cpp. I tried compiling your original player.cpp in your demo project, & the same thing happens.
Am I missing out on something here? Did I forgot to do something.
Your help is appreciated.
ReplyThanks in advance,
Lee
Filter Stream help.
Posted by Legacy on 09/05/2003 12:00amOriginally posted by: Lee
I am trying to find a way to add some other functions to the conversion stream. Anybody knows of any examples (such as adding echoes, reverberation or audio filters) that can manipulate the buffers in the stream.
Thanks.
ReplyThank You. Mr Colin. I will try that out.
Loading, Please Wait ...