]> icculus.org git repositories - taylor/freespace2.git/blob - src/gamesnd/gamesnd.cpp
use a better multi_sw_ok_to_commit() check
[taylor/freespace2.git] / src / gamesnd / gamesnd.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/GameSnd.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Routines to keep track of which sound files go where
16  *
17  * $Log$
18  * Revision 1.4  2003/05/25 02:30:42  taylor
19  * Freespace 1 support
20  *
21  * Revision 1.3  2002/06/09 04:41:17  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/03 13:34:33  theoddone33
25  * More stuff compiles
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:09  root
28  * Initial import.
29  *
30  * 
31  * 6     7/01/99 11:44a Dave
32  * Updated object sound system to allow multiple obj sounds per ship.
33  * Added hit-by-beam sound. Added killed by beam sound.
34  * 
35  * 5     6/25/99 3:08p Dave
36  * Multiple flyby sounds.
37  * 
38  * 4     5/23/99 8:11p Alanl
39  * Added support for EAX
40  * 
41  * 3     10/23/98 3:51p Dave
42  * Full support for tstrings.tbl and foreign languages. All that remains
43  * is to make it active in Fred.
44  * 
45  * 2     10/07/98 10:52a Dave
46  * Initial checkin.
47  * 
48  * 1     10/07/98 10:48a Dave
49  * 
50  * 39    5/05/98 4:49p Lawrance
51  * Put in code to authenticate A3D, improve A3D support
52  * 
53  * 38    4/25/98 1:25p Lawrance
54  * Make function for playing generic error beep
55  * 
56  * 37    4/18/98 9:12p Lawrance
57  * Added Aureal support.
58  * 
59  * 36    3/29/98 12:56a Lawrance
60  * preload the warp in and explosions sounds before a mission.
61  * 
62  * 35    3/25/98 6:10p Lawrance
63  * Work on DirectSound3D
64  * 
65  * 34    2/22/98 2:48p John
66  * More String Externalization Classification
67  * 
68  * 33    1/17/98 12:33p John
69  * Made the game_busy function be called a constant amount of times per
70  * level load, making the bar prediction easier.
71  * 
72  * 32    1/17/98 12:14p John
73  * Added loading... bar to freespace.
74  * 
75  * 31    1/11/98 11:14p Lawrance
76  * Preload sounds that we expect will get played.
77  * 
78  * 30    12/24/97 8:54p Lawrance
79  * Integrating new popup code
80  * 
81  * 29    12/19/97 3:44p Mike
82  * Fix parse code.  Would improperly read a number through a comma.  Lots
83  * of ships.tbl problems.
84  * 
85  * 28    12/01/97 5:25p Hoffoss
86  * Routed interface sound playing through a special function that will
87  * only allow one instance of the sound to play at a time, avoiding
88  * over-mixing problems.
89  * 
90  * 27    11/20/97 1:06a Lawrance
91  * Add Master_voice_volume, make voices play back at correctly scaled
92  * volumes
93  * 
94  * 26    10/17/97 1:36p Lawrance
95  * load/unload interface sounds
96  * 
97  * 25    10/14/97 11:35p Lawrance
98  * change snd_load parameters
99  * 
100  * 24    7/05/97 1:46p Lawrance
101  * improve robustness of gameplay and interface sound loading/unloading
102  * 
103  * 23    6/09/97 11:50p Lawrance
104  * integrating DirectSound3D
105  * 
106  * 22    6/08/97 5:59p Lawrance
107  * flag sounds as 3D
108  * 
109  * 21    6/05/97 11:25a Lawrance
110  * use sound signatures to ensure correct sound is loaded
111  * 
112  * 20    6/05/97 1:07a Lawrance
113  * changes to support sound interface
114  * 
115  * 19    6/04/97 1:18p Lawrance
116  * added hooks for shield impacts
117  * 
118  * 18    6/02/97 1:50p Lawrance
119  * supporting new format of sounds in table
120  * 
121  * 17    5/14/97 9:54a Lawrance
122  * supporting mission-specific briefing music
123  * 
124  * 16    5/08/97 1:56p Lawrance
125  * supporting ship-specific engine sounds
126  * 
127  * 15    5/06/97 9:36a Lawrance
128  * added support for min and max distances for 3d sounds
129  * 
130  * 14    4/23/97 5:19p Lawrance
131  * split up misc sounds into: gamewide, ingame, and interface
132  * 
133  * 13    4/20/97 11:48a Lawrance
134  * added array of filenames for misc sounds.  Will be useful if we want to
135  * unload then re-load sounds
136  * 
137  * 12    4/20/97 11:19a Lawrance
138  * sndman_ interface obsolete.  Using snd_ functions to load, play, and
139  * manage static sound fx
140  * 
141  * 11    4/18/97 4:31p Mike
142  * Add support for default volume levels.
143  * 
144  * 10    3/20/97 11:04a Lawrance
145  * using incorrect constant when loading music filenames
146  * 
147  * 9     3/19/97 5:53p Lawrance
148  * integrating new Misc_sounds[] array (replaces old Game_sounds
149  * structure)
150  * 
151  * 8     3/17/97 3:47p Mike
152  * Homing missile lock sound.
153  * More on AI ships firing missiles.
154  * 
155  * 7     3/10/97 8:54a Lawrance
156  * added gamesnd_init_looping_sounds()
157  * 
158  * 6     2/28/97 8:41a Lawrance
159  * added afterburner engage and burn sounds
160  * 
161  * 5     2/14/97 12:37a Lawrance
162  * added hooks to play docking/undocking sounds
163  * 
164  * 4     2/13/97 12:03p Lawrance
165  * hooked in throttle sounds
166  * 
167  * 3     2/05/97 10:35a Lawrance
168  * supporting spooled music at menus, briefings, credits etc.
169  * 
170  * 2     1/20/97 7:58p John
171  * Fixed some link errors with testcode.
172  * 
173  * 1     1/20/97 7:08p John
174  *
175  * $NoKeywords: $
176  */
177
178 #include "pstypes.h"
179 #include "gamesnd.h"
180 #include "sound.h"
181 #include "parselo.h"
182 #include "localize.h"
183
184 // Global array that holds data about the gameplay sound effects.
185 game_snd Snds[MAX_GAME_SOUNDS];
186
187 // Global array that holds data about the interface sound effects.
188 game_snd Snds_iface[MAX_INTERFACE_SOUNDS];
189 int Snds_iface_handle[MAX_INTERFACE_SOUNDS];
190
191 // flyby sounds - 2 for each species (fighter and bomber flybys)
192 game_snd Snds_flyby[MAX_SPECIES_NAMES][2];
193
194
195 void gamesnd_play_iface(int n)
196 {
197         if (Snds_iface_handle[n] >= 0)
198                 snd_stop(Snds_iface_handle[n]);
199
200         Snds_iface_handle[n] = snd_play(&Snds_iface[n]);
201 }
202
203 // load in sounds that we expect will get played
204 //
205 // The method currently used is to load all those sounds that have the hardware flag
206 // set.  This works well since we don't want to try and load hardware sounds in on the
207 // fly (too slow).
208 void gamesnd_preload_common_sounds()
209 {
210         int             i;
211         game_snd        *gs;
212
213         for ( i = 0; i < MAX_GAME_SOUNDS; i++ ) {
214                 gs = &Snds[i];
215                 if ( gs->filename[0] != 0 && SDL_strcasecmp(gs->filename, NOX("none.wav")) ) {
216                         if ( gs->preload ) {
217                                 gs->id = snd_load(gs);
218                         }
219                 }
220                 game_busy();            // Animate loading cursor... does nothing if loading screen not active.
221         }
222 }
223
224 // -------------------------------------------------------------------------------------------------
225 // gamesnd_load_gameplay_sounds()
226 //
227 // Load the ingame sounds into memory
228 //
229 void gamesnd_load_gameplay_sounds()
230 {
231         int             i;
232         game_snd        *gs;
233
234         for ( i = 0; i < MAX_GAME_SOUNDS; i++ ) {
235                 gs = &Snds[i];
236                 if ( gs->filename[0] != 0 && SDL_strcasecmp(gs->filename, NOX("none.wav")) ) {
237                         gs->id = snd_load(gs);
238                 }
239         }
240 }
241
242 // -------------------------------------------------------------------------------------------------
243 // gamesnd_unload_gameplay_sounds()
244 //
245 // Unload the ingame sounds from memory
246 //
247 void gamesnd_unload_gameplay_sounds()
248 {
249         int             i;
250         game_snd        *gs;
251
252         for ( i = 0; i < MAX_GAME_SOUNDS; i++ ) {
253                 gs = &Snds[i];
254                 if ( gs->id != -1 ) {
255                         snd_unload( gs->id );
256                         gs->id = -1;
257                 }
258         }       
259 }
260
261 // -------------------------------------------------------------------------------------------------
262 // gamesnd_load_interface_sounds()
263 //
264 // Load the interface sounds into memory
265 //
266 void gamesnd_load_interface_sounds()
267 {
268         int             i;
269         game_snd        *gs;
270
271         for ( i = 0; i < MAX_INTERFACE_SOUNDS; i++ ) {
272                 gs = &Snds_iface[i];
273                 if ( gs->filename[0] != 0 && SDL_strcasecmp(gs->filename, NOX("none.wav")) ) {
274                         gs->id = snd_load(gs);
275                 }
276         }
277 }
278
279 // -------------------------------------------------------------------------------------------------
280 // gamesnd_unload_interface_sounds()
281 //
282 // Unload the interface sounds from memory
283 //
284 void gamesnd_unload_interface_sounds()
285 {
286         int             i;
287         game_snd        *gs;
288
289         for ( i = 0; i < MAX_INTERFACE_SOUNDS; i++ ) {
290                 gs = &Snds_iface[i];
291                 if ( gs->id != -1 ) {
292                         snd_unload( gs->id );
293                         gs->id = -1;
294                         gs->id_sig = -1;
295                 }
296         }
297 }
298
299 // -------------------------------------------------------------------------------------------------
300 // gamesnd_parse_line()
301 //
302 // Parse a sound effect line
303 //
304 void gamesnd_parse_line(game_snd *gs, const char *tag)
305 {
306         int is_3d;
307
308         required_string(tag);
309         stuff_int(&gs->sig);
310         stuff_string(gs->filename, F_NAME, ",");
311         if ( !SDL_strcasecmp(gs->filename,NOX("empty")) ) {
312                 gs->filename[0] = 0;
313                 advance_to_eoln(NULL);
314                 return;
315         }
316         Mp++;
317         stuff_int(&gs->preload);
318         stuff_float(&gs->default_volume);
319         stuff_int(&is_3d);
320         if ( is_3d ) {
321                 gs->flags |= GAME_SND_USE_3D;
322                 stuff_int(&gs->min);
323                 stuff_int(&gs->max);
324         }
325         advance_to_eoln(NULL);
326 }
327
328 // -------------------------------------------------------------------------------------------------
329 // gamesnd_parse_soundstbl() will parse the sounds.tbl file, and load the specified sounds.
330 //
331 //
332 void gamesnd_parse_soundstbl()
333 {
334         int             num_game_sounds = 0;
335         int             num_iface_sounds = 0;
336
337         // open localization
338         lcl_ext_open();
339
340         gamesnd_init_sounds();
341
342         try {
343                 read_file_text("sounds.tbl");
344                 reset_parse();          
345
346                 // Parse the gameplay sounds section
347                 required_string("#Game Sounds Start");
348                 while (required_string_either("#Game Sounds End","$Name:")) {
349                         SDL_assert( num_game_sounds < MAX_GAME_SOUNDS);
350                         gamesnd_parse_line( &Snds[num_game_sounds], "$Name:" );
351                         num_game_sounds++;
352                 }
353                 required_string("#Game Sounds End");
354
355                 // Parse the interface sounds section
356                 required_string("#Interface Sounds Start");
357                 while (required_string_either("#Interface Sounds End","$Name:")) {
358                         SDL_assert( num_iface_sounds < MAX_INTERFACE_SOUNDS);
359                         gamesnd_parse_line(&Snds_iface[num_iface_sounds], "$Name:");
360                         num_iface_sounds++;
361                 }
362                 required_string("#Interface Sounds End");
363
364 #ifndef MAKE_FS1
365                 // parse flyby sound section
366                 required_string("#Flyby Sounds Start");
367
368                 // read 2 terran sounds
369                 gamesnd_parse_line(&Snds_flyby[SPECIES_TERRAN][0], "$Terran:");
370                 gamesnd_parse_line(&Snds_flyby[SPECIES_TERRAN][1], "$Terran:");
371
372                 // 2 vasudan sounds
373                 gamesnd_parse_line(&Snds_flyby[SPECIES_VASUDAN][0], "$Vasudan:");
374                 gamesnd_parse_line(&Snds_flyby[SPECIES_VASUDAN][1], "$Vasudan:");
375
376                 gamesnd_parse_line(&Snds_flyby[SPECIES_SHIVAN][0], "$Shivan:");
377                 gamesnd_parse_line(&Snds_flyby[SPECIES_SHIVAN][1], "$Shivan:");
378
379                 required_string("#Flyby Sounds End");
380 #endif
381         } catch (parse_error_t rval) {
382                 Error(LOCATION, "Unable to parse sounds.tbl!  Code = %i.\n", (int)rval);
383         }
384
385         // close localization
386         lcl_ext_close();
387 }
388
389
390 // -------------------------------------------------------------------------------------------------
391 // gamesnd_init_struct()
392 //
393 void gamesnd_init_struct(game_snd *gs)
394 {
395         gs->filename[0] = 0;
396         gs->id = -1;
397         gs->id_sig = -1;
398 //      gs->is_3d = 0;
399 //      gs->use_ds3d = 0;
400         gs->flags = 0;
401 }
402
403 // -------------------------------------------------------------------------------------------------
404 // gamesnd_init_sounds() will initialize the Snds[] and Snds_iface[] arrays
405 //
406 void gamesnd_init_sounds()
407 {
408         int             i;
409
410         // init the gameplay sounds
411         for ( i = 0; i < MAX_GAME_SOUNDS; i++ ) {
412                 gamesnd_init_struct(&Snds[i]);
413         }
414
415         // init the interface sounds
416         for ( i = 0; i < MAX_INTERFACE_SOUNDS; i++ ) {
417                 gamesnd_init_struct(&Snds_iface[i]);
418                 Snds_iface_handle[i] = -1;
419         }
420 }
421
422 // callback function for the UI code to call when the mouse first goes over a button.
423 void common_play_highlight_sound()
424 {
425         gamesnd_play_iface(SND_USER_OVER);
426 }
427
428 void gamesnd_play_error_beep()
429 {
430         gamesnd_play_iface(SND_GENERAL_FAIL);
431 }
432