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