File: win32\cd_win.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
   21 // rights reserved.
   22 
   23 #include <windows.h>
   24 #include "../client/client.h"
   25 
   26 extern  HWND    cl_hwnd;
   27 
   28 static qboolean cdValid = false;
   29 static qboolean playing = false;
   30 static qboolean wasPlaying = false;
   31 static qboolean initialized = false;
   32 static qboolean enabled = false;
   33 static qboolean playLooping = false;
   34 static byte     remap[100];
   35 static byte             cdrom;
   36 static byte             playTrack;
   37 static byte             maxTrack;
   38 
   39 cvar_t *cd_nocd;
   40 cvar_t *cd_loopcount;
   41 cvar_t *cd_looptrack;
   42 
   43 UINT    wDeviceID;
   44 int             loopcounter;
   45 
   46 
   47 void CDAudio_Pause(void);
   48 
   49 static void CDAudio_Eject(void)
   50 {
   51         DWORD   dwReturn;
   52 
   53     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
   54                 Com_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
   55 }
   56 
   57 
   58 static void CDAudio_CloseDoor(void)
   59 {
   60         DWORD   dwReturn;
   61 
   62     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
   63                 Com_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
   64 }
   65 
   66 
   67 static int CDAudio_GetAudioDiskInfo(void)
   68 {
   69         DWORD                           dwReturn;
   70         MCI_STATUS_PARMS        mciStatusParms;
   71 
   72 
   73         cdValid = false;
   74 
   75         mciStatusParms.dwItem = MCI_STATUS_READY;
   76     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
   77         if (dwReturn)
   78         {
   79                 Com_DPrintf("CDAudio: drive ready test - get status failed\n");
   80                 return -1;
   81         }
   82         if (!mciStatusParms.dwReturn)
   83         {
   84                 Com_DPrintf("CDAudio: drive not ready\n");
   85                 return -1;
   86         }
   87 
   88         mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
   89     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
   90         if (dwReturn)
   91         {
   92                 Com_DPrintf("CDAudio: get tracks - status failed\n");
   93                 return -1;
   94         }
   95         if (mciStatusParms.dwReturn < 1)
   96         {
   97                 Com_DPrintf("CDAudio: no music tracks\n");
   98                 return -1;
   99         }
  100 
  101         cdValid = true;
  102         maxTrack = mciStatusParms.dwReturn;
  103 
  104         return 0;
  105 }
  106 
  107 
  108 
  109 void CDAudio_Play2(int track, qboolean looping)
  110 {
  111         DWORD                           dwReturn;
  112     MCI_PLAY_PARMS              mciPlayParms;
  113         MCI_STATUS_PARMS        mciStatusParms;
  114 
  115         if (!enabled)
  116                 return;
  117         
  118         if (!cdValid)
  119         {
  120                 CDAudio_GetAudioDiskInfo();
  121                 if (!cdValid)
  122                         return;
  123         }
  124 
  125         track = remap[track];
  126 
  127         if (track < 1 || track > maxTrack)
  128         {
  129                 CDAudio_Stop();
  130                 return;
  131         }
  132 
  133         // don't try to play a non-audio track
  134         mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  135         mciStatusParms.dwTrack = track;
  136     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
  137         if (dwReturn)
  138         {
  139                 Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
  140                 return;
  141         }
  142         if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
  143         {
  144                 Com_Printf("CDAudio: track %i is not audio\n", track);
  145                 return;
  146         }
  147 
  148         // get the length of the track to be played
  149         mciStatusParms.dwItem = MCI_STATUS_LENGTH;
  150         mciStatusParms.dwTrack = track;
  151     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
  152         if (dwReturn)
  153         {
  154                 Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
  155                 return;
  156         }
  157 
  158         if (playing)
  159         {
  160                 if (playTrack == track)
  161                         return;
  162                 CDAudio_Stop();
  163         }
  164 
  165     mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
  166         mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
  167     mciPlayParms.dwCallback = (DWORD)cl_hwnd;
  168     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
  169         if (dwReturn)
  170         {
  171                 Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
  172                 return;
  173         }
  174 
  175         playLooping = looping;
  176         playTrack = track;
  177         playing = true;
  178 
  179         if ( Cvar_VariableValue( "cd_nocd" ) )
  180                 CDAudio_Pause ();
  181 }
  182 
  183 
  184 void CDAudio_Play(int track, qboolean looping)
  185 {
  186         // set a loop counter so that this track will change to the
  187         // looptrack later
  188         loopcounter = 0;
  189         CDAudio_Play2(track, looping);
  190 }
  191 
  192 void CDAudio_Stop(void)
  193 {
  194         DWORD   dwReturn;
  195 
  196         if (!enabled)
  197                 return;
  198         
  199         if (!playing)
  200                 return;
  201 
  202     if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
  203                 Com_DPrintf("MCI_STOP failed (%i)", dwReturn);
  204 
  205         wasPlaying = false;
  206         playing = false;
  207 }
  208 
  209 
  210 void CDAudio_Pause(void)
  211 {
  212         DWORD                           dwReturn;
  213         MCI_GENERIC_PARMS       mciGenericParms;
  214 
  215         if (!enabled)
  216                 return;
  217 
  218         if (!playing)
  219                 return;
  220 
  221         mciGenericParms.dwCallback = (DWORD)cl_hwnd;
  222     if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
  223                 Com_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
  224 
  225         wasPlaying = playing;
  226         playing = false;
  227 }
  228 
  229 
  230 void CDAudio_Resume(void)
  231 {
  232         DWORD                   dwReturn;
  233     MCI_PLAY_PARMS      mciPlayParms;
  234 
  235         if (!enabled)
  236                 return;
  237         
  238         if (!cdValid)
  239                 return;
  240 
  241         if (!wasPlaying)
  242                 return;
  243         
  244     mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
  245     mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
  246     mciPlayParms.dwCallback = (DWORD)cl_hwnd;
  247     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
  248         if (dwReturn)
  249         {
  250                 Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
  251                 return;
  252         }
  253         playing = true;
  254 }
  255 
  256 
  257 static void CD_f (void)
  258 {
  259         char    *command;
  260         int             ret;
  261         int             n;
  262 
  263         if (Cmd_Argc() < 2)
  264                 return;
  265 
  266         command = Cmd_Argv (1);
  267 
  268         if (Q_strcasecmp(command, "on") == 0)
  269         {
  270                 enabled = true;
  271                 return;
  272         }
  273 
  274         if (Q_strcasecmp(command, "off") == 0)
  275         {
  276                 if (playing)
  277                         CDAudio_Stop();
  278                 enabled = false;
  279                 return;
  280         }
  281 
  282         if (Q_strcasecmp(command, "reset") == 0)
  283         {
  284                 enabled = true;
  285                 if (playing)
  286                         CDAudio_Stop();
  287                 for (n = 0; n < 100; n++)
  288                         remap[n] = n;
  289                 CDAudio_GetAudioDiskInfo();
  290                 return;
  291         }
  292 
  293         if (Q_strcasecmp(command, "remap") == 0)
  294         {
  295                 ret = Cmd_Argc() - 2;
  296                 if (ret <= 0)
  297                 {
  298                         for (n = 1; n < 100; n++)
  299                                 if (remap[n] != n)
  300                                         Com_Printf("  %u -> %u\n", n, remap[n]);
  301                         return;
  302                 }
  303                 for (n = 1; n <= ret; n++)
  304                         remap[n] = atoi(Cmd_Argv (n+1));
  305                 return;
  306         }
  307 
  308         if (Q_strcasecmp(command, "close") == 0)
  309         {
  310                 CDAudio_CloseDoor();
  311                 return;
  312         }
  313 
  314         if (!cdValid)
  315         {
  316                 CDAudio_GetAudioDiskInfo();
  317                 if (!cdValid)
  318                 {
  319                         Com_Printf("No CD in player.\n");
  320                         return;
  321                 }
  322         }
  323 
  324         if (Q_strcasecmp(command, "play") == 0)
  325         {
  326                 CDAudio_Play(atoi(Cmd_Argv (2)), false);
  327                 return;
  328         }
  329 
  330         if (Q_strcasecmp(command, "loop") == 0)
  331         {
  332                 CDAudio_Play(atoi(Cmd_Argv (2)), true);
  333                 return;
  334         }
  335 
  336         if (Q_strcasecmp(command, "stop") == 0)
  337         {
  338                 CDAudio_Stop();
  339                 return;
  340         }
  341 
  342         if (Q_strcasecmp(command, "pause") == 0)
  343         {
  344                 CDAudio_Pause();
  345                 return;
  346         }
  347 
  348         if (Q_strcasecmp(command, "resume") == 0)
  349         {
  350                 CDAudio_Resume();
  351                 return;
  352         }
  353 
  354         if (Q_strcasecmp(command, "eject") == 0)
  355         {
  356                 if (playing)
  357                         CDAudio_Stop();
  358                 CDAudio_Eject();
  359                 cdValid = false;
  360                 return;
  361         }
  362 
  363         if (Q_strcasecmp(command, "info") == 0)
  364         {
  365                 Com_Printf("%u tracks\n", maxTrack);
  366                 if (playing)
  367                         Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
  368                 else if (wasPlaying)
  369                         Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
  370                 return;
  371         }
  372 }
  373 
  374 
  375 LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  376 {
  377         if (lParam != wDeviceID)
  378                 return 1;
  379 
  380         switch (wParam)
  381         {
  382                 case MCI_NOTIFY_SUCCESSFUL:
  383                         if (playing)
  384                         {
  385                                 playing = false;
  386                                 if (playLooping)
  387                                 {
  388                                         // if the track has played the given number of times,
  389                                         // go to the ambient track
  390                                         if (++loopcounter >= cd_loopcount->value)
  391                                                 CDAudio_Play2(cd_looptrack->value, true);
  392                                         else
  393                                                 CDAudio_Play2(playTrack, true);
  394                                 }
  395                         }
  396                         break;
  397 
  398                 case MCI_NOTIFY_ABORTED:
  399                 case MCI_NOTIFY_SUPERSEDED:
  400                         break;
  401 
  402                 case MCI_NOTIFY_FAILURE:
  403                         Com_DPrintf("MCI_NOTIFY_FAILURE\n");
  404                         CDAudio_Stop ();
  405                         cdValid = false;
  406                         break;
  407 
  408                 default:
  409                         Com_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
  410                         return 1;
  411         }
  412 
  413         return 0;
  414 }
  415 
  416 
  417 void CDAudio_Update(void)
  418 {
  419         if ( cd_nocd->value != !enabled )
  420         {
  421                 if ( cd_nocd->value )
  422                 {
  423                         CDAudio_Stop();
  424                         enabled = false;
  425                 }
  426                 else
  427                 {
  428                         enabled = true;
  429                         CDAudio_Resume ();
  430                 }
  431         }
  432 }
  433 
  434 
  435 int CDAudio_Init(void)
  436 {
  437         DWORD   dwReturn;
  438         MCI_OPEN_PARMS  mciOpenParms;
  439     MCI_SET_PARMS       mciSetParms;
  440         int                             n;
  441 
  442         cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
  443         cd_loopcount = Cvar_Get ("cd_loopcount", "4", 0);
  444         cd_looptrack = Cvar_Get ("cd_looptrack", "11", 0);
  445         if ( cd_nocd->value)
  446                 return -1;
  447 
  448         mciOpenParms.lpstrDeviceType = "cdaudio";
  449         if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
  450         {
  451                 Com_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
  452                 return -1;
  453         }
  454         wDeviceID = mciOpenParms.wDeviceID;
  455 
  456     // Set the time format to track/minute/second/frame (TMSF).
  457     mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
  458     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
  459     {
  460                 Com_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
  461         mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
  462                 return -1;
  463     }
  464 
  465         for (n = 0; n < 100; n++)
  466                 remap[n] = n;
  467         initialized = true;
  468         enabled = true;
  469 
  470         if (CDAudio_GetAudioDiskInfo())
  471         {
  472 //              Com_Printf("CDAudio_Init: No CD in player.\n");
  473                 cdValid = false;
  474                 enabled = false;
  475         }
  476 
  477         Cmd_AddCommand ("cd", CD_f);
  478 
  479         Com_Printf("CD Audio Initialized\n");
  480 
  481         return 0;
  482 }
  483 
  484 
  485 void CDAudio_Shutdown(void)
  486 {
  487         if (!initialized)
  488                 return;
  489         CDAudio_Stop();
  490         if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
  491                 Com_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
  492 }
  493 
  494 
  495 /*
  496 ===========
  497 CDAudio_Activate
  498 
  499 Called when the main window gains or loses focus.
  500 The window have been destroyed and recreated
  501 between a deactivate and an activate.
  502 ===========
  503 */
  504 void CDAudio_Activate (qboolean active)
  505 {
  506         if (active)
  507                 CDAudio_Resume ();
  508         else
  509                 CDAudio_Pause ();
  510 }
  511