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