2c6674835d05db4939bd3f4837917ce951985d43
[btb/d2x.git] / main / songs.c
1 /* $Id: songs.c,v 1.11 2004-04-14 07:35:55 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to manage the songs in Descent.
18  *
19  * Old Log:
20  * Revision 1.5  1995/11/03  12:52:59  allender
21  * shareware changes
22  *
23  * Revision 1.4  1995/10/18  01:51:33  allender
24  * fixed up stuff for redbook
25  *
26  * Revision 1.3  1995/10/17  13:13:44  allender
27  * dont' add resource value to songs to play -- now done in digi
28  * code
29  *
30  * Revision 1.2  1995/07/17  08:50:35  allender
31  * make work with new music system
32  *
33  * Revision 1.1  1995/05/16  15:31:05  allender
34  * Initial revision
35  *
36  * Revision 2.1  1995/05/02  16:15:21  john
37  * Took out printf.
38  *
39  * Revision 2.0  1995/02/27  11:27:13  john
40  * New version 2.0, which has no anonymous unions, builds with
41  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
42  *
43  * Revision 1.2  1995/02/11  12:42:12  john
44  * Added new song method, with FM bank switching..
45  *
46  * Revision 1.1  1995/02/11  10:20:33  john
47  * Initial revision
48  *
49  *
50  */
51
52
53 #ifdef HAVE_CONFIG_H
54 #include <conf.h>
55 #endif
56
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <ctype.h>
61 #ifndef _MSC_VER
62 #include <unistd.h>
63 #endif
64
65 #include "inferno.h"
66 #include "error.h"
67 #include "pstypes.h"
68 #include "args.h"
69 #include "songs.h"
70 #include "mono.h"
71 #include "cfile.h"
72 #include "digi.h"
73 #include "rbaudio.h"
74 #include "kconfig.h"
75 #include "timer.h"
76
77 song_info Songs[MAX_NUM_SONGS];
78 int Songs_initialized = 0;
79
80 #ifndef MACINTOSH
81 int Num_songs;
82 #endif
83
84 extern void digi_stop_current_song();
85
86 int Redbook_enabled = 1;
87
88 //0 if redbook is no playing, else the track number
89 int Redbook_playing = 0;
90
91 #define NumLevelSongs (Num_songs - SONG_FIRST_LEVEL_SONG)
92
93 extern int CD_blast_mixer();
94
95 #ifndef MACINTOSH
96 #define REDBOOK_VOLUME_SCALE  (255/3)           //255 is MAX
97 #else
98 #define REDBOOK_VOLUME_SCALE    (255)
99 #endif
100
101 //takes volume in range 0..8
102 void set_redbook_volume(int volume)
103 {
104         #ifndef MACINTOSH
105         RBASetVolume(0);                // makes the macs sound really funny
106         #endif
107         RBASetVolume(volume*REDBOOK_VOLUME_SCALE/8);
108 }
109
110 extern char CDROM_dir[];
111
112 void songs_init()
113 {
114         int i;
115         char inputline[80+1];
116         CFILE * fp;
117
118         if ( Songs_initialized ) return;
119
120
121         #if !defined(MACINTOSH) && !defined(WINDOWS)    // don't crank it if on a macintosh!!!!!
122                 if (!FindArg("-nomixer"))
123                         CD_blast_mixer();   // Crank it!
124         #endif
125
126
127         if (cfexist("descent.sng")) {   // mac (demo?) datafiles don't have the .sng file
128                 fp = cfopen( "descent.sng", "rb" );
129                 if ( fp == NULL )
130                 {
131                         Error( "Couldn't open descent.sng" );
132                 }
133                 i = 0;
134                 while (cfgets(inputline, 80, fp ))
135                 {
136                         char *p = strchr(inputline,'\n');
137                         if (p) *p = '\0';
138                         if ( strlen( inputline ) )
139                         {
140                                 Assert( i < MAX_NUM_SONGS );
141                                 sscanf( inputline, "%s %s %s",
142                                                 Songs[i].filename,
143                                                 Songs[i].melodic_bank_file,
144                                                 Songs[i].drum_bank_file );
145                                 //printf( "%d. '%s' '%s' '%s'\n",i,Songs[i].filename,Songs[i].melodic_bank_file,Songs[i].drum_bank_file );
146                                 i++;
147                         }
148                 }
149                 Num_songs = i;
150                 if (Num_songs <= SONG_FIRST_LEVEL_SONG)
151                         Error("Must have at least %d songs",SONG_FIRST_LEVEL_SONG+1);
152                 cfclose(fp);
153         }
154
155         Songs_initialized = 1;
156
157         //      RBA Hook
158         #if !defined(SHAREWARE) || ( defined(SHAREWARE) && defined(APPLE_DEMO) )
159                 if (FindArg("-noredbook"))
160                 {
161                         Redbook_enabled = 0;
162                 }
163                 else    // use redbook
164                 {
165                         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
166                                 RBAInit();
167                         #else
168                                 RBAInit(toupper(CDROM_dir[0]) - 'A');
169                         #endif
170
171                                 if (RBAEnabled())
172                         {
173                                 set_redbook_volume(Config_redbook_volume);
174                                 RBARegisterCD();
175                         }
176                 }
177                 atexit(RBAStop);    // stop song on exit
178         #endif  // endof ifndef SHAREWARE, ie ifdef SHAREWARE
179 }
180
181 #define FADE_TIME (f1_0/2)
182
183 //stop the redbook, so we can read off the CD
184 void songs_stop_redbook(void)
185 {
186         int old_volume = Config_redbook_volume*REDBOOK_VOLUME_SCALE/8;
187         fix old_time = timer_get_fixed_seconds();
188
189         if (Redbook_playing) {          //fade out volume
190                 int new_volume;
191                 do {
192                         fix t = timer_get_fixed_seconds();
193
194                         new_volume = fixmuldiv(old_volume,(FADE_TIME - (t-old_time)),FADE_TIME);
195
196                         if (new_volume < 0)
197                                 new_volume = 0;
198
199                         RBASetVolume(new_volume);
200
201                 } while (new_volume > 0);
202         }
203
204         RBAStop();                      // Stop CD, if playing
205
206         RBASetVolume(old_volume);       //restore volume
207
208         Redbook_playing = 0;            
209
210 }
211
212 //stop any songs - midi or redbook - that are currently playing
213 void songs_stop_all(void)
214 {
215         digi_stop_current_song();       // Stop midi song, if playing
216
217         songs_stop_redbook();                   // Stop CD, if playing
218 }
219
220 int force_rb_register=0;
221
222 void reinit_redbook()
223 {
224         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
225                 RBAInit();
226         #else
227                 RBAInit(toupper(CDROM_dir[0]) - 'A');
228         #endif
229
230         if (RBAEnabled())
231         {
232                 set_redbook_volume(Config_redbook_volume);
233                 RBARegisterCD();
234                 force_rb_register=0;
235         }
236 }
237
238
239 //returns 1 if track started sucessfully
240 //start at tracknum.  if keep_playing set, play to end of disc.  else
241 //play only specified track
242 int play_redbook_track(int tracknum,int keep_playing)
243 {
244         Redbook_playing = 0;
245
246         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
247                 reinit_redbook();
248
249         if (force_rb_register) {
250                 RBARegisterCD();                        //get new track list for new CD
251                 force_rb_register = 0;
252         }
253
254         if (Redbook_enabled && RBAEnabled()) {
255                 int num_tracks = RBAGetNumberOfTracks();
256                 if (tracknum <= num_tracks)
257                         if (RBAPlayTracks(tracknum,keep_playing?num_tracks:tracknum))  {
258                                 Redbook_playing = tracknum;
259                         }
260         }
261
262         return (Redbook_playing != 0);
263 }
264
265 /*
266  * Some of these have different Track listings!
267  * Which one is the "correct" order?
268  */
269 #define D2_1_DISCID         0x7d0ff809 // Descent II
270 #define D2_2_DISCID         0xe010a30e // Descent II
271 #define D2_3_DISCID         0xd410070d // Descent II
272 #define D2_4_DISCID         0xc610080d // Descent II
273 #define D2_DEF_DISCID       0x87102209 // Definitive collection Disc 2
274 #define D2_OEM_DISCID       0xac0bc30d // Destination: Quartzon
275 #define D2_OEM2_DISCID      0xc40c0a0d // Destination: Quartzon
276 #define D2_VERTIGO_DISCID   0x53078208 // Vertigo
277 #define D2_VERTIGO2_DISCID  0x64071408 // Vertigo + DMB
278 #define D2_MAC_DISCID       0xb70ee40e // Macintosh
279 #define D2_IPLAY_DISCID     0x22115710 // iPlay for Macintosh
280
281 #define REDBOOK_TITLE_TRACK         2
282 #define REDBOOK_CREDITS_TRACK       3
283 #define REDBOOK_FIRST_LEVEL_TRACK   (songs_haved2_cd()?4:1)
284
285 // songs_haved2_cd returns 1 if the descent 2 CD is in the drive and
286 // 0 otherwise
287
288 #if 1
289 int songs_haved2_cd()
290 {
291         int discid;
292
293         if (!Redbook_enabled)
294                 return 0;
295
296         discid = RBAGetDiscID();
297
298         switch (discid) {
299         case D2_1_DISCID:
300         case D2_2_DISCID:
301         case D2_3_DISCID:
302         case D2_4_DISCID:
303         case D2_DEF_DISCID:
304         case D2_OEM_DISCID:
305         case D2_OEM2_DISCID:
306         case D2_VERTIGO_DISCID:
307         case D2_VERTIGO2_DISCID:
308         case D2_MAC_DISCID:
309         case D2_IPLAY_DISCID:
310                 printf("Found D2 CD! discid: %x\n", discid);
311                 return 1;
312         default:
313                 printf("Unknown CD! discid: %x\n", discid);
314                 return 0;
315         }
316 }
317 #else
318 int songs_haved2_cd()
319 {
320         char temp[128],cwd[128];
321         
322         getcwd(cwd, 128);
323
324         strcpy(temp,CDROM_dir);
325
326         #ifndef MACINTOSH               //for PC, strip of trailing slash
327         if (temp[strlen(temp)-1] == '\\')
328                 temp[strlen(temp)-1] = 0;
329         #endif
330
331         if ( !chdir(temp) ) {
332                 chdir(cwd);
333                 return 1;
334         }
335
336         return 0;
337 }
338 #endif
339
340
341 void songs_play_song( int songnum, int repeat )
342 {
343         #ifndef SHAREWARE
344         //Assert(songnum != SONG_ENDLEVEL && songnum != SONG_ENDGAME);  //not in full version
345         #endif
346
347         if ( !Songs_initialized )
348                 songs_init();
349
350         //stop any music already playing
351
352         songs_stop_all();
353
354         //do we want any of these to be redbook songs?
355
356         if (force_rb_register) {
357                 RBARegisterCD();                        //get new track list for new CD
358                 force_rb_register = 0;
359         }
360
361         if (songnum == SONG_TITLE)
362                 play_redbook_track(REDBOOK_TITLE_TRACK,0);
363         else if (songnum == SONG_CREDITS)
364                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
365
366         if (!Redbook_playing) {         //not playing redbook, so play midi
367
368                 #ifndef MACINTOSH
369                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, repeat );
370                 #else
371                         digi_play_midi_song(songnum, repeat);
372                 #endif
373         }
374 }
375
376 int current_song_level;
377
378 void songs_play_level_song( int levelnum )
379 {
380         int songnum;
381         int n_tracks;
382
383         Assert( levelnum != 0 );
384
385         if ( !Songs_initialized )
386                 songs_init();
387
388         songs_stop_all();
389
390         current_song_level = levelnum;
391
392         songnum = (levelnum>0)?(levelnum-1):(-levelnum);
393
394         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
395                 reinit_redbook();
396
397         if (force_rb_register) {
398                 RBARegisterCD();                        //get new track list for new CD
399                 force_rb_register = 0;
400         }
401
402         if (Redbook_enabled && RBAEnabled() && (n_tracks = RBAGetNumberOfTracks()) > 1) {
403
404                 //try to play redbook
405
406                 mprintf((0,"n_tracks = %d\n",n_tracks));
407
408                 play_redbook_track(REDBOOK_FIRST_LEVEL_TRACK + (songnum % (n_tracks-REDBOOK_FIRST_LEVEL_TRACK+1)),1);
409         }
410
411         if (! Redbook_playing) {                        //not playing redbook, so play midi
412
413                 songnum = SONG_FIRST_LEVEL_SONG + (songnum % NumLevelSongs);
414
415                 #ifndef MACINTOSH
416                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, 1 );
417                 #else
418                         digi_play_midi_song( songnum, 1 );
419                 #endif
420
421         }
422 }
423
424 //this should be called regularly to check for redbook restart
425 void songs_check_redbook_repeat()
426 {
427         static fix last_check_time;
428         fix current_time;
429
430         if (!Redbook_playing || Config_redbook_volume==0) return;
431
432         current_time = timer_get_fixed_seconds();
433         if (current_time < last_check_time || (current_time - last_check_time) >= F2_0) {
434                 if (!RBAPeekPlayStatus()) {
435                         stop_time();
436                         // if title ends, start credit music
437                         // if credits music ends, restart it
438                         if (Redbook_playing == REDBOOK_TITLE_TRACK || Redbook_playing == REDBOOK_CREDITS_TRACK)
439                                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
440                         else {
441                                 //songs_goto_next_song();
442         
443                                 //new code plays all tracks to end of disk, so if disk has
444                                 //stopped we must be at end.  So start again with level 1 song.
445         
446                                 songs_play_level_song(1);
447                         }
448                         start_time();
449                 }
450                 last_check_time = current_time;
451         }
452 }
453
454 //goto the next level song
455 void songs_goto_next_song()
456 {
457         if (Redbook_playing)            //get correct track
458                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
459
460         songs_play_level_song(current_song_level+1);
461
462 }
463
464 //goto the previous level song
465 void songs_goto_prev_song()
466 {
467         if (Redbook_playing)            //get correct track
468                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
469
470         if (current_song_level > 1)
471                 songs_play_level_song(current_song_level-1);
472
473 }
474