]> icculus.org git repositories - taylor/freespace2.git/blob - src/gamesnd/eventmusic.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / gamesnd / eventmusic.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for high-level control of event driven music 
16  *
17  * $Log$
18  * Revision 1.5  2006/04/26 19:39:20  taylor
19  * fix music handling for FS1 to better match the original
20  *
21  * Revision 1.4  2002/06/09 04:41:17  relnev
22  * added copyright header
23  *
24  * Revision 1.3  2002/05/28 08:52:03  relnev
25  * implemented two assembly stubs.
26  *
27  * cleaned up a few warnings.
28  *
29  * added a little demo hackery to make it progress a little farther.
30  *
31  * Revision 1.2  2002/05/07 03:16:45  theoddone33
32  * The Great Newline Fix
33  *
34  * Revision 1.1.1.1  2002/05/03 03:28:09  root
35  * Initial import.
36  *
37  * 
38  * 14    8/19/99 9:41a Alanl
39  * don't play victory 2 music if there are no goals in the mission
40  * 
41  * 13    8/11/99 5:33p Jefff
42  * added 3rd debrief music track
43  * 
44  * 12    8/01/99 2:11p Alanl
45  * make hull value to play more intense battle music a constant
46  * 
47  * 11    8/01/99 2:06p Alanl
48  * tweak battle music track switching
49  * 
50  * 10    7/25/99 9:57p Alanl
51  * change battle music track selection after enemy arrivals to make battle
52  * tracks less repetitive
53  * 
54  * 9     7/19/99 10:13p Andsager
55  * Tie in hud_targeting to  hostile_ships_present() used to determine next
56  * song.
57  * 
58  * 8     6/24/99 10:47p Alanl
59  * loop battle between tracks 2 and 3 if hull integrity < 70%
60  * 
61  * 7     6/21/99 1:34p Alanl
62  * event music tweaks
63  * 
64  * 6     6/20/99 12:06a Alanl
65  * new event music changes
66  * 
67  * 5     11/23/98 11:55a Johnson
68  * return -1 if a score isn't found
69  * 
70  * 4     11/20/98 4:08p Dave
71  * Fixed flak effect in multiplayer.
72  * 
73  * 3     10/23/98 3:51p Dave
74  * Full support for tstrings.tbl and foreign languages. All that remains
75  * is to make it active in Fred.
76  * 
77  * 2     10/07/98 10:52a Dave
78  * Initial checkin.
79  * 
80  * 1     10/07/98 10:48a Dave
81  * 
82  * 107   6/09/98 5:15p Lawrance
83  * French/German localization
84  * 
85  * 106   6/09/98 10:31a Hoffoss
86  * Created index numbers for all xstr() references.  Any new xstr() stuff
87  * added from here on out should be added to the end if the list.  The
88  * current list count can be found in FreeSpace.cpp (search for
89  * XSTR_SIZE).
90  * 
91  * 105   5/24/98 5:28p Dan
92  * let event_music_level_init() over-ride Event_music_enabled
93  * 
94  * 104   5/24/98 4:42p Dan
95  * AL: Fix several bugs related to pausing and enabling/disabling event
96  * music
97  * 
98  * 103   5/23/98 3:17a Lawrance
99  * Tweak how battle music gets restarted
100  * 
101  * 102   5/22/98 10:43a Lawrance
102  * If mission doesn't have event music, don't choose random track
103  * 
104  * 101   5/21/98 6:56p Lawrance
105  * Tweak how victory music plays
106  * 
107  * 100   5/21/98 2:47a Lawrance
108  * Fix some problems with event music
109  * 
110  * 99    5/18/98 3:21p Mike
111  * Don't play arrival and goals tracks in a training mission.
112  * 
113  * 98    5/04/98 3:15p Duncan
114  * AL: remove bogus assert in event_music_player_respawn()
115  * 
116  * 97    5/03/98 1:54a Lawrance
117  * Fix event music problems related to respawning
118  * 
119  * 96    4/03/98 12:56a Lawrance
120  * Fix bug with music not starting in the first mission
121  * 
122  * 95    4/01/98 6:46p Lawrance
123  * Lower default music volume 
124  *
125  * $NoKeywords: $
126  */
127
128
129 #include        "pstypes.h"
130 #include "eventmusic.h"
131 #include "object.h"
132 #include "ship.h"
133 #include "linklist.h"
134 #include "missionload.h"        /* for Builtin_mission_names[] */
135 #include "missionparse.h"
136 #include "timer.h"
137 #include "freespace.h"
138 #include "audiostr.h"
139 #include "missioncampaign.h"
140 #include "sound.h"
141 #include "time.h"
142 #include "cmdline.h"
143 #include "missiongoals.h"
144 #include "localize.h"
145
146 #ifndef PLAT_UNIX
147 #pragma optimize("", off)
148 #endif
149
150 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME       0.5f
151
152 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
153
154 ////////////////////////////
155 // Globals
156 ////////////////////////////
157 int Event_Music_battle_started = 0;
158 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME;                    // range is 0->1
159
160 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
161 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
162
163 // array that holds which briefing track to play for which mission.  Index into Spooled_music[][].
164 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
165
166 typedef struct tagSNDPATTERN {
167         int default_next_pattern;       // Needed so the next_pattern member can be reset
168         int next_pattern;                               // Next pattern to play at loop time (can be same pattern)
169         int default_loop_for;           // Needed so the loop_for variable can be reset
170         int loop_for;                                   // Number of times to loop before switching to next pattern
171         int handle;                                             // handle to open audio stream
172         int force_pattern;                      // flag to indicate that we want to not continue loop, but go to next_pattern
173         int can_force;                                  // whether this pattern can be interrupted
174         int bytes_per_measure;          // number of bytes in a measure
175         float num_measures;                             // number of measures in wave file
176 }       SNDPATTERN;
177
178 SNDPATTERN      Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
179
180 // Holds filenames for the different sections of a soundtrack
181 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
182 int Num_soundtracks;
183 int Current_soundtrack_num;     // Active soundtrack for the current mission.. index into Soundtracks[]
184
185 #define PATTERN_DELAY   1000    // in ms
186 int Current_pattern = -1;               // currently playing part of track
187 int Pending_pattern = -1;
188 int Pattern_timer_id = 0;
189
190 // File Globals
191 static int Num_enemy_arrivals;
192 static int Num_friendly_arrivals;
193
194 #define ARRIVAL_INTERVAL_TIMESTAMP  5000
195 #define BATTLE_CHECK_INTERVAL                   15000
196 static int Battle_over_timestamp;
197 static int Mission_over_timestamp;
198 static int Victory2_music_played;
199 static int Next_arrival_timestamp;
200 static int Check_for_battle_music;
201
202 // stores the number of measures for the different patterns (data from music.tbl)
203 float   Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
204
205 // stores the number of bytes per measure (data from music.tbl)
206 int     Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
207
208 const char* Pattern_names[MAX_PATTERNS] =
209 {
210 //XSTR:OFF
211         "NRML_1",       // Normal Song 1
212 #ifdef MAKE_FS1
213         "NRML_2",       // Normal Song 2
214         "NRML_3",       // Normal Song 3
215 #endif
216         "AARV_1",       // Allied Arrival 1
217         "EARV_1",       // Enemy Arrival 1
218         "BTTL_1",       // Battle Song 1
219         "BTTL_2",       // Battle Song 2
220         "BTTL_3",       // Battle Song 3
221         "AARV_2",       // Allied Arrival 2
222         "EARV_2",       // Enemy Arrival 2
223         "VICT_1",       // Victory Song 1
224         "VICT_2",       // Victory Song 2
225         "FAIL_1",               // Goal Failed 1
226         "DEAD_1"                // Death Song 1
227 //XSTR:ON
228 };
229
230 const char* Pattern_description[MAX_PATTERNS] =
231 {
232 //XSTR:OFF
233         "normal 1",
234 #ifdef MAKE_FS1
235         "normal 2",
236         "normal 3",
237 #endif
238         "friendly arrival 1",
239         "enemy arrival 2",
240         "battle 1",
241         "battle 2",
242         "battle 3",
243         "friendly arrival 2",
244         "enemey arrival 2",
245         "victory 1",
246         "victory 2",
247         "goal failed 1",
248         "death "
249 //XSTR:ON
250 };
251
252 int Pattern_loop_for[MAX_PATTERNS] =
253 {
254         1,      // Normal Song 1
255 #ifdef MAKE_FS1
256         1,      // Normal Song 2
257         1,      // Normal Song 3
258 #endif
259         1,      // Allied Arrival 1
260         1,      // Enemy Arrival 1
261         1,      // Battle Song 1
262         1,      // Battle Song 2
263         1,      // Battle Song 3
264         1,      // Allied Arrival 2
265         1,      // Enemy Arrival 2
266         1,      // Victory Song 1
267         1,      // Victory Song 2
268         1, // Goal Failed 1
269         1       // Death Song 1
270 };
271
272 int Pattern_default_next[MAX_PATTERNS] =
273 {
274 #ifdef MAKE_FS1
275         SONG_NRML_2,    // NRML_1 progresses to NRML_2 by default
276         SONG_NRML_1,    // NRML_2 progresses to NRML_1 by default
277         SONG_NRML_1,    // NRML_3 progresses to NRML_1 by default
278         SONG_NRML_2,    // AARV_1 progresses to NRML_2 by default
279         SONG_BTTL_1,    // EARV_1 progresses to BTTL_1 by default
280         SONG_BTTL_2,    // BTTL_1 progresses to BTTL_2 by default
281         SONG_BTTL_3,    // BTTL_2 progresses to BTTL_3 by default
282         SONG_BTTL_1,    // BTTL_3 progresses to BTTL_1 by default
283         SONG_BTTL_2,    // AARV_2 progresses to BTTL_2 by default
284         SONG_BTTL_2,    // EARV_2 progresses to BTTL_2 by default
285         SONG_NRML_3,    // VICT_1 progresses to NRML_3 by default
286         SONG_NRML_3,    // VICT_2 progresses to NRML_3 by default
287         SONG_NRML_1,    // FAIL_1 progresses to NRML_1 by default
288         -1                              // no music playes after dead
289 #else
290         SONG_NRML_1,    // NRML_1 progresses to NRML_1 by default
291         SONG_NRML_1,    // AARV_1 progresses to NRML_1 by default
292         SONG_BTTL_1,    // EARV_1 progresses to BTTL_1 by default
293         SONG_BTTL_2,    // BTTL_1 progresses to BTTL_2 by default
294         SONG_BTTL_3,    // BTTL_2 progresses to BTTL_3 by default
295         SONG_BTTL_1,    // BTTL_3 progresses to BTTL_1 by default
296         SONG_BTTL_2,    // AARV_2 progresses to BTTL_2 by default
297         SONG_BTTL_3,    // EARV_2 progresses to BTTL_3 by default
298         SONG_NRML_1,    // VICT_1 progresses to NRML_1 by default
299         SONG_NRML_1,    // VICT_2 progresses to NRML_1 by default
300         SONG_NRML_1,    //      FAIL_1 progresses to NRML_1 by default
301         -1                                      // no music plays after dead
302 #endif
303 };
304
305
306 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).  
307 // Other shorter tracks (such as arrivals) play their entire duration.
308 int Pattern_can_force[MAX_PATTERNS] =
309 {
310         TRUE,           // NRML_1 
311 #ifdef MAKE_FS1
312         TRUE,           // NRML_2
313         TRUE,           // NRML_3
314 #endif
315         FALSE,  // AARV_1 
316         FALSE,  // EARV_1 
317         TRUE,           // BTTL_1
318         TRUE,           // BTTL_2 
319         TRUE,           // BTTL_3
320         FALSE,  // AARV_2 
321         FALSE,  // EARV_2 
322         FALSE,  // VICT_1 
323         TRUE,           // VICT_2 
324         FALSE,  // FAIL_1
325         TRUE            // DEAD_1
326 };
327
328
329 int Event_music_enabled = TRUE;
330 static int Event_music_inited = FALSE;
331 static int Event_music_level_inited = FALSE;
332 static int Event_music_begun = FALSE;
333
334 // forward function declarations
335 int hostile_ships_present();
336 int hostile_ships_to_arrive();
337 extern int hud_target_invalid_awacs(object *objp);
338
339 // Holds file names of spooled music that is played at menus, briefings, credits etc.
340 // Indexed into by a #define enumeration of the different kinds of spooled music
341 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
342 int Num_music_files;                            // Number of spooled music files
343
344 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
345 int Mission_music[NUM_SCORES];  
346
347 // -------------------------------------------------------------------------------------------------
348 // event_music_init() 
349 //
350 // Called once at game start-up to parse music.tbl and set some state variables
351 //
352 void event_music_init()
353 {
354         if ( snd_is_inited() == FALSE ) {
355                 Event_music_enabled = FALSE;
356                 return;
357         }
358
359         if ( Cmdline_freespace_no_music ) {
360                 return;
361         }
362
363         if ( Event_music_inited == TRUE )
364                 return;
365
366         event_music_parse_musictbl();
367         Event_music_inited = TRUE;
368         Event_music_begun = FALSE;
369 }
370
371 // -------------------------------------------------------------------------------------------------
372 // event_music_close() 
373 //
374 // Called once at game end
375 //
376 void event_music_close()
377 {
378         if ( Event_music_inited == FALSE )
379                 return;
380
381         Event_music_inited = FALSE;
382 }
383
384 // -------------------------------------------------------------------------------------------------
385 // event_music_force_switch() 
386 //
387 // Performs a switch between patterns.  Sets the cutoff limit for the pattern that is being
388 // switch to.
389 //
390 void event_music_force_switch()
391 {
392         if ( Event_music_enabled == FALSE )
393                 return;
394
395         if ( Event_music_level_inited == FALSE )
396                 return;
397
398         int new_pattern;
399         Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
400
401         new_pattern = Patterns[Current_pattern].next_pattern;
402
403         if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
404                 if ( Current_pattern == SONG_BTTL_2 ) {
405                         new_pattern = SONG_BTTL_1;
406                 } else {
407                         new_pattern = SONG_BTTL_2;
408                 }
409         } else {
410                 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
411                         // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
412                         if (Player_obj != NULL && Player_ship != NULL) {
413                                 SDL_assert(Player_ship->ship_info_index >= 0);
414                                 SDL_assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
415                                 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
416                                 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
417                                         new_pattern = SONG_BTTL_2;
418                                 }
419                         }
420                 }
421         }
422
423         if ( new_pattern == -1 ) {
424                 return;
425         }
426
427         if ( Patterns[new_pattern].num_measures == 0 )
428                 return; // invalid pattern
429
430         SDL_assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
431         audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0);   // no looping
432         audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
433         Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
434         Patterns[Current_pattern].force_pattern = FALSE;
435         nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
436         Current_pattern = new_pattern;
437 }
438
439 // -------------------------------------------------------------------------------------------------
440 // event_music_do_frame() 
441 //
442 // Called once per game frame, to check for transitions of patterns (and to start the music off at
443 // the beginning).
444 //
445 void event_music_do_frame()
446 {
447         if ( Event_music_level_inited == FALSE ) {
448                 return;
449         }
450
451         if ( Event_music_enabled == FALSE ) {
452                 return;
453         }
454
455         // start off the music delayed
456         if ( timestamp_elapsed(Pattern_timer_id) ) {
457                 Pattern_timer_id = 0;
458                 Event_music_begun = TRUE;
459                 if ( Current_pattern != -1 ) {
460                         SDL_assert(Patterns[Current_pattern].handle >= 0 );
461                         audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0);       // no looping
462                         audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
463                 }
464         }
465
466         if ( Event_music_begun == FALSE ) {
467                 return;
468         }
469
470         if ( Current_pattern != -1 ) {
471                 SNDPATTERN *pat;
472                 pat = &Patterns[Current_pattern];
473
474                 // First case: switching to a different track since first track is almost at end
475                 if ( audiostream_done_reading(pat->handle) ) {
476                         event_music_force_switch();     
477                 }
478                 // Second case: looping back to start of same track since at the end
479                 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
480                         audiostream_stop(pat->handle);  // stop current and rewind
481                         pat->loop_for--;
482                         if ( pat->loop_for > 0 ) {
483                                 audiostream_play(pat->handle, Master_event_music_volume, 0);    // no looping
484                                 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
485                         }
486                         else {
487                                 event_music_force_switch();
488                         }
489                 }
490                 // Third case: switching to a different track by interruption
491                 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
492                         int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
493                         int measures_played = bytes_streamed / pat->bytes_per_measure;
494                         if ( measures_played < pat->num_measures ) {
495                                 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
496                                 pat->force_pattern = FALSE;
497                                 pat->loop_for = 0;
498                         }
499                 }
500
501                 // We want to go back to NRML track music if all the hostiles have been 
502                 // destroyed, and we are still playing the battle music
503                 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
504                         if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
505                                 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
506                                 if ( hostile_ships_present() == FALSE ) {
507                                         if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
508                                                 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
509                                                 Patterns[Current_pattern].force_pattern = TRUE;
510                                                 Event_Music_battle_started = 0;
511                                         }
512                                 }
513                         }
514                 }
515
516                 if (Event_Music_battle_started == 0) {
517 #ifdef MAKE_FS1
518                         if ( (Current_pattern == SONG_NRML_1) || (Current_pattern == SONG_NRML_2) ) {
519 #else
520                         if (Current_pattern == SONG_NRML_1) {
521 #endif
522                                 if (timestamp_elapsed(Check_for_battle_music)) {
523                                         Check_for_battle_music = timestamp(1000);
524                                         if (hostile_ships_present() == TRUE) {
525                                                 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
526                                                 Patterns[Current_pattern].force_pattern = TRUE;
527                                         }
528                                 }
529                         }
530                 }
531
532                 if ( !Victory2_music_played ) {
533                         if ( timestamp_elapsed(Mission_over_timestamp) ) {
534                                 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
535                                 if ( mission_goals_met() && (!hostile_ships_present()) ) {
536                                         Patterns[Current_pattern].next_pattern = SONG_VICT_2;
537                                         Patterns[Current_pattern].force_pattern = TRUE;
538                                         Victory2_music_played = 1;
539                                 }
540                         }
541                 }
542         }
543 }
544
545 // -------------------------------------------------------------------------------------------------
546 // event_music_level_init() 
547 //
548 // Called at the start of a mission (level).  Sets up the pattern data, and kicks off the
549 // first track to play().
550 //
551 // input:       force_soundtrack        =>              OPTIONAL parameter (default value -1)
552 //                                                                                              forces the soundtrack to ignore the music.tbl assignment
553 //
554 void event_music_level_init(int force_soundtrack)
555 {
556         int                                     i;
557         SOUNDTRACK_INFO *strack;
558
559         if ( Cmdline_freespace_no_music ) {
560                 return;
561         }
562
563         if ( !audiostream_is_inited() )
564                 return;
565
566         if ( Event_music_level_inited == TRUE )
567                 return;
568
569         Current_pattern = -1;
570
571         if ( Event_music_inited == FALSE )
572                 return;
573
574
575         if ( force_soundtrack != -1 ) {
576                 Current_soundtrack_num = force_soundtrack;
577         }
578
579         if ( Current_soundtrack_num < 0 ) {
580                 return;
581 /*
582                 // okay, assign a random soundtrack if one exists
583                 if ( Num_soundtracks > 0 ) {
584                         Current_soundtrack_num = rand()%Num_soundtracks;
585                         nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
586                 } else {
587                         return;
588                 }
589 */
590         }
591
592         SDL_assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
593         strack = &Soundtracks[Current_soundtrack_num];
594
595         // open the pattern files, and get ready to play them
596         for ( i = 0; i < strack->num_patterns; i++ ) {
597                 if ( !SDL_strcasecmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
598                         Patterns[i].handle = -1;        
599                         continue;
600                 }
601
602                 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
603
604                 if ( Patterns[i].handle >= 0 ) {
605                         Event_music_level_inited = TRUE;
606                         Event_music_enabled = TRUE;
607                 }
608
609                 Patterns[i].next_pattern = Pattern_default_next[i];
610                 Patterns[i].default_next_pattern = Pattern_default_next[i];
611                 Patterns[i].loop_for = Pattern_loop_for[i];
612                 Patterns[i].default_loop_for = Pattern_loop_for[i];
613                 Patterns[i].force_pattern = FALSE;
614                 Patterns[i].can_force = Pattern_can_force[i];
615                 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
616                 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
617         }
618
619         Num_enemy_arrivals = 0;
620         Num_friendly_arrivals = 0;
621         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
622         Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
623         Next_arrival_timestamp = timestamp(1);
624         Victory2_music_played = 0;
625         Check_for_battle_music = 0;
626
627         if ( Event_music_level_inited ) {
628                 if ( force_soundtrack != -1 )  {
629                         event_music_first_pattern();
630                 }
631         }
632 }
633
634 // -------------------------------------------------------------------------------------------------
635 // event_music_first_pattern() 
636 //
637 // Picks the first pattern to play, based on whether the battle has started.  Delay start
638 // by PATTERN_DELAY
639 //
640 void event_music_first_pattern()
641 {
642         if ( Event_music_inited == FALSE ) {
643                 return;
644         }
645
646         if ( Event_music_enabled == FALSE ) {
647                 return;
648         }
649
650         if ( Event_music_level_inited == FALSE ) {
651                 event_music_level_init();
652         }
653
654         if ( Event_music_level_inited == FALSE ) {
655                 return;
656         }
657
658         if ( Event_music_begun == TRUE ) {
659                 return;
660         }
661
662         if ( Current_pattern != -1 ) {
663                 if (  audiostream_is_playing(Patterns[Current_pattern].handle) )
664                         audiostream_stop( Patterns[Current_pattern].handle );
665         }
666
667         Pattern_timer_id = 2000;        // start music delay
668         
669         Event_music_begun = FALSE;
670         if ( Event_Music_battle_started == TRUE ) {
671                 Current_pattern = SONG_BTTL_1;
672         }
673         else {
674                 Current_pattern = SONG_NRML_1;
675         }
676 }
677
678 // -------------------------------------------------------------------------------------------------
679 // event_music_level_close() 
680 //
681 // Called at the end of each mission (level).  Stops any playing patterns by fading them out.
682 //
683 void event_music_level_close()
684 {
685         int i;
686
687         if ( Event_music_level_inited == FALSE )
688                 return;
689
690         if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
691                 SOUNDTRACK_INFO *strack;
692    
693                 SDL_assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
694                 strack = &Soundtracks[Current_soundtrack_num];
695
696                 // close the pattern files
697                 for ( i = 0; i < strack->num_patterns; i++ ) {
698                         if ( i == Current_pattern ) {
699                                 if (  audiostream_is_playing(Patterns[Current_pattern].handle) )
700                                         audiostream_close_file( Patterns[i].handle );
701                                 else
702                                         audiostream_close_file( Patterns[i].handle, 0 );
703                         }
704                         else
705                                 audiostream_close_file( Patterns[i].handle, 0 );
706                 }
707         } else {
708                 // close em all down then
709                 audiostream_close_all(0);
710         }
711
712         Current_pattern = -1;
713         Event_music_level_inited = FALSE;
714         Event_Music_battle_started = FALSE;
715         Event_music_enabled = 0;
716         Event_music_begun = FALSE;
717 }
718
719 // -------------------------------------------------------------------------------------------------
720 // event_music_battle_start() 
721 //
722 // Start the battle music.  If the music is already started before, do nothing.
723 //
724 int event_music_battle_start()
725 {       
726         if ( !hostile_ships_present() ) {
727                 return 0;
728         }
729
730         //      No special tracks in training.
731         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
732                 return -1;
733
734         // Check to see if we've already started off the battle song
735         if ( Event_Music_battle_started == 1 ) {
736                 return 0;
737         }
738
739         if ( Event_music_enabled == FALSE )
740                 return -1;
741
742         if ( Event_music_level_inited == FALSE )
743                 return -1;
744
745         if ( Current_pattern == SONG_BTTL_1 )
746                 return 0;       // already playing
747
748         if ( Current_pattern == SONG_DEAD_1 )
749                 return 0;       // death is the last song to play
750
751         if ( Current_pattern != -1 ) {
752                 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
753                 Patterns[Current_pattern].force_pattern = TRUE;
754         }
755
756         Event_Music_battle_started = 1; // keep track of this state though, need on restore
757         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
758
759         return 0;
760 }
761
762 // -------------------------------------------------------------------------------------------------
763 // event_music_enemy_arrival() 
764 //
765 // An enemy has arrived, play an enemy arrival pattern.
766 //
767 int event_music_enemy_arrival()
768 {
769         if ( Event_music_enabled == FALSE ) {
770                 return -1;
771         }
772
773         if ( Event_music_level_inited == FALSE ) {
774                 return -1;
775         }
776
777         int next_pattern;
778         if ( Event_Music_battle_started == TRUE ) {
779                 next_pattern = SONG_EARV_2;
780         }
781         else {
782                 next_pattern = SONG_EARV_1;
783         }
784
785         if ( Current_pattern == next_pattern )
786                 return 0;       // already playing
787
788         if ( Current_pattern == SONG_DEAD_1 )
789                 return 0;       // death is the last song to play
790
791         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
792                 return 0;
793
794         if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
795                 return 0;       // don't squash a pending pattern
796
797         Num_enemy_arrivals++;
798
799         // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
800         bool play_intense_battle_music = false;
801         if (Player_obj != NULL && Player_ship != NULL) {
802                 SDL_assert(Player_ship->ship_info_index >= 0);
803                 SDL_assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
804                 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
805                 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
806                         play_intense_battle_music = true;
807                 }
808         }
809
810         if (play_intense_battle_music == true) {
811                 if (Current_pattern == SONG_BTTL_2) {
812                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
813                 } else {
814                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
815                 }
816         } else {
817                 if (Current_pattern == SONG_BTTL_1) {
818                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
819                 } else if (Current_pattern == SONG_BTTL_2) {
820                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
821                 } else {
822                         Patterns[next_pattern].next_pattern = SONG_BTTL_1;
823                 }
824         }
825
826         /*
827         // AL 11-03-97:
828         // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
829         if ( Num_enemy_arrivals & 1 ) {
830                 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
831         } else {
832                 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
833                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
834                 } else {
835                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
836                 }
837         }
838         */
839
840         if ( Current_pattern != -1 ) {
841                 Patterns[Current_pattern].next_pattern = next_pattern;
842                 Patterns[Current_pattern].force_pattern = TRUE;
843         }
844
845         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
846
847         return 0;
848 }
849
850 // -------------------------------------------------------------------------------------------------
851 // event_music_friendly_arrival() 
852 //
853 // An friendly has arrived, play a friendly arrival pattern.
854 //
855 int event_music_friendly_arrival()
856 {
857         if ( Event_music_enabled == FALSE )
858                 return -1;
859
860         if ( Event_music_level_inited == FALSE )
861                 return -1;
862
863         if (timestamp_elapsed(Next_arrival_timestamp) == false) {
864                 return 0;
865         }
866
867         int next_pattern;
868         if ( Event_Music_battle_started == TRUE ) {
869                 next_pattern = SONG_AARV_2;
870         }
871         else {
872                 next_pattern = SONG_AARV_1;
873         }
874
875         if ( Current_pattern == next_pattern )
876                 return 0;       // already playing
877
878         if ( Current_pattern == SONG_DEAD_1 )
879                 return 0;       // death is the last song to play
880
881         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
882                 return 0;
883
884         if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
885                 return 0;       // don't squash a pending pattern
886
887         // After the second friendly arrival, default to SONG_BTTL_3
888         Num_friendly_arrivals++;
889
890         if ( Current_pattern != -1 ) {
891                 // AL 06-24-99: always overlay allied arrivals
892                 /*
893                 if (next_pattern == SONG_AARV_1) {
894                         Patterns[Current_pattern].next_pattern = next_pattern;
895                         Patterns[Current_pattern].force_pattern = TRUE;
896                 } else {
897                 */
898                         SDL_assert(Patterns[SONG_AARV_1].handle >= 0 );
899                         audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0);   // no looping
900                         audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
901                 //}
902         }
903
904         Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
905
906         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
907
908         return 0;
909 }
910
911 //      Play arrival music keyed to team "team".
912 void event_music_arrival(int team)
913 {
914         //      No friendly arrival music in a training mission.
915         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
916                 return;
917
918         if ( Player_ship->team == team ) {
919                 event_music_friendly_arrival();
920         } else {
921                 event_music_enemy_arrival();
922         }
923 }
924
925 // -------------------------------------------------------------------------------------------------
926 // event_music_primary_goals_met() 
927 //
928 // A primary goal has failed
929 //
930 int event_music_primary_goal_failed()
931 {
932         int next_pattern;
933
934         //      No special tracks in training.
935         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
936                 return -1;
937
938         if ( Event_music_enabled == FALSE )
939                 return -1;
940
941         if ( Event_music_level_inited == FALSE )
942                 return -1;
943
944         if ( Current_pattern == SONG_DEAD_1 )
945                 return 0;       // death is the last song to play
946
947         if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
948                 return 0;
949
950         if ( hostile_ships_present() ) {
951                 next_pattern = SONG_BTTL_1;
952         }
953         else {
954                 next_pattern = SONG_NRML_1;
955                 Event_Music_battle_started = 0;
956         }
957
958         if ( Current_pattern != -1 ) {
959                 Patterns[Current_pattern].next_pattern = next_pattern;
960                 Patterns[Current_pattern].force_pattern = TRUE;
961         }
962
963         return 0;
964 }
965
966 // -------------------------------------------------------------------------------------------------
967 // event_music_primary_goals_met() 
968 //
969 // A goal has been achieved, play the appropriate victory music.
970 //
971 int event_music_primary_goals_met()
972 {
973         int next_pattern = SONG_VICT_1;
974
975         //      No special tracks in training.
976         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
977                 return -1;
978
979         if ( Event_music_enabled == FALSE )
980                 return -1;
981
982         if ( Event_music_level_inited == FALSE )
983                 return -1;
984
985         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
986                 return 0;       // already playing
987
988         if ( Current_pattern == SONG_DEAD_1 )
989                 return 0;       // death is the last song to play
990
991         if ( hostile_ships_present() ) {
992                 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
993         }
994         else {
995                 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
996                 Event_Music_battle_started = 0;
997
998                 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
999                 // to the next default track
1000                 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
1001                         Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
1002                 } else {
1003                         Victory2_music_played = 1;
1004                 }
1005         }
1006
1007         if ( Current_pattern != -1 ) {
1008                 Patterns[Current_pattern].next_pattern = next_pattern;
1009                 Patterns[Current_pattern].force_pattern = TRUE;
1010         }
1011
1012         return 0;
1013 }
1014
1015 // -------------------------------------------------------------------------------------------------
1016 // event_music_player_death() 
1017 //
1018 // The player has died, play death pattern.
1019 //
1020 int event_music_player_death()
1021 {
1022         if ( Event_music_enabled == FALSE )
1023                 return -1;
1024
1025         if ( Event_music_level_inited == FALSE )
1026                 return -1;
1027
1028         if ( Current_pattern == SONG_DEAD_1 )
1029                 return 0;       // already playing
1030
1031         if ( Current_pattern != -1 ) {
1032                 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
1033                 Patterns[Current_pattern].force_pattern = TRUE;
1034         }
1035
1036         return 0;
1037 }
1038
1039 // -------------------------------------------------------------------------------------------------
1040 // event_music_player_respawn() 
1041 //
1042 // Player has respawned (multiplayer only)
1043 //
1044 int event_music_player_respawn()
1045 {
1046         if ( Event_music_enabled == FALSE )
1047                 return -1;
1048
1049         if ( Event_music_level_inited == FALSE )
1050                 return -1;
1051
1052 //      SDL_assert(Current_pattern == SONG_DEAD_1);
1053
1054         Event_Music_battle_started = 0;
1055         Patterns[Current_pattern].next_pattern = SONG_NRML_1;
1056         Patterns[Current_pattern].force_pattern = TRUE;
1057
1058         return 0;
1059 }
1060
1061 // -------------------------------------------------------------------------------------------------
1062 // event_music_player_respawn_as_observer() 
1063 //
1064 // Player has respawned (multiplayer only)
1065 //
1066 int event_music_player_respawn_as_observer()
1067 {
1068         if ( Event_music_enabled == FALSE )
1069                 return -1;
1070
1071         if ( Event_music_level_inited == FALSE )
1072                 return -1;
1073
1074         if ( Current_pattern >= 0 ) {
1075                 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1076                         audiostream_stop(Patterns[Current_pattern].handle);
1077                         Current_pattern = -1;
1078                 }
1079         }
1080
1081         return 0;
1082 }
1083
1084 // -------------------------------------------------------------------------------------------------
1085 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1086 // array
1087 //
1088 void event_music_parse_musictbl()
1089 {
1090         char fname[MAX_FILENAME_LEN];
1091         char line_buf[128];
1092
1093         int num_patterns = 0;
1094
1095         Num_music_files = 0;
1096         Num_soundtracks = 0;            // Global
1097         event_music_reset_choices();
1098
1099         // open localization
1100         lcl_ext_open();
1101
1102         try {
1103                 read_file_text("music.tbl");
1104                 reset_parse();          
1105
1106                 // Loop through all the sound-tracks
1107                 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1108                         SDL_assert(Num_soundtracks < MAX_SOUNDTRACKS);
1109                         required_string("#SoundTrack Start");
1110                         required_string("$SoundTrack Name:");
1111                         stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1112                         while (required_string_either("#SoundTrack End","$Name:")) {
1113                                 SDL_assert( num_patterns < MAX_PATTERNS );
1114                                 required_string("$Name:");
1115                                 stuff_string(line_buf, F_NAME, NULL);
1116
1117                                 // line_buf holds 3 fields:  filename, num measures, bytes per measure
1118
1119                                 char *token;
1120                                 int count = 0;
1121                                 token = strtok( line_buf, NOX(" ,\t"));
1122                                 SDL_strlcpy(fname, token, SDL_arraysize(fname));
1123                                 while ( token != NULL ) {
1124                                         token = strtok( NULL, NOX(" ,\t") );
1125                                         if ( token == NULL ) {
1126                                                 SDL_assert(count == 2 );
1127                                                 break;
1128                                         }
1129
1130                                         if ( count == 0 ) {
1131                                                 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1132
1133                                         } else {
1134                                                 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1135                                         }
1136
1137                                         count++;
1138                                 }       // end while
1139
1140                                 // convert from samples per measure to bytes per measure
1141                                 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1142                                 SDL_strlcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname, MAX_FILENAME_LEN);
1143                                 num_patterns++;
1144                         }
1145
1146                         required_string("#SoundTrack End");
1147                         Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1148                         Num_soundtracks++;
1149                         num_patterns = 0;
1150                 }
1151
1152                 // Parse the menu music section
1153                 required_string("#Menu Music Start");
1154                 while (required_string_either("#Menu Music End","$Name:")) {
1155                         SDL_assert( Num_music_files < MAX_SPOOLED_MUSIC );
1156
1157                         required_string("$Name:");
1158                         stuff_string(fname, F_PATHNAME, NULL);
1159                         SDL_assert( strlen(fname) < (NAME_LENGTH-1) );
1160                         SDL_strlcpy( Spooled_music[Num_music_files].name, fname, SDL_arraysize(Spooled_music[0].name) );
1161
1162                         required_string("$Filename:");
1163                         stuff_string(fname, F_PATHNAME, NULL);
1164                         if ( SDL_strcasecmp(fname, NOX("none.wav"))  ) {
1165                                 SDL_assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1166                                 SDL_strlcpy( Spooled_music[Num_music_files].filename, fname, SDL_arraysize(Spooled_music[0].filename) );
1167                         }
1168
1169                         Num_music_files++;                      
1170                 }
1171
1172                 required_string("#Menu Music End");
1173         } catch (parse_error_t rval) {
1174                 Error(LOCATION, "Unable to parse music.tbl!  Code = %i.\n", (int)rval);
1175         }
1176
1177         // close localization
1178         lcl_ext_close();
1179 }
1180
1181 // -------------------------------------------------------------------------------------------------
1182 // event_music_change_pattern()
1183 //
1184 // Force a particular pattern to play.  This is used for debugging purposes.
1185 //
1186 void event_music_change_pattern(int new_pattern)
1187 {
1188         if ( Event_music_enabled == FALSE ) {
1189                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1190                 return;
1191         }
1192
1193         if ( Event_music_level_inited == FALSE ) {
1194                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1195                 return;
1196         }
1197
1198         if ( Current_pattern == new_pattern )
1199                 return; // already playing
1200
1201         if ( Current_pattern != -1 ) {
1202                 Patterns[Current_pattern].next_pattern = new_pattern;
1203                 Patterns[Current_pattern].force_pattern = TRUE;
1204         }
1205 }
1206
1207 // -------------------------------------------------------------------------------------------------
1208 // event_music_return_current_pattern()
1209 //
1210 // Simply return what the current pattern being played is.  Don't want to make global.
1211 //
1212 int event_music_return_current_pattern()
1213 {
1214         return Current_pattern;
1215 }
1216
1217 // -------------------------------------------------------------------------------------------------
1218 // event_music_disable()
1219 //
1220 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1221 // set Event_music_enabled = FALSE).  We don't uninit event music, since it might be toggled
1222 // back on this level.
1223 //
1224 void event_music_disable()
1225 {
1226         if ( Event_music_level_inited == FALSE )
1227                 return;
1228
1229         if ( Event_music_enabled == FALSE )
1230                 return;
1231
1232         if (Current_pattern == -1)
1233                 return;
1234
1235         SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1236         if (  audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1237                         audiostream_stop(Patterns[Current_pattern].handle);     // stop current and rewind
1238         }
1239
1240         Event_music_begun = FALSE;
1241         Event_music_enabled = FALSE;
1242         Current_pattern = -1;
1243 }
1244
1245 // -------------------------------------------------------------------------------------------------
1246 // event_music_enable()
1247 //
1248 // Init the event music (ie load the patterns) if required.  Set up the first song to play, and
1249 // set Event_music_enabled = TRUE to allow patterns to play.
1250 //
1251 void event_music_enable()
1252 {
1253         if ( Event_music_enabled == TRUE )
1254                 return;
1255
1256         Event_music_enabled = TRUE;
1257
1258         if ( Event_music_level_inited == FALSE ) {
1259                 event_music_level_init();
1260                 // start the first pattern to play (delayed)
1261                 if ( Game_mode & GM_IN_MISSION ) {
1262                         event_music_first_pattern();
1263                 }
1264         }
1265         else {
1266                 // start a new pattern
1267                 Event_music_begun = FALSE;
1268                 Pattern_timer_id = timestamp(150);
1269                 event_music_start_default();
1270         }
1271 }
1272
1273 // -------------------------------------------------------------------------------------------------
1274 // event_music_start_default()
1275 //
1276 //      Start playing a default track, based on how far the mission has progressed
1277 //
1278 void event_music_start_default()
1279 {       
1280         int next_pattern;
1281
1282         if ( Event_Music_battle_started == TRUE ) {
1283                 if ( hostile_ships_present() ) {
1284                         next_pattern = SONG_BTTL_1;
1285                 }
1286                 else {
1287                         Event_Music_battle_started = FALSE;
1288 #ifdef MAKE_FS1
1289                         next_pattern = SONG_NRML_3;
1290 #else
1291                         next_pattern = SONG_NRML_1;
1292 #endif
1293                 }
1294         }
1295         else
1296                 next_pattern = SONG_NRML_1;     
1297
1298         if ( Current_pattern == -1 ) {
1299                 Current_pattern = next_pattern;
1300         }
1301         else {
1302                 Patterns[Current_pattern].next_pattern = next_pattern;
1303                 Patterns[Current_pattern].force_pattern = TRUE;
1304         }
1305
1306 }
1307
1308 // -------------------------------------------------------------------------------------------------
1309 // event_music_pause()
1310 //
1311 //      Stop any playing pattern, but don't rewind.
1312 //
1313 void event_music_pause()
1314 {
1315         if ( Event_music_enabled == FALSE ) {
1316                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1317                 return;
1318         }
1319
1320         if ( Event_music_level_inited == FALSE ) {
1321                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1322                 return;
1323         }
1324
1325         if (Current_pattern == -1)
1326                 return;
1327
1328         SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1329         if (  audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1330                         audiostream_stop(Patterns[Current_pattern].handle, 0);  // stop current and don't rewind
1331         }
1332 }
1333
1334 // -------------------------------------------------------------------------------------------------
1335 // event_music_unpause()
1336 //
1337 //      Start the Current_pattern if it is paused.
1338 //
1339 void event_music_unpause()
1340 {
1341         if ( Event_music_enabled == FALSE ) {
1342                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1343                 return;
1344         }
1345
1346         if ( Event_music_level_inited == FALSE ) {
1347                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1348                 return;
1349         }
1350
1351         if (Current_pattern == -1)
1352                 return;
1353
1354         SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1355         if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1356                 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0);       // no looping
1357                 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1358         }
1359 }
1360
1361 // -------------------------------------------------------------------------------------------------
1362 // event_music_set_volume_all()
1363 //
1364 //      Set the volume of the event driven music.  Used when using the game-wide music volume is changed
1365 // by the user.
1366 //
1367 void event_music_set_volume_all(float volume)
1368 {
1369         audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1370 }
1371
1372 // ----------------------------------------------------------------------
1373 // hostile_ships_present()
1374 //
1375 // Determine if there are any non-friendly ships in existance
1376 //
1377 // returns: 1 =>        there are non-friendly ships in existance
1378 //                              0 =>  any ships in existance are friendly
1379 int hostile_ships_present()
1380 {
1381         ship            *shipp;
1382         ship_obj *so;
1383
1384         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1385                 shipp = &Ships[Objects[so->objnum].instance];
1386
1387                 // check if ship if enemy ship
1388                 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR)  )
1389                         continue;
1390
1391                 // check if ship is threatening
1392                 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) ) 
1393                         continue;
1394         
1395                 // check if ship is flyable
1396                 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1397                         continue;
1398                 }
1399
1400                 // check if ship is visible by player's team
1401                 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1402                         continue;
1403                 }
1404
1405                 return 1;
1406         }
1407         return 0;
1408 }
1409
1410 // ----------------------------------------------------------------------
1411 // hostile_ships_to_arrive()
1412 //
1413 // Determine if there are any non-friendly ships yet to arrive
1414 //
1415 // NOTE: neutral ships are considered hostile for the purpose of event music
1416 //
1417 int hostile_ships_to_arrive()
1418 {
1419         p_object *p_objp;
1420
1421         p_objp = GET_FIRST(&ship_arrival_list);
1422         while( p_objp != END_OF_LIST(&ship_arrival_list) )      {
1423                 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1424                         return 1;
1425                 }
1426                 p_objp = GET_NEXT(p_objp);
1427         }
1428         return 0;
1429 }
1430
1431 // ----------------------------------------------------------------
1432 // event_music_get_info()
1433 //
1434 // Return information about the event music in the buffer outbuf
1435 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1436 void event_music_get_info(char *outbuf, const int outbuf_size)
1437 {
1438         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1439                 SDL_strlcpy(outbuf, XSTR( "Event music is not playing", 213), outbuf_size);
1440         }
1441         else {  
1442                 SDL_snprintf(outbuf, outbuf_size, XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1443         }
1444 }
1445
1446 // ----------------------------------------------------------------
1447 // event_music_next_soundtrack()
1448 //
1449 // input:       delta           =>              1 or -1, depending if you want to go to next or previous song
1450 //
1451 // returns: New soundtrack number if successfully changed, otherwise return -1
1452 //
1453 int event_music_next_soundtrack(int delta)
1454 {
1455         int new_soundtrack;
1456
1457         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1458                 return -1;
1459         }
1460                 
1461         new_soundtrack = Current_soundtrack_num + delta;
1462         if ( new_soundtrack >= Num_soundtracks )
1463                 new_soundtrack = 0;
1464
1465         event_music_level_close();
1466         event_music_level_init(new_soundtrack);
1467
1468         return Current_soundtrack_num;
1469 }
1470
1471 // ----------------------------------------------------------------
1472 // event_music_get_soundtrack_name()
1473 //
1474 // Return information about the event music in the buffer outbuf
1475 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1476 void event_music_get_soundtrack_name(char *outbuf, const int outbuf_size)
1477 {
1478         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1479                 SDL_strlcpy(outbuf, XSTR( "Event music is not playing", 213), outbuf_size);
1480         }
1481         else {
1482                 SDL_strlcpy(outbuf, Soundtracks[Current_soundtrack_num].name, outbuf_size);
1483         }
1484 }
1485
1486 // set the current soundtrack based on name
1487 void event_music_set_soundtrack(char *name)
1488 {
1489         int i;
1490
1491         // find the correct index for the event music
1492         for ( i = 0; i < Num_soundtracks; i++ ) {
1493                 if ( !SDL_strcasecmp(name, Soundtracks[i].name) ) {
1494                         Current_soundtrack_num = i;
1495                         break;
1496                 }
1497         }
1498
1499         if ( i == Num_soundtracks ) {
1500                 Current_soundtrack_num = -1;
1501                 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1502         }
1503 }
1504
1505 int event_music_get_spooled_music_index(const char *name)
1506 {
1507         // find the correct index for the event music
1508         for ( int i = 0; i < Num_music_files; i++ ) {
1509                 if ( !SDL_strcasecmp(name, Spooled_music[i].name) ) {
1510                         return i;
1511                 }
1512         }
1513
1514         return -1;
1515 }
1516
1517 // set a score based on name
1518 void event_music_set_score(int score_index, const char *name)
1519 {
1520         SDL_assert(score_index < NUM_SCORES);
1521
1522         // find the correct index for the event music
1523         Mission_music[score_index] = event_music_get_spooled_music_index(name);
1524 }
1525
1526 // reset what sort of music is to be used for this mission
1527 void event_music_reset_choices()
1528 {
1529         Current_soundtrack_num = -1;
1530         mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1531         Mission_music[SCORE_BRIEFING] = -1;
1532         event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1533         event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1534         event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1535         //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1536         //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1537 }
1538
1539 void event_music_hostile_ship_destroyed()
1540 {
1541         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1542 }
1543
1544 #ifndef PLAT_UNIX
1545 #pragma optimize("", on)
1546 #endif