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.'
Thanks guys! ;-)

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 Kb
Download source - 88 Kb