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 
CDAudio_Eject(void)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 
CDAudio_CloseDoor(void)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 
CDAudio_GetAudioDiskInfo(void)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 
CDAudio_Play2(int track,qboolean looping)107 void CDAudio_Play2(int track, qboolean looping)
108 {
109 	DWORD				dwReturn;
110     MCI_PLAY_PARMS		mciPlayParms;
111 	MCI_STATUS_PARMS	mciStatusParms;
112 
113 	if (!enabled)
114 		return;
115 
116 	if (!cdValid)
117 	{
118 		CDAudio_GetAudioDiskInfo();
119 		if (!cdValid)
120 			return;
121 	}
122 
123 	track = remap[track];
124 
125 	if (track < 1 || track > maxTrack)
126 	{
127 		CDAudio_Stop();
128 		return;
129 	}
130 
131 	// don't try to play a non-audio track
132 	mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
133 	mciStatusParms.dwTrack = track;
134     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
135 	if (dwReturn)
136 	{
137 		Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
138 		return;
139 	}
140 	if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
141 	{
142 		Com_Printf("CDAudio: track %i is not audio\n", track);
143 		return;
144 	}
145 
146 	// get the length of the track to be played
147 	mciStatusParms.dwItem = MCI_STATUS_LENGTH;
148 	mciStatusParms.dwTrack = track;
149     dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
150 	if (dwReturn)
151 	{
152 		Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
153 		return;
154 	}
155 
156 	if (playing)
157 	{
158 		if (playTrack == track)
159 			return;
160 		CDAudio_Stop();
161 	}
162 
163     mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
164 	mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
165     mciPlayParms.dwCallback = (DWORD)cl_hwnd;
166     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
167 	if (dwReturn)
168 	{
169 		Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
170 		return;
171 	}
172 
173 	playLooping = looping;
174 	playTrack = track;
175 	playing = true;
176 
177 	if ( Cvar_VariableValue( "cd_nocd" ) )
178 		CDAudio_Pause ();
179 }
180 
181 
CDAudio_Play(int track,qboolean looping)182 void CDAudio_Play(int track, qboolean looping)
183 {
184 	// set a loop counter so that this track will change to the
185 	// looptrack later
186 	loopcounter = 0;
187 	CDAudio_Play2(track, looping);
188 }
189 
CDAudio_RandomPlay(void)190 void CDAudio_RandomPlay(void)
191 {
192   int track, i = 0, free_tracks = 0, remap_track;
193   float f;
194   byte* track_bools;;
195   DWORD				dwReturn;
196   MCI_PLAY_PARMS		mciPlayParms;
197   MCI_STATUS_PARMS	mciStatusParms;
198 
199   if (!enabled)
200     return;
201 
202   //create array of available audio tracknumbers
203 
204   track_bools = (byte*)malloc(maxTrack * sizeof(byte));
205 
206   if (track_bools == 0)
207     return;
208 
209   for (; i < maxTrack; i++)
210     {
211       // don't try to play a non-audio track
212       mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
213       mciStatusParms.dwTrack = remap[i];
214       dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
215       if (dwReturn)
216 	{
217 	  track_bools[i] = 0;
218 	}
219       else
220         track_bools[i] = (mciStatusParms.dwReturn == MCI_CDA_TRACK_AUDIO);
221 
222       free_tracks += track_bools[i];
223     }
224 
225   if (!free_tracks)
226     {
227       Com_DPrintf("CDAudio_RandomPlay: Unable to find and play a random audio track, insert an audio cd please");
228       goto free_end;
229     }
230 
231   //choose random audio track
232   do
233     {
234       do
235 	{
236 	  f = ((float)rand()) / ((float)RAND_MAX + 1.0);
237 	  track = (int)(maxTrack  * f);
238 	}
239       while(!track_bools[track]);
240 
241       remap_track = remap[track];
242 
243       // get the length of the track to be played
244       mciStatusParms.dwItem = MCI_STATUS_LENGTH;
245       mciStatusParms.dwTrack = remap_track;
246       dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
247       if (dwReturn)
248 	{
249 	  Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
250 	  goto free_end;
251 	}
252 
253       if (playing)
254 	{
255 	  if (playTrack == remap_track)
256 	    {
257 	      goto free_end;
258 	    }
259 	  CDAudio_Stop();
260 	}
261 
262       mciPlayParms.dwFrom = MCI_MAKE_TMSF(remap_track, 0, 0, 0);
263       mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | remap_track;
264       mciPlayParms.dwCallback = (DWORD)cl_hwnd;
265       dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
266       if (dwReturn)
267 	{
268 	  track_bools[track] = 0;
269 	  free_tracks--;
270 	}
271       else
272 	{
273 	  playLooping = true;
274 	  playTrack = remap_track;
275 	  playing = true;
276 	  break;
277 	}
278   while (free_tracks > 0);
279 
280 free_end:
281   free((void*)track_bools);
282 }
283 
284 void CDAudio_Stop(void)
285 {
286 	DWORD	dwReturn;
287 
288 	if (!enabled)
289 		return;
290 
291 	if (!playing)
292 		return;
293 
294     if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
295 		Com_DPrintf("MCI_STOP failed (%i)", dwReturn);
296 
297 	wasPlaying = false;
298 	playing = false;
299 }
300 
301 
302 void CDAudio_Pause(void)
303 {
304 	DWORD				dwReturn;
305 	MCI_GENERIC_PARMS	mciGenericParms;
306 
307 	if (!enabled)
308 		return;
309 
310 	if (!playing)
311 		return;
312 
313 	mciGenericParms.dwCallback = (DWORD)cl_hwnd;
314     if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
315 		Com_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
316 
317 	wasPlaying = playing;
318 	playing = false;
319 }
320 
321 
322 void CDAudio_Resume(void)
323 {
324 	DWORD			dwReturn;
325     MCI_PLAY_PARMS	mciPlayParms;
326 
327 	if (!enabled)
328 		return;
329 
330 	if (!cdValid)
331 		return;
332 
333 	if (!wasPlaying)
334 		return;
335 
336     mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
337     mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
338     mciPlayParms.dwCallback = (DWORD)cl_hwnd;
339     dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
340 	if (dwReturn)
341 	{
342 		Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
343 		return;
344 	}
345 	playing = true;
346 }
347 
348 
349 static void CD_f (void)
350 {
351 	char	*command;
352 	int		ret;
353 	int		n;
354 
355 	if (Cmd_Argc() < 2)
356 		return;
357 
358 	command = Cmd_Argv (1);
359 
360 	if (Q_strcasecmp(command, "on") == 0)
361 	{
362 		enabled = true;
363 		return;
364 	}
365 
366 	if (Q_strcasecmp(command, "off") == 0)
367 	{
368 		if (playing)
369 			CDAudio_Stop();
370 		enabled = false;
371 		return;
372 	}
373 
374 	if (Q_strcasecmp(command, "reset") == 0)
375 	{
376 		enabled = true;
377 		if (playing)
378 			CDAudio_Stop();
379 		for (n = 0; n < 100; n++)
380 			remap[n] = n;
381 		CDAudio_GetAudioDiskInfo();
382 		return;
383 	}
384 
385 	if (Q_strcasecmp(command, "remap") == 0)
386 	{
387 		ret = Cmd_Argc() - 2;
388 		if (ret <= 0)
389 		{
390 			for (n = 1; n < 100; n++)
391 				if (remap[n] != n)
392 					Com_Printf("  %u -> %u\n", n, remap[n]);
393 			return;
394 		}
395 		for (n = 1; n <= ret; n++)
396 			remap[n] = atoi(Cmd_Argv (n+1));
397 		return;
398 	}
399 
400 	if (Q_strcasecmp(command, "close") == 0)
401 	{
402 		CDAudio_CloseDoor();
403 		return;
404 	}
405 
406 	if (!cdValid)
407 	{
408 		CDAudio_GetAudioDiskInfo();
409 		if (!cdValid)
410 		{
411 			Com_Printf("No CD in player.\n");
412 			return;
413 		}
414 	}
415 
416 	if (Q_strcasecmp(command, "play") == 0)
417 	{
418 		CDAudio_Play(atoi(Cmd_Argv (2)), false);
419 		return;
420 	}
421 
422 	if (Q_strcasecmp(command, "loop") == 0)
423 	{
424 		CDAudio_Play(atoi(Cmd_Argv (2)), true);
425 		return;
426 	}
427 
428 	if (Q_strcasecmp(command, "stop") == 0)
429 	{
430 		CDAudio_Stop();
431 		return;
432 	}
433 
434 	if (Q_strcasecmp(command, "pause") == 0)
435 	{
436 		CDAudio_Pause();
437 		return;
438 	}
439 
440 	if (Q_strcasecmp(command, "resume") == 0)
441 	{
442 		CDAudio_Resume();
443 		return;
444 	}
445 
446 	if (Q_strcasecmp(command, "eject") == 0)
447 	{
448 		if (playing)
449 			CDAudio_Stop();
450 		CDAudio_Eject();
451 		cdValid = false;
452 		return;
453 	}
454 
455 	if (Q_strcasecmp(command, "info") == 0)
456 	{
457 		Com_Printf("%u tracks\n", maxTrack);
458 		if (playing)
459 			Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
460 		else if (wasPlaying)
461 			Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
462 		return;
463 	}
464 }
465 
466 
467 LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
468 {
469 	if (lParam != wDeviceID)
470 		return 1;
471 
472 	switch (wParam)
473 	{
474 		case MCI_NOTIFY_SUCCESSFUL:
475 			if (playing)
476 			{
477 				playing = false;
478 				if (playLooping)
479 				{
480 					// if the track has played the given number of times,
481 					// go to the ambient track
482 					if (++loopcounter >= cd_loopcount->value)
483 						CDAudio_Play2(cd_looptrack->value, true);
484 					else
485 						CDAudio_Play2(playTrack, true);
486 				}
487 			}
488 			break;
489 
490 		case MCI_NOTIFY_ABORTED:
491 		case MCI_NOTIFY_SUPERSEDED:
492 			break;
493 
494 		case MCI_NOTIFY_FAILURE:
495 			Com_DPrintf("MCI_NOTIFY_FAILURE\n");
496 			CDAudio_Stop ();
497 			cdValid = false;
498 			break;
499 
500 		default:
501 			Com_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
502 			return 1;
503 	}
504 
505 	return 0;
506 }
507 
508 
509 void CDAudio_Update(void)
510 {
511 	if ( cd_nocd->value != !enabled )
512 	{
513 		if ( cd_nocd->value )
514 		{
515 			CDAudio_Stop();
516 			enabled = false;
517 		}
518 		else
519 		{
520 			enabled = true;
521 			CDAudio_Resume ();
522 		}
523 	}
524 }
525 
526 
527 int CDAudio_Init(void)
528 {
529 	DWORD	dwReturn;
530 	MCI_OPEN_PARMS	mciOpenParms;
531     MCI_SET_PARMS	mciSetParms;
532 	int				n;
533 
534 	if (initialized)
535 	  return;
536 
537 	cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
538 	cd_loopcount = Cvar_Get ("cd_loopcount", "4", 0);
539 	cd_looptrack = Cvar_Get ("cd_looptrack", "11", 0);
540 	if ( cd_nocd->value)
541 		return -1;
542 
543 	mciOpenParms.lpstrDeviceType = "cdaudio";
544 	if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
545 	{
546 		Com_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
547 		return -1;
548 	}
549 	wDeviceID = mciOpenParms.wDeviceID;
550 
551     // Set the time format to track/minute/second/frame (TMSF).
552     mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
553     if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
554     {
555 		Com_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
556         mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
557 		return -1;
558     }
559 
560 	for (n = 0; n < 100; n++)
561 		remap[n] = n;
562 	initialized = true;
563 	enabled = true;
564 
565 	if (CDAudio_GetAudioDiskInfo())
566 	{
567 //		Com_Printf("CDAudio_Init: No CD in player.\n");
568 		cdValid = false;
569 		enabled = false;
570 	}
571 
572 	Cmd_AddCommand ("cd", CD_f);
573 
574 	Com_Printf("CD Audio Initialized\n");
575 
576 	return 0;
577 }
578 
579 
580 void CDAudio_Shutdown(void)
581 {
582 	if (!initialized)
583 		return;
584 	CDAudio_Stop();
585 	if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
586 		Com_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
587 	initialized = false;
588 }
589 
590 
591 /*
592 ===========
593 CDAudio_Activate
594 
595 Called when the main window gains or loses focus.
596 The window have been destroyed and recreated
597 between a deactivate and an activate.
598 ===========
599 */
600 void CDAudio_Activate (qboolean active)
601 {
602 	if (active)
603 		CDAudio_Resume ();
604 	else
605 		CDAudio_Pause ();
606 }
607