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