Feedback Search Top Backward
EDM/2

Building a CD Player - Part 1/4

Written by Stephane Bessette

Linkbar

 
Part1 Part2 Part3 Part4
[NOTE: Here is a link to a zip of the source code for this article. Ed.]

Introduction

This series of articles will present the steps necessary to build a simple application that plays audio CDs. The interface will present menus for all possible actions, buttons for the most common action, and display some information about the currently inserted CD, such as the number of the current track and some form of time display (eg. the time remaining in the current track). Finally, dialogs will present and request various information.

Here's the list of the actions commonly found in audio CD players that will be implemented: Play, Stop, Pause, Resume, Next and Previous track, Backward and Forward seek, Insert, Eject. In addition, Mute, Unmute, and Volume level will also be implemented.

This program will rely on various controls: menu (unchecked/checked, active/disabled), pushbutton (visible/invisible), graphical button, radio button, circular slider, and static text fields. And dialogs will be used to (1) show information about each audio track on the CD (table of contents), (2) select the connector to use: headphones or stream, and (3) select the volume level.

Finally, when communicating with the CD device, two MCI commands will be used: mciSendCommand() to issue various commands to the CD device, and mciGetErrorString() to convert an error number into an error string. Let's start by looking at these two commands more closely.

mciSendCommand()

All commands to the CD device will be issued with the mciSendCommand API. Its syntax is:


     ulrc = mciSendCommand(USHORT usDeviceID,  // (1)
                           USHORT usMessage,   // (2)
                           ULONG ulParam1,     // (3)
                           PVOID pParam2,      // (4)
                           USHORT usUserParm); // (5)

(1) The ID of the device
(2) The message to send
(3) Parameters; MCI_WAIT or MCI_NOTIFY, and other flags
(4) The address of a structure containing additional data
(5) User parameter, probably used when there's more than
    one device in use
When issuing a MCI command, you have to specify the ID of the device that is to receive the command. In this program, we'll obtain the ID of the CD device and send commands to that device. Quite a few commands can be issued, and the most relevant ones will be covered. These commands can function in two modes. By specifying MCI_WAIT, the execution of the program will be stopped until the command is completely processed. This is conceptually similar to the WinSendMsg() API. And by specifying MCI_NOTIFY, the execution of the program will resume immediately. When the command is completely processed, a message will be posted to the window specified in the hwndCallback member of the structure (4) passed along with the command. This is conceptually similar to the WinPostMsg() API.

MCI_WAIT or MCI_NOTIFY?

So how do we determine which to use? It could be argued that all commands should use the MCI_NOTIFY flag, since this would not tie up OS/2's message queue. However, some commands execute quite rapidly, and would not have a great impact on the overall responsiveness of the system. But there are some exceptions. Open (MCI_OPEN) takes some time before returning, so it is better written with the MCI_NOTIFY flag. And in some cases you absolutely have to use MCI_NOTIFY. For instance, the play (MCI_PLAY) command terminates only when the end of the audio CD is reached; using MCI_WAIT would essentially freeze the system since messages would no longer be processed.

Notification Messages

When the MCI_NOTIFY is specified, the command will send an MM_MCINOTIFY message to the window specified in the hwndCallback member of the structure passed as one of the parameters of the mciSendCommand() function. The first short of mp1 will contain the notification message.


  -MCI_NOTIFY_SUCCESSFUL
      The command completed successfully
  -MCI_NOTIFY_SUPERSEDED
      Another similar command was issued and will be
      processed (eg. Two successive play commands)
  -MCI_NOTIFY_ABORTED
      The command was aborted by a second command
      (eg. A Play command followed by a Stop command)
And if none of these messages are received, then an error occurred. The second short of mp2 contains the ID of the commands, such as MCI_PLAY.

mciGetErrorString()

To determine whether the MCI command was successful or not, the low part of the return code must be examined:


  if(LOUSHORT(ulrc) == MCIERR_SUCCESS) {
      // The command was successful
  }
  else {
      // The command was not successfull
  }
If the command was not successful, you can obtain a textual description of the error code with mciGetErrorString():

     ulrc = mciGetErrorString(ULONG ulError,     // (1)
                              PSZ pszBuffer,     // (2)
                              USHORT usLength);  // (3)

(1) The error code from mciSendCommand()
(2) A string to contain the description
(3) The size of this string

MCI Structures

To finish on the topic of the MCI commands, I'll mention that most commands require additional information to be specified in the structure (4) passed as a parameter of the mciSendCommand(). But for this member to be considered, you often need to specify an additional flag in the ulParam1 (3) parameter. We'll see many examples of this in the sections to come, where we actually issue commands. The next section will open and query the CD device's capacities.

Source


Basic.hpp
     Defines two often used macros (InfoBox and ErrorBox)
     Defines two user message

BasicDialogFramework.cpp
     Standard file to support a dialog as the main interface

Main.cpp
     Handles the interaction from the three dialogs:
          CD Player dialog
               User commands
               Notifications from various MCI commands
          Connector selection
          Volume level selection

Class_CDROM.hpp
     Header for the Class_CDROM class
     Definition of three supporting structures:
          Struct_Volume
          Struct_TOC
          Struct_DeviceCapacities
     Definition of inline functions

Class_CDROM.cpp
     Implementation of the members of the Class_CDROM class

Class_Controls.hpp
     Header for the Class_CDROM class
     Implementation of inline functions

Resource.def
     Application definition

Resource.hpp
     Header for the various resources used:
          icon
          bitmaps
          dialogs
          controls
          menuitems

Resource.rc
     Application resources:
          icon
          bitmaps
          menu
          accelerator table

Resource.dlg
     Application resources:
          dialogs


 

Linkbar