1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 26extern HWND mainwindow; 27extern cvar_t bgmvolume; 28 29static qboolean cdValid = false; 30static qboolean playing = false; 31static qboolean wasPlaying = false; 32static qboolean initialized = false; 33static qboolean enabled = false; 34static qboolean playLooping = false; 35static float cdvolume; 36static byte remap[100]; 37static byte cdrom; 38static byte playTrack; 39static byte maxTrack; 40 41UINT wDeviceID; 42 43 44static 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 53static 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 62static 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 103void 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 178void 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 196void 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 216void 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 243static 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 363LONG 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 398void 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 421int 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 470void 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