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