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