]> icculus.org git repositories - btb/d2x.git/blob - main/songs.c
don't fall thru if invalid redbook track requested
[btb/d2x.git] / main / songs.c
1 /* $Id: songs.c,v 1.14 2004-08-29 17:57:23 schaffner 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  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <conf.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #if !defined(_MSC_VER) && !defined(macintosh)
31 #include <unistd.h>
32 #endif
33
34 #include "inferno.h"
35 #include "error.h"
36 #include "pstypes.h"
37 #include "args.h"
38 #include "songs.h"
39 #include "mono.h"
40 #include "cfile.h"
41 #include "digi.h"
42 #include "rbaudio.h"
43 #include "kconfig.h"
44 #include "timer.h"
45
46 song_info Songs[MAX_NUM_SONGS];
47 int Songs_initialized = 0;
48
49 #ifndef MACINTOSH
50 int Num_songs;
51 #endif
52
53 extern void digi_stop_current_song();
54
55 int Redbook_enabled = 1;
56
57 //0 if redbook is no playing, else the track number
58 int Redbook_playing = 0;
59
60 #define NumLevelSongs (Num_songs - SONG_FIRST_LEVEL_SONG)
61
62 extern int CD_blast_mixer();
63
64 #ifndef MACINTOSH
65 #define REDBOOK_VOLUME_SCALE  (255/3)           //255 is MAX
66 #else
67 #define REDBOOK_VOLUME_SCALE    (255)
68 #endif
69
70 //takes volume in range 0..8
71 void set_redbook_volume(int volume)
72 {
73         #ifndef MACINTOSH
74         RBASetVolume(0);                // makes the macs sound really funny
75         #endif
76         RBASetVolume(volume*REDBOOK_VOLUME_SCALE/8);
77 }
78
79 extern char CDROM_dir[];
80
81 void songs_init()
82 {
83         int i;
84         char inputline[80+1];
85         CFILE * fp;
86
87         if ( Songs_initialized ) return;
88
89
90         #if !defined(MACINTOSH) && !defined(WINDOWS)    // don't crank it if on a macintosh!!!!!
91                 if (!FindArg("-nomixer"))
92                         CD_blast_mixer();   // Crank it!
93         #endif
94
95
96         if (cfexist("descent.sng")) {   // mac (demo?) datafiles don't have the .sng file
97                 fp = cfopen( "descent.sng", "rb" );
98                 if ( fp == NULL )
99                 {
100                         Error( "Couldn't open descent.sng" );
101                 }
102                 i = 0;
103                 while (cfgets(inputline, 80, fp ))
104                 {
105                         if ( strlen( inputline ) )
106                         {
107                                 Assert( i < MAX_NUM_SONGS );
108                                 sscanf( inputline, "%s %s %s",
109                                                 Songs[i].filename,
110                                                 Songs[i].melodic_bank_file,
111                                                 Songs[i].drum_bank_file );
112                                 //printf( "%d. '%s' '%s' '%s'\n",i,Songs[i].filename,Songs[i].melodic_bank_file,Songs[i].drum_bank_file );
113                                 i++;
114                         }
115                 }
116                 Num_songs = i;
117                 if (Num_songs <= SONG_FIRST_LEVEL_SONG)
118                         Error("Must have at least %d songs",SONG_FIRST_LEVEL_SONG+1);
119                 cfclose(fp);
120         }
121
122         Songs_initialized = 1;
123
124         //      RBA Hook
125                 if (FindArg("-noredbook"))
126                 {
127                         Redbook_enabled = 0;
128                 }
129                 else    // use redbook
130                 {
131                         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
132                                 RBAInit();
133                         #else
134                                 RBAInit(toupper(CDROM_dir[0]) - 'A');
135                         #endif
136
137                                 if (RBAEnabled())
138                         {
139                                 set_redbook_volume(Config_redbook_volume);
140                                 RBARegisterCD();
141                         }
142                 }
143                 atexit(RBAStop);    // stop song on exit
144 }
145
146 #define FADE_TIME (f1_0/2)
147
148 //stop the redbook, so we can read off the CD
149 void songs_stop_redbook(void)
150 {
151         int old_volume = Config_redbook_volume*REDBOOK_VOLUME_SCALE/8;
152         fix old_time = timer_get_fixed_seconds();
153
154         if (Redbook_playing) {          //fade out volume
155                 int new_volume;
156                 do {
157                         fix t = timer_get_fixed_seconds();
158
159                         new_volume = fixmuldiv(old_volume,(FADE_TIME - (t-old_time)),FADE_TIME);
160
161                         if (new_volume < 0)
162                                 new_volume = 0;
163
164                         RBASetVolume(new_volume);
165
166                 } while (new_volume > 0);
167         }
168
169         RBAStop();                      // Stop CD, if playing
170
171         RBASetVolume(old_volume);       //restore volume
172
173         Redbook_playing = 0;            
174
175 }
176
177 //stop any songs - midi or redbook - that are currently playing
178 void songs_stop_all(void)
179 {
180         digi_stop_current_song();       // Stop midi song, if playing
181
182         songs_stop_redbook();                   // Stop CD, if playing
183 }
184
185 int force_rb_register=0;
186
187 void reinit_redbook()
188 {
189         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
190                 RBAInit();
191         #else
192                 RBAInit(toupper(CDROM_dir[0]) - 'A');
193         #endif
194
195         if (RBAEnabled())
196         {
197                 set_redbook_volume(Config_redbook_volume);
198                 RBARegisterCD();
199                 force_rb_register=0;
200         }
201 }
202
203
204 //returns 1 if track started sucessfully
205 //start at tracknum.  if keep_playing set, play to end of disc.  else
206 //play only specified track
207 int play_redbook_track(int tracknum,int keep_playing)
208 {
209         Redbook_playing = 0;
210
211         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
212                 reinit_redbook();
213
214         if (force_rb_register) {
215                 RBARegisterCD();                        //get new track list for new CD
216                 force_rb_register = 0;
217         }
218
219         if (Redbook_enabled && RBAEnabled()) {
220                 int num_tracks = RBAGetNumberOfTracks();
221                 if (tracknum <= num_tracks)
222                         if (RBAPlayTracks(tracknum,keep_playing?num_tracks:tracknum))  {
223                                 Redbook_playing = tracknum;
224                         }
225         }
226
227         return (Redbook_playing != 0);
228 }
229
230
231 #if 0
232
233 #define REDBOOK_TITLE_TRACK         2
234 #define REDBOOK_CREDITS_TRACK       3
235 #define REDBOOK_FIRST_LEVEL_TRACK   (songs_haved2_cd()?4:1)
236
237 // songs_haved2_cd returns 1 if the descent 2 CD is in the drive and
238 // 0 otherwise
239 int songs_haved2_cd()
240 {
241         char temp[128],cwd[128];
242         
243         getcwd(cwd, 128);
244
245         strcpy(temp,CDROM_dir);
246
247         #ifndef MACINTOSH               //for PC, strip of trailing slash
248         if (temp[strlen(temp)-1] == '\\')
249                 temp[strlen(temp)-1] = 0;
250         #endif
251
252         if ( !chdir(temp) ) {
253                 chdir(cwd);
254                 return 1;
255         }
256
257         return 0;
258 }
259
260 #else
261
262
263 /* Redbook versions of 13 songs from Descent 1 as found on the Macintosh version.
264    All the same tracklist, but some versions have tracks mixed to different lengths
265  1:  Data
266  2:  Primitive Rage
267  3:  Outer Limits
268  4:  The Escape (aka Close Call)
269  5:  Ether in the Air (aka The Darkness of Space)
270  6:  Robotic Menace (aka Get It On)
271  7:  Virtual Tension (aka Fight)
272  8:  Time for the Big Guns (aka Death Lurks Beneath)
273  9:  Mystery Metal (aka C-4 Home Recipe)
274  10: Hydraulic Pressure (aka Escape)
275  11: Not That Button! (aka Backwards Time)
276  12: Industrial Accident (aka Crazyfactory)
277  13: Overdrive (aka Machine Gun)
278  14: A Big Problem (aka Insanity)
279  */
280 #define D1_DISCID_1         0xb60d990e
281 #define D1_DISCID_2         0xde0feb0e
282 #define D1_DISCID_3         0xb70ee40e
283
284 #define D1_RB_TITLE             2
285 #define D1_RB_BRIEFING          3
286 #define D1_RB_ENDLEVEL          4
287 #define D1_RB_ENDGAME           3
288 #define D1_RB_CREDITS           5
289 #define D1_RB_FIRST_LEVEL_SONG  6
290
291 /* Descent II
292  1:  Data
293  2:  Title
294  3:  Crawl
295  4:  Glut
296  5:  Gunner Down
297  6:  Cold Reality
298  7:  Ratzez
299  8:  Crush
300  9:  Untitled
301  10: Haunted (Instrumental Remix)
302  11: Are You Descent?
303  12: Techno Industry
304  13: Robot Jungle
305  */
306 #define D2_DISCID_1         0x22115710 // Mac version, has some extended versions and 3 bonus tracks
307 #define D2_DISCID_2         0xac0bc30d
308 #define D2_DISCID_3         0xc40c0a0d
309 #define D2_DISCID_4         0xc610080d
310 #define D2_DISCID_5         0xcc101b0d
311 #define D2_DISCID_6         0xd00bf30d
312 #define D2_DISCID_7         0xd2101d0d
313 #define D2_DISCID_8         0xd410070d
314 #define D2_DISCID_9         0xda10370d
315
316 #define D2_RB_TITLE            2
317 #define D2_RB_CREDITS          3
318 #define D2_RB_FIRST_LEVEL_SONG 4
319
320 /* Same as above, but all tracks shifted by one
321  1:  Data
322  2:  Data
323  3:  Title
324  4:  Crawl
325  5:  Glut
326  6:  Gunner Down
327  7:  Cold Reality
328  8:  Ratzez
329  9:  Crush
330  10: Untitled
331  11: Haunted (Instrumental Remix)
332  12: Are You Descent?
333  13: Techno Industry
334  14: Robot Jungle
335  */
336 #define D2_2_DISCID_1       0xe010a30e
337
338 #define D2_2_RB_TITLE               3
339 #define D2_2_RB_CREDITS             4
340 #define D2_2_RB_FIRST_LEVEL_SONG    5
341
342 /* Descent II: The Infinite Abyss
343  1:  Data
344  2:  Title
345  3:  Cold Reality - Extended Remix
346  4:  Crawl - Extended Remix
347  5:  Gunner Down - Extended Remix
348  6:  Ratzez - Extended Remix
349  7:  Techno Industry - Extended Remix
350  8:  Are You Descent? - Extended Remix
351  9:  Robot Jungle - Extended Remix
352  */
353 #define D2_IA_DISCID_1      0x7d0ff809
354 #define D2_IA_DISCID_2      0x8110ec09
355 #define D2_IA_DISCID_3      0x82104909
356 #define D2_IA_DISCID_4      0x85101d09
357 #define D2_IA_DISCID_5      0x87102209
358
359 #define D2_IA_RB_TITLE              2
360 #define D2_IA_RB_CREDITS            3
361 #define D2_IA_RB_FIRST_LEVEL_SONG   4
362
363 /* Descent II: Vertigo Series
364  1:  Data
365  2:  Crush - Extended Remix
366  3:  Glut - Extended Remix
367  4:  Haunted - Instrumental Re-Remix
368  5:  New Song #1
369  6:  Untitled - Extended Remix
370  7:  New Song #2
371  8:  New Song #3
372  */
373 #define D2_X_DISCID_1       0x53078208
374 #define D2_X_DISCID_2       0x64071408
375
376 #define D2_X_RB_FIRST_LEVEL_SONG    2
377
378
379 int songs_redbook_track(int songnum)
380 {
381         uint32_t discid;
382
383         if (!Redbook_enabled)
384                 return 0;
385
386         discid = RBAGetDiscID();
387
388         switch (discid) {
389                 case D1_DISCID_1:
390                 case D1_DISCID_2:
391                 case D1_DISCID_3:
392                         switch (songnum) {
393                                 case SONG_TITLE:            return D1_RB_TITLE;
394                                 case SONG_BRIEFING:         return D1_RB_BRIEFING;
395                                 case SONG_ENDLEVEL:         return D1_RB_ENDLEVEL;
396                                 case SONG_ENDGAME:          return D1_RB_ENDGAME;
397                                 case SONG_CREDITS:          return D1_RB_CREDITS;
398                                 case SONG_FIRST_LEVEL_SONG: return D1_RB_FIRST_LEVEL_SONG;
399                                 default: Int3(); break;
400                         }
401                 case D2_DISCID_1:
402                 case D2_DISCID_2:
403                 case D2_DISCID_3:
404                 case D2_DISCID_4:
405                 case D2_DISCID_5:
406                 case D2_DISCID_6:
407                 case D2_DISCID_7:
408                 case D2_DISCID_8:
409                 case D2_DISCID_9:
410                         switch (songnum) {
411                                 case SONG_TITLE:            return D2_RB_TITLE;
412                                 case SONG_CREDITS:          return D2_RB_CREDITS;
413                                 case SONG_FIRST_LEVEL_SONG: return D2_RB_FIRST_LEVEL_SONG;
414                                 default: Int3(); break;
415                         }
416                 case D2_2_DISCID_1:
417                         switch (songnum) {
418                                 case SONG_TITLE:            return D2_2_RB_TITLE;
419                                 case SONG_CREDITS:          return D2_2_RB_CREDITS;
420                                 case SONG_FIRST_LEVEL_SONG: return D2_2_RB_FIRST_LEVEL_SONG;
421                                 default: Int3(); break;
422                         }
423                 case D2_IA_DISCID_1:
424                 case D2_IA_DISCID_2:
425                 case D2_IA_DISCID_3:
426                 case D2_IA_DISCID_4:
427                 case D2_IA_DISCID_5:
428                         switch (songnum) {
429                                 case SONG_TITLE:            return D2_IA_RB_TITLE;
430                                 case SONG_CREDITS:          return D2_IA_RB_CREDITS;
431                                 case SONG_FIRST_LEVEL_SONG: return D2_IA_RB_FIRST_LEVEL_SONG;
432                                 default: Int3(); break;
433                         }
434                 case D2_X_DISCID_1:
435                 case D2_X_DISCID_2:
436                         return D2_X_RB_FIRST_LEVEL_SONG;
437
438                 default:
439                         con_printf(CON_DEBUG, "Unknown CD. discid: %x\n", discid);
440                         return 1;
441         }
442         return 1;
443 }
444
445 #define REDBOOK_TITLE_TRACK         (songs_redbook_track(SONG_TITLE))
446 #define REDBOOK_CREDITS_TRACK       (songs_redbook_track(SONG_CREDITS))
447 #define REDBOOK_FIRST_LEVEL_TRACK   (songs_redbook_track(SONG_FIRST_LEVEL_SONG))
448
449 #endif
450
451
452 void songs_play_song( int songnum, int repeat )
453 {
454         #ifndef SHAREWARE
455         //Assert(songnum != SONG_ENDLEVEL && songnum != SONG_ENDGAME);  //not in full version
456         #endif
457
458         if ( !Songs_initialized )
459                 songs_init();
460
461         //stop any music already playing
462
463         songs_stop_all();
464
465         //do we want any of these to be redbook songs?
466
467         if (force_rb_register) {
468                 RBARegisterCD();                        //get new track list for new CD
469                 force_rb_register = 0;
470         }
471
472         if (songnum == SONG_TITLE)
473                 play_redbook_track(REDBOOK_TITLE_TRACK,0);
474         else if (songnum == SONG_CREDITS)
475                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
476
477         if (!Redbook_playing) {         //not playing redbook, so play midi
478
479                 #ifndef MACINTOSH
480                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, repeat );
481                 #else
482                         digi_play_midi_song(songnum, repeat);
483                 #endif
484         }
485 }
486
487 int current_song_level;
488
489 void songs_play_level_song( int levelnum )
490 {
491         int songnum;
492         int n_tracks;
493
494         Assert( levelnum != 0 );
495
496         if ( !Songs_initialized )
497                 songs_init();
498
499         songs_stop_all();
500
501         current_song_level = levelnum;
502
503         songnum = (levelnum>0)?(levelnum-1):(-levelnum);
504
505         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
506                 reinit_redbook();
507
508         if (force_rb_register) {
509                 RBARegisterCD();                        //get new track list for new CD
510                 force_rb_register = 0;
511         }
512
513         if (Redbook_enabled && RBAEnabled() && (n_tracks = RBAGetNumberOfTracks()) > 1) {
514
515                 //try to play redbook
516
517                 mprintf((0,"n_tracks = %d\n",n_tracks));
518
519                 play_redbook_track(REDBOOK_FIRST_LEVEL_TRACK + (songnum % (n_tracks-REDBOOK_FIRST_LEVEL_TRACK+1)),1);
520         }
521
522         if (! Redbook_playing) {                        //not playing redbook, so play midi
523
524                 songnum = SONG_FIRST_LEVEL_SONG + (songnum % NumLevelSongs);
525
526                 #ifndef MACINTOSH
527                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, 1 );
528                 #else
529                         digi_play_midi_song( songnum, 1 );
530                 #endif
531
532         }
533 }
534
535 //this should be called regularly to check for redbook restart
536 void songs_check_redbook_repeat()
537 {
538         static fix last_check_time;
539         fix current_time;
540
541         if (!Redbook_playing || Config_redbook_volume==0) return;
542
543         current_time = timer_get_fixed_seconds();
544         if (current_time < last_check_time || (current_time - last_check_time) >= F2_0) {
545                 if (!RBAPeekPlayStatus()) {
546                         stop_time();
547                         // if title ends, start credit music
548                         // if credits music ends, restart it
549                         if (Redbook_playing == REDBOOK_TITLE_TRACK || Redbook_playing == REDBOOK_CREDITS_TRACK)
550                                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
551                         else {
552                                 //songs_goto_next_song();
553         
554                                 //new code plays all tracks to end of disk, so if disk has
555                                 //stopped we must be at end.  So start again with level 1 song.
556         
557                                 songs_play_level_song(1);
558                         }
559                         start_time();
560                 }
561                 last_check_time = current_time;
562         }
563 }
564
565 //goto the next level song
566 void songs_goto_next_song()
567 {
568         if (Redbook_playing)            //get correct track
569                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
570
571         songs_play_level_song(current_song_level+1);
572
573 }
574
575 //goto the previous level song
576 void songs_goto_prev_song()
577 {
578         if (Redbook_playing)            //get correct track
579                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
580
581         if (current_song_level > 1)
582                 songs_play_level_song(current_song_level-1);
583
584 }
585