]> icculus.org git repositories - btb/d2x.git/blob - main/songs.c
fixes d1 still textures which are animated in d2, refactorizes d1 texture reading
[btb/d2x.git] / main / songs.c
1 /* $Id: songs.c,v 1.9 2003-10-10 09:36:35 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 #include <unistd.h>
62
63 #include "inferno.h"
64 #include "error.h"
65 #include "pstypes.h"
66 #include "args.h"
67 #include "songs.h"
68 #include "mono.h"
69 #include "cfile.h"
70 #include "digi.h"
71 #include "rbaudio.h"
72 #include "kconfig.h"
73 #include "timer.h"
74
75 song_info Songs[MAX_NUM_SONGS];
76 int Songs_initialized = 0;
77
78 #ifndef MACINTOSH
79 int Num_songs;
80 #endif
81
82 extern void digi_stop_current_song();
83
84 int Redbook_enabled = 1;
85
86 //0 if redbook is no playing, else the track number
87 int Redbook_playing = 0;
88
89 #define NumLevelSongs (Num_songs - SONG_FIRST_LEVEL_SONG)
90
91 extern int CD_blast_mixer();
92
93 #ifndef MACINTOSH
94 #define REDBOOK_VOLUME_SCALE  (255/3)           //255 is MAX
95 #else
96 #define REDBOOK_VOLUME_SCALE    (255)
97 #endif
98
99 //takes volume in range 0..8
100 void set_redbook_volume(int volume)
101 {
102         #ifndef MACINTOSH
103         RBASetVolume(0);                // makes the macs sound really funny
104         #endif
105         RBASetVolume(volume*REDBOOK_VOLUME_SCALE/8);
106 }
107
108 extern char CDROM_dir[];
109
110 void songs_init()
111 {
112         int i;
113         char inputline[80+1];
114         CFILE * fp;
115
116         if ( Songs_initialized ) return;
117
118
119         #if !defined(MACINTOSH) && !defined(WINDOWS)    // don't crank it if on a macintosh!!!!!
120                 if (!FindArg("-nomixer"))
121                         CD_blast_mixer();   // Crank it!
122         #endif
123
124
125         if (cfexist("descent.sng")) {   // mac (demo?) datafiles don't have the .sng file
126                 fp = cfopen( "descent.sng", "rb" );
127                 if ( fp == NULL )
128                 {
129                         Error( "Couldn't open descent.sng" );
130                 }
131                 i = 0;
132                 while (cfgets(inputline, 80, fp ))
133                 {
134                         char *p = strchr(inputline,'\n');
135                         if (p) *p = '\0';
136                         if ( strlen( inputline ) )
137                         {
138                                 Assert( i < MAX_NUM_SONGS );
139                                 sscanf( inputline, "%s %s %s",
140                                                 Songs[i].filename,
141                                                 Songs[i].melodic_bank_file,
142                                                 Songs[i].drum_bank_file );
143                                 //printf( "%d. '%s' '%s' '%s'\n",i,Songs[i].filename,Songs[i].melodic_bank_file,Songs[i].drum_bank_file );
144                                 i++;
145                         }
146                 }
147                 Num_songs = i;
148                 if (Num_songs <= SONG_FIRST_LEVEL_SONG)
149                         Error("Must have at least %d songs",SONG_FIRST_LEVEL_SONG+1);
150                 cfclose(fp);
151         }
152
153         Songs_initialized = 1;
154
155         //      RBA Hook
156         #if !defined(SHAREWARE) || ( defined(SHAREWARE) && defined(APPLE_DEMO) )
157                 if (FindArg("-noredbook"))
158                 {
159                         Redbook_enabled = 0;
160                 }
161                 else    // use redbook
162                 {
163                         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
164                                 RBAInit();
165                         #else
166                                 RBAInit(toupper(CDROM_dir[0]) - 'A');
167                         #endif
168
169                                 if (RBAEnabled())
170                         {
171                                 set_redbook_volume(Config_redbook_volume);
172                                 RBARegisterCD();
173                         }
174                 }
175                 //atexit(RBAStop);      // stop song on exit
176         #endif  // endof ifndef SHAREWARE, ie ifdef SHAREWARE
177 }
178
179 #define FADE_TIME (f1_0/2)
180
181 //stop the redbook, so we can read off the CD
182 void songs_stop_redbook(void)
183 {
184         int old_volume = Config_redbook_volume*REDBOOK_VOLUME_SCALE/8;
185         fix old_time = timer_get_fixed_seconds();
186
187         if (Redbook_playing) {          //fade out volume
188                 int new_volume;
189                 do {
190                         fix t = timer_get_fixed_seconds();
191
192                         new_volume = fixmuldiv(old_volume,(FADE_TIME - (t-old_time)),FADE_TIME);
193
194                         if (new_volume < 0)
195                                 new_volume = 0;
196
197                         RBASetVolume(new_volume);
198
199                 } while (new_volume > 0);
200         }
201
202         //RBAStop();                                            // Stop CD, if playing
203
204         RBASetVolume(old_volume);       //restore volume
205
206         Redbook_playing = 0;            
207
208 }
209
210 //stop any songs - midi or redbook - that are currently playing
211 void songs_stop_all(void)
212 {
213         digi_stop_current_song();       // Stop midi song, if playing
214
215         songs_stop_redbook();                   // Stop CD, if playing
216 }
217
218 int force_rb_register=0;
219
220 void reinit_redbook()
221 {
222         #ifndef __MSDOS__ // defined(WINDOWS) || defined(MACINTOSH)
223                 RBAInit();
224         #else
225                 RBAInit(toupper(CDROM_dir[0]) - 'A');
226         #endif
227
228         if (RBAEnabled())
229         {
230                 set_redbook_volume(Config_redbook_volume);
231                 RBARegisterCD();
232                 force_rb_register=0;
233         }
234 }
235
236
237 //returns 1 if track started sucessfully
238 //start at tracknum.  if keep_playing set, play to end of disc.  else
239 //play only specified track
240 int play_redbook_track(int tracknum,int keep_playing)
241 {
242         Redbook_playing = 0;
243
244         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
245                 reinit_redbook();
246
247         if (force_rb_register) {
248                 RBARegisterCD();                        //get new track list for new CD
249                 force_rb_register = 0;
250         }
251
252         if (Redbook_enabled && RBAEnabled()) {
253                 int num_tracks = RBAGetNumberOfTracks();
254                 if (tracknum <= num_tracks)
255                         if (RBAPlayTracks(tracknum,keep_playing?num_tracks:tracknum))  {
256                                 Redbook_playing = tracknum;
257                         }
258         }
259
260         return (Redbook_playing != 0);
261 }
262
263 /*
264  * Some of these have different Track listings!
265  * Which one is the "correct" order?
266  */
267 #define D2_1_DISCID         0x7d0ff809 // Descent II
268 #define D2_2_DISCID         0xe010a30e // Descent II
269 #define D2_3_DISCID         0xd410070d // Descent II
270 #define D2_4_DISCID         0xc610080d // Descent II
271 #define D2_DEF_DISCID       0x87102209 // Definitive collection Disc 2
272 #define D2_OEM_DISCID       0xac0bc30d // Destination: Quartzon
273 #define D2_OEM2_DISCID      0xc40c0a0d // Destination: Quartzon
274 #define D2_VERTIGO_DISCID   0x53078208 // Vertigo
275 #define D2_VERTIGO2_DISCID  0x64071408 // Vertigo + DMB
276 #define D2_MAC_DISCID       0xb70ee40e // Macintosh
277 #define D2_IPLAY_DISCID     0x22115710 // iPlay for Macintosh
278
279 #define REDBOOK_TITLE_TRACK         2
280 #define REDBOOK_CREDITS_TRACK       3
281 #define REDBOOK_FIRST_LEVEL_TRACK   (songs_haved2_cd()?4:1)
282
283 // songs_haved2_cd returns 1 if the descent 2 CD is in the drive and
284 // 0 otherwise
285
286 #if 1
287 int songs_haved2_cd()
288 {
289         int discid;
290
291         if (!Redbook_enabled)
292                 return 0;
293
294         discid = RBAGetDiscID();
295
296         switch (discid) {
297         case D2_1_DISCID:
298         case D2_2_DISCID:
299         case D2_3_DISCID:
300         case D2_4_DISCID:
301         case D2_DEF_DISCID:
302         case D2_OEM_DISCID:
303         case D2_OEM2_DISCID:
304         case D2_VERTIGO_DISCID:
305         case D2_VERTIGO2_DISCID:
306         case D2_MAC_DISCID:
307         case D2_IPLAY_DISCID:
308                 printf("Found D2 CD! discid: %x\n", discid);
309                 return 1;
310         default:
311                 printf("Unknown CD! discid: %x\n", discid);
312                 return 0;
313         }
314 }
315 #else
316 int songs_haved2_cd()
317 {
318         char temp[128],cwd[128];
319         
320         getcwd(cwd, 128);
321
322         strcpy(temp,CDROM_dir);
323
324         #ifndef MACINTOSH               //for PC, strip of trailing slash
325         if (temp[strlen(temp)-1] == '\\')
326                 temp[strlen(temp)-1] = 0;
327         #endif
328
329         if ( !chdir(temp) ) {
330                 chdir(cwd);
331                 return 1;
332         }
333
334         return 0;
335 }
336 #endif
337
338
339 void songs_play_song( int songnum, int repeat )
340 {
341         #ifndef SHAREWARE
342         //Assert(songnum != SONG_ENDLEVEL && songnum != SONG_ENDGAME);  //not in full version
343         #endif
344
345         if ( !Songs_initialized )
346                 songs_init();
347
348         //stop any music already playing
349
350         songs_stop_all();
351
352         //do we want any of these to be redbook songs?
353
354         if (force_rb_register) {
355                 RBARegisterCD();                        //get new track list for new CD
356                 force_rb_register = 0;
357         }
358
359         if (songnum == SONG_TITLE)
360                 play_redbook_track(REDBOOK_TITLE_TRACK,0);
361         else if (songnum == SONG_CREDITS)
362                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
363
364         if (!Redbook_playing) {         //not playing redbook, so play midi
365
366                 #ifndef MACINTOSH
367                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, repeat );
368                 #else
369                         digi_play_midi_song(songnum, repeat);
370                 #endif
371         }
372 }
373
374 int current_song_level;
375
376 void songs_play_level_song( int levelnum )
377 {
378         int songnum;
379         int n_tracks;
380
381         Assert( levelnum != 0 );
382
383         if ( !Songs_initialized )
384                 songs_init();
385
386         songs_stop_all();
387
388         current_song_level = levelnum;
389
390         songnum = (levelnum>0)?(levelnum-1):(-levelnum);
391
392         if (!RBAEnabled() && Redbook_enabled && !FindArg("-noredbook"))
393                 reinit_redbook();
394
395         if (force_rb_register) {
396                 RBARegisterCD();                        //get new track list for new CD
397                 force_rb_register = 0;
398         }
399
400         if (Redbook_enabled && RBAEnabled() && (n_tracks = RBAGetNumberOfTracks()) > 1) {
401
402                 //try to play redbook
403
404                 mprintf((0,"n_tracks = %d\n",n_tracks));
405
406                 play_redbook_track(REDBOOK_FIRST_LEVEL_TRACK + (songnum % (n_tracks-REDBOOK_FIRST_LEVEL_TRACK+1)),1);
407         }
408
409         if (! Redbook_playing) {                        //not playing redbook, so play midi
410
411                 songnum = SONG_FIRST_LEVEL_SONG + (songnum % NumLevelSongs);
412
413                 #ifndef MACINTOSH
414                         digi_play_midi_song( Songs[songnum].filename, Songs[songnum].melodic_bank_file, Songs[songnum].drum_bank_file, 1 );
415                 #else
416                         digi_play_midi_song( songnum, 1 );
417                 #endif
418
419         }
420 }
421
422 //this should be called regularly to check for redbook restart
423 void songs_check_redbook_repeat()
424 {
425         static fix last_check_time;
426         fix current_time;
427
428         if (!Redbook_playing || Config_redbook_volume==0) return;
429
430         current_time = timer_get_fixed_seconds();
431         if (current_time < last_check_time || (current_time - last_check_time) >= F2_0) {
432                 if (!RBAPeekPlayStatus()) {
433                         stop_time();
434                         // if title ends, start credit music
435                         // if credits music ends, restart it
436                         if (Redbook_playing == REDBOOK_TITLE_TRACK || Redbook_playing == REDBOOK_CREDITS_TRACK)
437                                 play_redbook_track(REDBOOK_CREDITS_TRACK,0);
438                         else {
439                                 //songs_goto_next_song();
440         
441                                 //new code plays all tracks to end of disk, so if disk has
442                                 //stopped we must be at end.  So start again with level 1 song.
443         
444                                 songs_play_level_song(1);
445                         }
446                         start_time();
447                 }
448                 last_check_time = current_time;
449         }
450 }
451
452 //goto the next level song
453 void songs_goto_next_song()
454 {
455         if (Redbook_playing)            //get correct track
456                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
457
458         songs_play_level_song(current_song_level+1);
459
460 }
461
462 //goto the previous level song
463 void songs_goto_prev_song()
464 {
465         if (Redbook_playing)            //get correct track
466                 current_song_level = RBAGetTrackNum() - REDBOOK_FIRST_LEVEL_TRACK + 1;
467
468         if (current_song_level > 1)
469                 songs_play_level_song(current_song_level-1);
470
471 }
472