1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_cdmus.c 1257 2016-09-20 17:14:21Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: i_cdmus.c,v $
20 // Revision 1.2 2000/02/27 00:42:11 hurdler
21 // fix CR+LF problem
22 //
23 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
24 // Initial import into CVS (v1.29 pr3)
25 //
26 //
27 // DESCRIPTION:
28 // cd music interface (uses bcd library)
29 //
30 //-----------------------------------------------------------------------------
31
32 #include "doomincl.h"
33
34 // CD-Audio library by Brennan Underwood
35 #include "bcd.h"
36
37 #include "i_sound.h"
38 #include "command.h"
39 #include "i_system.h"
40 #include "s_sound.h"
41
42 // ------
43 // protos
44 // ------
45 void Command_Cd_f (void);
46
47
48 //======================================================================
49 // CD AUDIO MUSIC SUBSYSTEM
50 //======================================================================
51
52 byte cdaudio_started=0; // for system startup/shutdown
53
54 #define MAX_CD_TRACKS 256
55 static boolean cdPlaying = false;
56 static int cdPlayTrack; // when cdPlaying is true
57 static boolean cdLooping = false;
58 static byte cdRemap[MAX_CD_TRACKS];
59 static boolean cdEnabled=true; // cd info available
60 static boolean cdValid; // true when last cd audio info was ok
61 static boolean wasPlaying;
62 static int cdVolume=0; // current cd volume (0-31)
63
64 // 0-31 like Music & Sfx, though CD hardware volume is 0-255.
65 consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t};
66
67 // allow Update for next/loop track
68 // some crap cd drivers take up to
69 // a second for a simple 'busy' check..
70 // (on those Update can be disabled)
71 consvar_t cdUpdate = {"cd_update","1",CV_SAVE,CV_OnOff};
72
73
74 // hour,minutes,seconds
hms(int hsg)75 static char* hms(int hsg)
76 {
77 int hours, minutes, seconds;
78 static char s[9];
79
80 seconds = hsg / 75;
81 minutes = seconds / 60;
82 seconds %= 60;
83 hours = minutes / 60;
84 minutes %= 60;
85 if (hours>0)
86 sprintf (s, "%d:%02d:%02d", hours, minutes, seconds);
87 else
88 sprintf (s, "%2d:%02d", minutes, seconds);
89 return s;
90 }
91
Command_Cd_f(void)92 void Command_Cd_f (void)
93 {
94 char* s;
95 int i,j;
96
97 if (!cdaudio_started)
98 return;
99
100 if (COM_Argc()<2)
101 {
102 CONS_Printf ("cd [on] [off] [remap] [reset] [open]\n"
103 " [info] [play <track>] [loop <track>]\n"
104 " [stop] [resume]\n");
105 return;
106 }
107
108 s = COM_Argv(1);
109
110 // activate cd music
111 if (!strncmp(s,"on",2))
112 {
113 cdEnabled = true;
114 return;
115 }
116
117 // stop/deactivate cd music
118 if (!strncmp(s,"off",3))
119 {
120 if (cdPlaying)
121 I_StopCD ();
122 cdEnabled = false;
123 return;
124 }
125
126 // remap tracks
127 if (!strncmp(s,"remap",5))
128 {
129 i = COM_Argc() - 2;
130 if (i <= 0)
131 {
132 CONS_Printf ("CD tracks remapped in that order :\n");
133 for (j = 1; j < MAX_CD_TRACKS; j++)
134 if (cdRemap[j] != j)
135 CONS_Printf (" %2d -> %2d\n", j, cdRemap[j]);
136 return;
137 }
138 for (j = 1; j <= i; j++)
139 cdRemap[j] = atoi (COM_Argv (j+1));
140 return;
141 }
142
143 // reset the CD driver, useful on some odd cd's
144 if (!strncmp(s,"reset",5))
145 {
146 cdEnabled = true;
147 if (cdPlaying)
148 I_StopCD ();
149 for (i = 0; i < MAX_CD_TRACKS; i++)
150 cdRemap[i] = i;
151 bcd_reset ();
152 cdValid = bcd_get_audio_info ();
153 return;
154 }
155
156 // any other command is not allowed until we could retrieve cd information
157 if (!cdValid)
158 {
159 CONS_Printf ("CD is not ready.\n");
160 return;
161 }
162
163 if (!strncmp(s,"open",4))
164 {
165 if (cdPlaying)
166 I_StopCD ();
167 bcd_open_door();
168 cdValid = false;
169 return;
170 }
171
172 if (!strncmp(s,"info",4))
173 {
174 int totaltime = 0;
175
176 if (!bcd_get_audio_info())
177 {
178 CONS_Printf ("Error getting audio info: %s\n",bcd_error());
179 cdValid = false;
180 return;
181 }
182
183 cdValid = true;
184
185 if (lowest_track == 0)
186 CONS_Printf ("No audio tracks\n");
187 else
188 {
189 // display list of tracks
190 // highlight current playing track
191 for (i=lowest_track; i <= highest_track; i++)
192 {
193 CONS_Printf ("%s%2d. %s %s\n",
194 cdPlaying && (cdPlayTrack == i) ? "\2 " : " ",
195 i, tracks[i].is_audio ? "audio" : "data ",
196 hms(tracks[i].len));
197 if (tracks[i].is_audio)
198 totaltime += tracks[i].len;
199 }
200
201 if (totaltime)
202 CONS_Printf ("\2Total time : %s\n", hms(totaltime));
203 }
204 if (cdPlaying)
205 {
206 CONS_Printf ("%s track : %d\n", cdLooping ? "looping" : "playing",
207 cdPlayTrack);
208 }
209 return;
210 }
211
212 if (!strncmp(s,"play",4))
213 {
214 I_PlayCD (atoi (COM_Argv (2)), false);
215 return;
216 }
217
218 if (!strncmp(s,"stop",4))
219 {
220 I_StopCD ();
221 return;
222 }
223
224 if (!strncmp(s,"loop",4))
225 {
226 I_PlayCD (atoi (COM_Argv (2)), true);
227 return;
228 }
229
230 if (!strncmp(s,"resume",4))
231 {
232 I_ResumeCD ();
233 return;
234 }
235
236 CONS_Printf ("cd command '%s' unknown\n", s);
237 }
238
239
240 // pause cd music
I_StopCD(void)241 void I_StopCD (void)
242 {
243 if (!cdaudio_started || !cdEnabled)
244 return;
245
246 bcd_stop();
247
248 wasPlaying = cdPlaying;
249 cdPlaying = false;
250 }
251
252 // continue after a pause
I_ResumeCD(void)253 void I_ResumeCD (void)
254 {
255 if (!cdaudio_started || !cdEnabled)
256 return;
257
258 if (!cdValid)
259 return;
260
261 if (!wasPlaying)
262 return;
263
264 bcd_resume ();
265 cdPlaying = true;
266 }
267
268
I_ShutdownCD(void)269 void I_ShutdownCD (void)
270 {
271 int rc;
272
273 if (!cdaudio_started)
274 return;
275
276 I_StopCD ();
277
278 rc = bcd_close ();
279 if (!rc)
280 CONS_Printf ("Error shuting down cd\n");
281 }
282
I_InitCD(void)283 void I_InitCD (void)
284 {
285 int rc;
286 int i;
287
288 rc = bcd_open ();
289
290 if (rc>=0x200)
291 {
292 CONS_Printf ("MSCDEX version %d.%d\n", rc>>8, rc&255);
293
294 I_AddExitFunc (I_ShutdownCD);
295 cdaudio_started = true;
296 }
297 else
298 {
299 if (!rc)
300 CONS_Printf ("%s\n", bcd_error() );
301
302 cdaudio_started = false;
303 return;
304 }
305
306 // last saved in config.cfg
307 i = cd_volume.value;
308 I_SetVolumeCD (0); // initialize to 0 for some odd cd drivers
309 I_SetVolumeCD (i); // now set the last saved volume
310
311 for (i = 0; i < MAX_CD_TRACKS; i++)
312 cdRemap[i] = i;
313
314 if (!bcd_get_audio_info())
315 {
316 CONS_Printf("\2CD Init: No CD in player.\n");
317 cdEnabled = false;
318 cdValid = false;
319 }
320 else
321 {
322 cdEnabled = true;
323 cdValid = true;
324 }
325
326 COM_AddCommand ("cd", Command_Cd_f);
327 }
328
329
330
331 // loop/go to next track when track is finished (if cd_update var is true)
332 // update the volume when it has changed (from console/menu)
333 // TODO: check for cd change and restart music ?
334 //
I_UpdateCD(void)335 void I_UpdateCD (void)
336 {
337 int newVolume;
338 int now;
339 static int last; //game tics (35th of second)
340
341 if (!cdaudio_started)
342 return;
343
344 now = I_GetTime ();
345 if ((now - last) < 10) // about 1/4 second
346 return;
347 last = now;
348
349 // update cd volume changed at console/menu
350 newVolume = cd_volume.value & 31;
351
352 if (cdVolume != newVolume)
353 I_SetVolumeCD (newVolume);
354
355 // slow drivers exit here
356 if (!cdUpdate.value)
357 return;
358
359 if (cdPlaying)
360 {
361 if (!bcd_audio_busy())
362 {
363 cdPlaying = false;
364 if (cdLooping)
365 I_PlayCD (cdPlayTrack, true);
366 else
367 {
368 // play the next cd track, or restart the first
369 cdPlayTrack++;
370 if (cdPlayTrack > highest_track)
371 cdPlayTrack = lowest_track;
372 while (!tracks[cdPlayTrack].is_audio && cdPlayTrack<highest_track)
373 cdPlayTrack++;
374 I_PlayCD (cdPlayTrack, true);
375 }
376 }
377 }
378
379 }
380
381
382 //
I_PlayCD(int track,boolean looping)383 void I_PlayCD (int track, boolean looping)
384 {
385 if (!cdaudio_started || !cdEnabled)
386 return;
387
388 if (!cdValid)
389 return;
390
391 track = cdRemap[track];
392
393 if (cdPlaying)
394 {
395 if (cdPlayTrack == track)
396 return;
397 I_StopCD ();
398 }
399
400 if (track < lowest_track || track > highest_track)
401 {
402 //CONS_Printf ("\2CD Audio: wrong track number %d\n", track);
403 // suppose there are not enough tracks for game levels..
404 // then do a modulo so we always get something to hear
405 track = (track % (highest_track-lowest_track+1)) + 1;
406 //return;
407 }
408
409 cdPlayTrack = track;
410
411 if (!tracks[track].is_audio)
412 {
413 CONS_Printf ("\2CD Play: not an audio track\n");
414 return;
415 }
416
417 cdLooping = looping;
418
419 if (!bcd_play_track (track))
420 {
421 CONS_Printf ("CD Play: could not play track %d\n", track);
422 cdValid = false;
423 cdPlaying = false;
424 return;
425 }
426
427 cdPlaying = true;
428
429 }
430
431
432 // volume : logical cd audio volume 0-31 (hardware is 0-255)
I_SetVolumeCD(int volume)433 int I_SetVolumeCD (int volume)
434 {
435 int hardvol;
436
437 if (!cdaudio_started || !cdEnabled)
438 return 0;
439
440 // translate to hardware volume
441 volume &= 31;
442
443 hardvol = ((volume+1)<<3)-1; //highest volume is 255
444 if (hardvol<=8)
445 hardvol=0; //lowest volume is ZERO
446
447 cdVolume = volume;
448
449 if (bcd_set_volume (hardvol))
450 {
451 CV_SetValue (&cd_volume, volume);
452
453 return 1;
454 }
455 else
456 return 0;
457 }
458