Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 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 "quakedef.h"
     25 
     26 extern	HWND	mainwindow;
     27 extern	cvar_t	bgmvolume;
     28 
     29 static qboolean cdValid = false;
     30 static qboolean	playing = false;
     31 static qboolean	wasPlaying = false;
     32 static qboolean	initialized = false;
     33 static qboolean	enabled = false;
     34 static qboolean playLooping = false;
     35 static float	cdvolume;
     36 static byte 	remap[100];
     37 static byte		cdrom;
     38 static byte		playTrack;
     39 static byte		maxTrack;
     40 
     41 UINT	wDeviceID;
     42 
     43 
     44 static void CDAudio_Eject(void)
     45 {
     46 	DWORD	dwReturn;
     47 
     48     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
     49 		Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
     50 }
     51 
     52 
     53 static void CDAudio_CloseDoor(void)
     54 {
     55 	DWORD	dwReturn;
     56 
     57     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
     58 		Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
     59 }
     60 
     61 
     62 static int CDAudio_GetAudioDiskInfo(void)
     63 {
     64 	DWORD				dwReturn;
     65 	MCI_STATUS_PARMS	mciStatusParms;
     66 
     67 
     68 	cdValid = false;
     69 
     70 	mciStatusParms.dwItem = MCI_STATUS_READY;
     71     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
     72 	if (dwReturn)
     73 	{
     74 		Con_DPrintf("CDAudio: drive ready test - get status failed\n");
     75 		return -1;
     76 	}
     77 	if (!mciStatusParms.dwReturn)
     78 	{
     79 		Con_DPrintf("CDAudio: drive not ready\n");
     80 		return -1;
     81 	}
     82 
     83 	mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
     84     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
     85 	if (dwReturn)
     86 	{
     87 		Con_DPrintf("CDAudio: get tracks - status failed\n");
     88 		return -1;
     89 	}
     90 	if (mciStatusParms.dwReturn < 1)
     91 	{
     92 		Con_DPrintf("CDAudio: no music tracks\n");
     93 		return -1;
     94 	}
     95 
     96 	cdValid = true;
     97 	maxTrack = mciStatusParms.dwReturn;
     98 
     99 	return 0;
    100 }
    101 
    102 
    103 void CDAudio_Play(byte track, qboolean looping)
    104 {
    105 	DWORD				dwReturn;
    106     MCI_PLAY_PARMS		mciPlayParms;
    107 	MCI_STATUS_PARMS	mciStatusParms;
    108 
    109 	if (!enabled)
    110 		return;
    111 
    112 	if (!cdValid)
    113 	{
    114 		CDAudio_GetAudioDiskInfo();
    115 		if (!cdValid)
    116 			return;
    117 	}
    118 
    119 	track = remap[track];
    120 
    121 	if (track < 1 || track > maxTrack)
    122 	{
    123 		Con_DPrintf("CDAudio: Bad track number %u.\n", track);
    124 		return;
    125 	}
    126 
    127 	// don't try to play a non-audio track
    128 	mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
    129 	mciStatusParms.dwTrack = track;
    130     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
    131 	if (dwReturn)
    132 	{
    133 		Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
    134 		return;
    135 	}
    136 	if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
    137 	{
    138 		Con_Printf("CDAudio: track %i is not audio\n", track);
    139 		return;
    140 	}
    141 
    142 	// get the length of the track to be played
    143 	mciStatusParms.dwItem = MCI_STATUS_LENGTH;
    144 	mciStatusParms.dwTrack = track;
    145     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
    146 	if (dwReturn)
    147 	{
    148 		Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
    149 		return;
    150 	}
    151 
    152 	if (playing)
    153 	{
    154 		if (playTrack == track)
    155 			return;
    156 		CDAudio_Stop();
    157 	}
    158 
    159     mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
    160 	mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
    161     mciPlayParms.dwCallback = (DWORD)mainwindow;
    162     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
    163 	if (dwReturn)
    164 	{
    165 		Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
    166 		return;
    167 	}
    168 
    169 	playLooping = looping;
    170 	playTrack = track;
    171 	playing = true;
    172 
    173 	if (cdvolume == 0.0)
    174 		CDAudio_Pause ();
    175 }
    176 
    177 
    178 void CDAudio_Stop(void)
    179 {
    180 	DWORD	dwReturn;
    181 
    182 	if (!enabled)
    183 		return;
    184 
    185 	if (!playing)
    186 		return;
    187 
    188     if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
    189 		Con_DPrintf("MCI_STOP failed (%i)", dwReturn);
    190 
    191 	wasPlaying = false;
    192 	playing = false;
    193 }
    194 
    195 
    196 void CDAudio_Pause(void)
    197 {
    198 	DWORD				dwReturn;
    199 	MCI_GENERIC_PARMS	mciGenericParms;
    200 
    201 	if (!enabled)
    202 		return;
    203 
    204 	if (!playing)
    205 		return;
    206 
    207 	mciGenericParms.dwCallback = (DWORD)mainwindow;
    208     if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
    209 		Con_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
    210 
    211 	wasPlaying = playing;
    212 	playing = false;
    213 }
    214 
    215 
    216 void CDAudio_Resume(void)
    217 {
    218 	DWORD			dwReturn;
    219     MCI_PLAY_PARMS	mciPlayParms;
    220 
    221 	if (!enabled)
    222 		return;
    223 
    224 	if (!cdValid)
    225 		return;
    226 
    227 	if (!wasPlaying)
    228 		return;
    229 
    230     mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
    231     mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
    232     mciPlayParms.dwCallback = (DWORD)mainwindow;
    233     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
    234 	if (dwReturn)
    235 	{
    236 		Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
    237 		return;
    238 	}
    239 	playing = true;
    240 }
    241 
    242 
    243 static void CD_f (void)
    244 {
    245 	char	*command;
    246 	int		ret;
    247 	int		n;
    248 	int		startAddress;
    249 
    250 	if (Cmd_Argc() < 2)
    251 		return;
    252 
    253 	command = Cmd_Argv (1);
    254 
    255 	if (Q_strcasecmp(command, "on") == 0)
    256 	{
    257 		enabled = true;
    258 		return;
    259 	}
    260 
    261 	if (Q_strcasecmp(command, "off") == 0)
    262 	{
    263 		if (playing)
    264 			CDAudio_Stop();
    265 		enabled = false;
    266 		return;
    267 	}
    268 
    269 	if (Q_strcasecmp(command, "reset") == 0)
    270 	{
    271 		enabled = true;
    272 		if (playing)
    273 			CDAudio_Stop();
    274 		for (n = 0; n < 100; n++)
    275 			remap[n] = n;
    276 		CDAudio_GetAudioDiskInfo();
    277 		return;
    278 	}
    279 
    280 	if (Q_strcasecmp(command, "remap") == 0)
    281 	{
    282 		ret = Cmd_Argc() - 2;
    283 		if (ret <= 0)
    284 		{
    285 			for (n = 1; n < 100; n++)
    286 				if (remap[n] != n)
    287 					Con_Printf("  %u -> %u\n", n, remap[n]);
    288 			return;
    289 		}
    290 		for (n = 1; n <= ret; n++)
    291 			remap[n] = Q_atoi(Cmd_Argv (n+1));
    292 		return;
    293 	}
    294 
    295 	if (Q_strcasecmp(command, "close") == 0)
    296 	{
    297 		CDAudio_CloseDoor();
    298 		return;
    299 	}
    300 
    301 	if (!cdValid)
    302 	{
    303 		CDAudio_GetAudioDiskInfo();
    304 		if (!cdValid)
    305 		{
    306 			Con_Printf("No CD in player.\n");
    307 			return;
    308 		}
    309 	}
    310 
    311 	if (Q_strcasecmp(command, "play") == 0)
    312 	{
    313 		CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), false);
    314 		return;
    315 	}
    316 
    317 	if (Q_strcasecmp(command, "loop") == 0)
    318 	{
    319 		CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), true);
    320 		return;
    321 	}
    322 
    323 	if (Q_strcasecmp(command, "stop") == 0)
    324 	{
    325 		CDAudio_Stop();
    326 		return;
    327 	}
    328 
    329 	if (Q_strcasecmp(command, "pause") == 0)
    330 	{
    331 		CDAudio_Pause();
    332 		return;
    333 	}
    334 
    335 	if (Q_strcasecmp(command, "resume") == 0)
    336 	{
    337 		CDAudio_Resume();
    338 		return;
    339 	}
    340 
    341 	if (Q_strcasecmp(command, "eject") == 0)
    342 	{
    343 		if (playing)
    344 			CDAudio_Stop();
    345 		CDAudio_Eject();
    346 		cdValid = false;
    347 		return;
    348 	}
    349 
    350 	if (Q_strcasecmp(command, "info") == 0)
    351 	{
    352 		Con_Printf("%u tracks\n", maxTrack);
    353 		if (playing)
    354 			Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
    355 		else if (wasPlaying)
    356 			Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
    357 		Con_Printf("Volume is %f\n", cdvolume);
    358 		return;
    359 	}
    360 }
    361 
    362 
    363 LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    364 {
    365 	if (lParam != wDeviceID)
    366 		return 1;
    367 
    368 	switch (wParam)
    369 	{
    370 		case MCI_NOTIFY_SUCCESSFUL:
    371 			if (playing)
    372 			{
    373 				playing = false;
    374 				if (playLooping)
    375 					CDAudio_Play(playTrack, true);
    376 			}
    377 			break;
    378 
    379 		case MCI_NOTIFY_ABORTED:
    380 		case MCI_NOTIFY_SUPERSEDED:
    381 			break;
    382 
    383 		case MCI_NOTIFY_FAILURE:
    384 			Con_DPrintf("MCI_NOTIFY_FAILURE\n");
    385 			CDAudio_Stop ();
    386 			cdValid = false;
    387 			break;
    388 
    389 		default:
    390 			Con_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
    391 			return 1;
    392 	}
    393 
    394 	return 0;
    395 }
    396 
    397 
    398 void CDAudio_Update(void)
    399 {
    400 	if (!enabled)
    401 		return;
    402 
    403 	if (bgmvolume.value != cdvolume)
    404 	{
    405 		if (cdvolume)
    406 		{
    407 			Cvar_SetValue ("bgmvolume", 0.0);
    408 			cdvolume = bgmvolume.value;
    409 			CDAudio_Pause ();
    410 		}
    411 		else
    412 		{
    413 			Cvar_SetValue ("bgmvolume", 1.0);
    414 			cdvolume = bgmvolume.value;
    415 			CDAudio_Resume ();
    416 		}
    417 	}
    418 }
    419 
    420 
    421 int CDAudio_Init(void)
    422 {
    423 	DWORD	dwReturn;
    424 	MCI_OPEN_PARMS	mciOpenParms;
    425     MCI_SET_PARMS	mciSetParms;
    426 	int				n;
    427 
    428 	if (cls.state == ca_dedicated)
    429 		return -1;
    430 
    431 	if (COM_CheckParm("-nocdaudio"))
    432 		return -1;
    433 
    434 	mciOpenParms.lpstrDeviceType = "cdaudio";
    435 	if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
    436 	{
    437 		Con_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
    438 		return -1;
    439 	}
    440 	wDeviceID = mciOpenParms.wDeviceID;
    441 
    442     // Set the time format to track/minute/second/frame (TMSF).
    443     mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
    444     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
    445     {
    446 		Con_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
    447         mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
    448 		return -1;
    449     }
    450 
    451 	for (n = 0; n < 100; n++)
    452 		remap[n] = n;
    453 	initialized = true;
    454 	enabled = true;
    455 
    456 	if (CDAudio_GetAudioDiskInfo())
    457 	{
    458 		Con_Printf("CDAudio_Init: No CD in player.\n");
    459 		cdValid = false;
    460 	}
    461 
    462 	Cmd_AddCommand ("cd", CD_f);
    463 
    464 	Con_Printf("CD Audio Initialized\n");
    465 
    466 	return 0;
    467 }
    468 
    469 
    470 void CDAudio_Shutdown(void)
    471 {
    472 	if (!initialized)
    473 		return;
    474 	CDAudio_Stop();
    475 	if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
    476 		Con_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
    477 }
    478