### Creating Master Devices

The master volume control determines the maximum volume level of all audio output devices in the system. It sets a scale by which all subsequent volume commands are based. For instance, if the volume control sets the master volume at 50 percent, then all volume levels are cut in half.

Use the IMMasterAudio class to create a master audio object.

The master audio object has functions that do the following:

- Returns the current or saved setting of headphones, speakers, and master volume.
- Saves the current setting of headphones, speakers, and master volume.
- Sets the headphones and speakers on or off.
- Sets the master volume to a percent of the total volume available.

Note: | We recommend that you do not use a master volume control in your application unless it absolutely requires you to do so. This control affects all volumes in your system. One scenario that is appropriate for using a master volume control is when you are using the amplifier-mixer device class to control a complete system. In this case, you want to control all volume in the system.

#### Creating Amplifier-Mixer Devices (IMMAmpMixer)

The visuals and functions of the amplifier-mixer device are similar to the amplifier-mixer device on your home stereo system. Components are plugged into the amplifier-mixer so that audio signals can be transferred to a pair of attached speakers, headphones, or another device. The amplifier-mixer is the center of all audio signals and provides input or output switching and sound-shaping services, such as volume, treble, or base control.

Use the IMMAmpMixer class to create an amplifier-mixer device. Its specific functions include the following:

- Controlling the balance, bass, treble, gain, and pitch of a signal
- Connecting other devices that need the above functions to the amplifier-mixer
- Turning off and on the sound that is routed through the amplifier-mixer to another device

Creating an Amplifier-Mixer Device: An Example

An example that creates an amplifier-mixer device follows.

1. Define the device in the .hpp file as follows:

       class AmpHandler    : public ISliderArmHandler { typedef ISliderArmHandler  Inherited;
       //*********************************************************************
       //Class:   AmpHandler                                                 *
       //                                                                    *
       // Purpose: Provide a handler for processing the circular sliders.    *
       //          It is derived from ISliderArmHandler.                     *
       //                                                                    *
       //*********************************************************************
       public:

        AmpHandler ();

        virtual bool  moving   (IControlEvent& evt);
       };

       class Amp    : public IMultiCellCanvas {
       //*********************************************************************
       // Class:   Amp                                                       *
       //                                                                    *
       // Purpose: Provide an  amplifier-mixer for use by             *
       //          all of the devices.                                       *
       //          It is derived from IMultiCell.                            *
       //                                                                    *
       //*********************************************************************
       public:

       Amp(unsigned long windowid,   IWindow* parent,  IWindow* owner);

         ICircularSlider
              slVolume,
              slBalance,
              slBass,
              slTreble,
              slPitch,
              slGain;

         AmpHandler    ampHandler;

         IStaticText   name;
       };

       class MainWindow : public IFrameWindow {
       //*****************************************************************
       // Class:   MainWindow                                            *
       //                                                                *
       // Purpose: Main application window.                              *
       //          It is derived from IFrameWindow.                      *
       //*****************************************************************
       public:

         MainWindow( unsigned long windowId);

       private:
         ISetCanvas      clientCanvas;

         Amp*            amp;
       };

2. Create the constructors for the MainWindow and the amplifier-mixer as follows:

       MainWindow::MainWindow( unsigned long windowId)
                 : IFrameWindow("Amplifier-Mixer Example",windowId),        //Call IFrameWindow constructor
                   clientCanvas(CLIENTCANVASID,this,this)
       {
         amp        = new Amp(AMP_ID, &clientCanvas, this);

          clientCanvas.setBackgroundColor(IColor(IColor::kBlack));
          setBackgroundColor(IColor(IColor::kPaleGray));
          IFont("Helv",8).setWindowFont(this);

          setClient(&clientCanvas);
          clientCanvas.setDeckOrientation(ISetCanvas::vertical);
          ISize size = clientCanvas.minimumSize();
          IPoint point = position();
          moveSizeToClient(IRectangle(point.x(),
                                      point.y(),
                                      point.x() + size.width(),
                                      point.y() + size.height()));

          show();
          setFocus();
       }

       /*------------------------------------------------------------------------------
       | Amp::Amp                                                                                                       |
       |                                                                                                                     |
       |                                                                                                                     |
       ------------------------------------------------------------------------------*/
       //Amp::Amp(IMMAmpMixer& aAmp,
       Amp::Amp(
                unsigned long windowid,
                IWindow*          parent,
                IWindow*          owner)
          : IMultiCellCanvas(windowid,parent,owner),
            name            (AMPNAMEID, this,owner),
            slVolume        (SL_VOLUME_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            slBalance       (SL_BALANCE_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            slBass          (SL_BASS_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            slTreble        (SL_TREBLE_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            slPitch         (SL_PITCH_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            slGain          (SL_GAIN_ID,this,this,IRectangle(),
                             ICircularSlider::defaultStyle()
                             | ICircularSlider::proportionalTicks ),
            ampHandler()
       {
          // Set up the title
          name.setText("Class Library Amp/Mixer Player");
          name.setForegroundColor(IColor(IColor::kRed));

          slVolume.setArmRange     (IRange(0,100));
          slVolume.setRotationIncrement (1);
          slVolume.setText      ("Volume");
          addToCell             (&slVolume,     1, 1, 1, 1);

          slBalance.setArmRange    (IRange(-50,50));
          slBalance.setRotationIncrement(1);
          slBalance.setText     ("Balance");
          addToCell             (&slBalance,    2, 1, 1, 1);

          slBass.setArmRange       (IRange(0,100));
          slBass.setRotationIncrement   (1);
          slBass.setText        ("Bass");
          addToCell             (&slBass,       3, 1, 1, 1);

          slTreble.setArmRange     (IRange(0,100));
          slTreble.setRotationIncrement (1);
          slTreble.setText      ("Treble");
          addToCell             (&slTreble,     4, 1, 1, 1);

          slPitch.setArmRange      (IRange(0,100));
          slPitch.setRotationIncrement  (1);
          slPitch.setText       ("Pitch");
          addToCell             (&slPitch,      5, 1, 1, 1);

          slGain.setArmRange       (IRange(0,100));
          slGain.setRotationIncrement   (1);
          slGain.setText        ("Gain");
          addToCell             (&slGain,       6, 1, 1, 1);

          addToCell             (&name,       3, 2, 3, 1);

          ampHandler.handleEventsFor(this);
       }

       /*------------------------------------------------------------------------------
       | AmpHandler::AmpHandler                                                       |
       |                                                                              |
       |                                                                              |
       ------------------------------------------------------------------------------*/
       AmpHandler::AmpHandler()
                 : AmpHandler::Inherited()
       {}

       /*------------------------------------------------------------------------------
       | AmpHandler::moving                                                          |
       |                                                                              |
       |                                                                              |
       ------------------------------------------------------------------------------*/
       bool AmpHandler::moving   (IControlEvent& evt)
       {
          bool result=false;
             switch (evt.controlId())
             {
              case SL_VOLUME_ID:
                   result = true;
                   break;
              case SL_BALANCE_ID:
                               //Added 50 since balance can only be 1 to 100 where
                               //0 is full to the left and 100 is full to the right
                   result = true;
                   break;
              case SL_BASS_ID:
                   result = true;
                   break;
              case SL_TREBLE_ID:
                   result = true;
                   break;
              case SL_PITCH_ID:
                   result = true;
                   break;
              case SL_GAIN_ID:
                   result = true;
                   break;
             } /* endswitch */

          return result;
       }

The following figure shows an amplifier-mixer player. All audio signals and sound shapings are controlled here.

#### Creating CD Audio Player Devices (IMMAudioCD)

The CD audio player device's interface should look and function similarly to your home CD system as it uses the same meduim, the compact disk.

A compact disc can store up to 74 minutes of 44.1-kilohertz, two-channel audio encoded as digital information. The audio compact disc, or the audio portion with both data and audio on it, is organized as tracks, where one track is typically one song. A track can be any length you want it to be, as long as it fits in the length of the disc. The length of a compact disc track is measured in minutes, seconds, and frames, where one frame is 1/75 second. It is possible to play portions of a track, starting and stopping within the accuracy of a single frame. While an application can play portions of a track, the amount of time required to seek from one track to another and locate the starting frame in question can be substantial; it can vary depending on where you are starting from. If your application calls for playing numerous sounds from a CD with precise timing, make sure they are located physically close together on the disc.

In addition to playing tracks, you can find out things about a CD, such as how many tracks it contains and how long each track is, or you can query a CD's table of contents.

The CD device class, IMMAudioCD, provides access to devices that read CDs in order to play a compact disc's digital audio data. This data format, which is digital audio, consists of sound that has been recorded as a sequence of 1's and 0's. A digital-to-analog converter recreates the original waveforms at playback.

You can perform the following functions with the IMMAudioCD class:

- Playing
- Scanning
- Tracking
- Querying a CD's table of contents
- Querying a UPC code or country code (a UPC code is a serial number that is assigned to a disc)
- Setting up to play a particular song automatically
- Forwarding or reversing to a particular track
- Forwarding or reversing to a particular location (for example, 2 minutes into track 3)

Also useful is the ability to program the order in which a CD plays its tracks. Using the IProfile class, you can record in a file the song title or track information. The IMMAudioCD object loads the profile data and plays the CD based on the contents of the data. This might be useful in a CD store, where a system allows you to listen to CDs, traversing through the various tracks in six minutes.

You can use the following command to create a CD device object:

    #include <immcdda.hpp> // Define the header file
    IMMAudioCD cdPlayer;         // Define the object
    cdPlayer(true)               // Pass true to the device constructors so
                                 // the devices are opened and no additional
                                 // function calls are made before using
                                 // the device.

Multimedia Devices

Playing Audio Compact Discs
Creating Audio Devices
Creating Video Devices
Adding Animated Buttons and Circular Sliders

IAnimatedButton
ICircularSlider
IMMAmpMixer
IMMAudioCD
IMMasterAudio
IMMPlayerPanel
IMMRecordable
IMMWaveAudio
IMultiCellCanvas
ISliderArmHandler
IStaticText