Playing Audio CDs, part 4 - MCI Playback.

The other day, I wrote about dumping the track database on an audio using the MCI string command set.
Today, I'll include the piece I left out of the last article, actually playing a track from the CD.
HRESULT CMCIStringCDPlayer::PlayTrack(int TrackNumber)<br>{<br>    MCIERROR mciError;<br>    TCHAR mciReturnBuffer[512];<br>    TCHAR mciCommandBuffer[512];<br>    if (TrackNumber > _TrackCount)<br>    {<br>        printf("Track out of range\n");<br>        return E_FAIL;<br>    }<br>    // Set the MCI time format to track/minute/second/frame.<br>    mciError = mciSendString("open cdaudio", mciReturnBuffer, sizeof(mciReturnBuffer), NULL);<br>    if (mciError != 0)<br>    {<br>        printf("MCI Error %x opening CDRom\n",mciError);<br>        return HRESULT_FROM_WIN32(mciError);<br>    }<br>    // Set the MCI time format to track/minute/second/frame.<br>    mciError = mciSendString("set cdaudio time format tmsf", mciReturnBuffer, sizeof(mciReturnBuffer), NULL);<br>    if (mciError != 0)<br>    {<br>        printf("MCI Error %x setting time format\n",mciError);<br>        return HRESULT_FROM_WIN32(mciError);<br>    }<br>    sprintf(mciCommandBuffer, "play cdaudio from %d to %d", TrackNumber, TrackNumber+1);<br>    mciError = mciSendString(mciCommandBuffer, mciReturnBuffer, sizeof(mciReturnBuffer), NULL);<br>    if (mciError != 0)<br>    {<br>        printf("MCI Error %x playing audio\n",mciError);<br>        return HRESULT_FROM_WIN32(mciError);<br>    }<br>    Sleep(_TrackTimes[TrackNumber]);<br>    // Close the CD <br>    mciError = mciSendString("close cdaudio", mciReturnBuffer, sizeof(mciReturnBuffer), NULL);<br>    if (mciError != 0)<br>    {<br>        printf("MCI Error %x closing CDRom\n",mciError);<br>        return HRESULT_FROM_WIN32(mciError);<br>    }<br>    return S_OK;<br>}
There are a couple of things to notice about the code.  The first thing that's done is to open the CDAudio device.  We do that to be able to set the audio time format to tmsf (track/minute/second/frame).  The default audio time format appears to be frame based, but it's not easy to tell from the documentation. 
Once I set the cdrom track, it was trivial to have it play the selected track - you just say "play".
This ease of use is why the MCICDA commands are so widely used - playing a track is literally as easy as hitting the buttons on the player.
Next time, a different version of the MCI command set.
Edit: Fixed typo in comment.

Comments

  • Anonymous
    April 25, 2005
    The comment has been removed
  • Anonymous
    April 25, 2005
    Is the Sleep() call after starting CD playback really recommended? Would it be better to call one of the MsgWait type functions?
  • Anonymous
    April 25, 2005
    Actually, I intentionally used Sleep() to indicate that MCI doesn't require a message pump to work.

    On a non console app it would make sense, but MCI's command set doesn't require the pump.
  • Anonymous
    April 25, 2005
    Larry, where did the syntax of those commands come from? Was it some late 80s media standard or something?
  • Anonymous
    April 25, 2005
    Gunroom, I haven't the faintest idea where it came from (and nobody on the team does either :()

    I just know that it is :)
  • Anonymous
    April 26, 2005
    The comment has been removed
  • Anonymous
    April 26, 2005
    Larry, thanks for the info. It is fascinating to me to understand why things are the way they are.