1 #ifdef NEW_SOUND
2 #include <ctype.h>
3 #include <string.h>
4 #include <SDL.h>
5 #include <SDL_thread.h>
6 #include <math.h>
7 #include "sound.h"
8 #include "asc.h"
9 #include "draw_scene.h"
10 #include "elconfig.h"
11 #include "errors.h"
12 #include "init.h"
13 #include "lights.h"
14 #include "main.h"
15 #include "map.h"
16 #include "misc.h"
17 #include "multiplayer.h"
18 #include "translate.h"
19 #include "weather.h"
20 #include "2d_objects.h"
21 #include "3d_objects.h"
22 #include "spells.h"
23 #include "tiles.h"
24 #include "actors.h"
25 #include "interface.h"
26 #include "io/elpathwrapper.h"
27 #include "io/elfilewrapper.h"
28 #include "threads.h"
29
30 #if defined _EXTRA_SOUND_DEBUG && OSX
31 #define printf LOG_ERROR
32 #endif
33
34 #define OGG_BUFFER_SIZE (1048576)
35 #define STREAM_BUFFER_SIZE (4096 * 16)
36 #define SLEEP_TIME 300 // Time to give CPU to other processes between loops of update_streams()
37
38 #ifdef _EXTRA_SOUND_DEBUG
39 #include <unistd.h>
40 static char last_file[50] = "";
41 static char last_func[50] = "";
42 static int last_line = 0;
43 #define LOCK_SOUND_LIST() \
44 { \
45 while (SDL_TryLockMutex(sound_list_mutex) != 0) \
46 { \
47 printf("lock loop in %s, %s:%d - last lock: %s, %s:%d\n", __FILE__, __FUNCTION__, __LINE__, last_file, last_func, last_line); \
48 usleep(100); \
49 } \
50 safe_strncpy(last_file, __FILE__, strlen(last_file)); \
51 safe_strncpy(last_func, __FUNCTION__, strlen(last_func)); \
52 last_line = __LINE__; \
53 }
54 #define UNLOCK_SOUND_LIST() { CHECK_AND_UNLOCK_MUTEX(sound_list_mutex); }
55 #else // _EXTRA_SOUND_DEBUG
56 #define LOCK_SOUND_LIST() CHECK_AND_LOCK_MUTEX(sound_list_mutex);
57 #define UNLOCK_SOUND_LIST() CHECK_AND_UNLOCK_MUTEX(sound_list_mutex);
58 #endif // _EXTRA_SOUND_DEBUG
59
60 #define MAX_FILENAME_LENGTH 80
61 #define MAX_BUFFERS 64
62 #define MAX_SOURCES 16
63 #define ABS_MAX_SOURCES 64 // Define an absolute maximum for the sources (the size of the array)
64
65 #define MAX_SOUNDS 200
66
67 #define MAX_STREAMS 7 // 1 music stream and up to 3 each for bg and crowds
68 #define STREAM_TYPE_NONE -1
69 #define STREAM_TYPE_SOUNDS 0
70 #define STREAM_TYPE_MUSIC 1
71 #define STREAM_TYPE_CROWD 2
72 #define NUM_STREAM_BUFFERS 4
73
74 #define MAX_PLAYLIST_ENTRIES 50
75 #define MAX_PLAYLIST_FILENAME 64
76
77 #define MAX_SOUND_FILES (MAX_SOUNDS * MAX_SOUND_VARIANTS * num_STAGES) // The total number of files if every part of every
78 // variant of every sound had a different file
79 #define MAX_BACKGROUND_DEFAULTS 8 // Maximum number of global default backgrounds
80 #define MAX_MAP_BACKGROUND_DEFAULTS 4 // Maximum number of default backgrounds per map
81 #define MAX_SOUND_MAP_NAME_LENGTH 60 // Maximum length of the name of the map
82 #define MAX_SOUND_VARIANTS 10 // Maximum number of different sounds allowed for the one sound type
83 #define MAX_SOUND_MAP_BOUNDARIES 20 // Maximum number of boundary sets per map
84 #define MAX_SOUND_WALK_BOUNDARIES 40 // Maximum number of walk boundary sets per map
85 #define MAX_ITEM_SOUND_IMAGE_IDS 30 // Maximum number of image id's linked to an item sound def
86 #define MAX_SOUND_TILE_TYPES 20 // Maximum number of different tile types
87 #define MAX_SOUND_TILES 30 // Maximum number of different tiles for a tile type
88 #define MAX_SOUND_TILES_SOUNDS 5 // Maximum number of different sound types for a tile type
89 #define MAX_SERVER_SOUNDS 10 // Maximum number of server sounds - keep up to date with the snd_xxx #defs client_serv.h
90
91 #define MAX_SOUND_MAPS 150 // This value is the maximum number of maps sounds can be defined for
92 // (Roja has suggested 150 is safe for now)
93 #define MAX_SOUND_EFFECTS 60 // This value should equal the max special_effect_enum
94 #define MAX_SOUND_PARTICLES 20 // This value should equal the number of particle effects
95 #define MAX_SOUND_ITEMS 5 // This is the number of sounds defined for "Use item" sfx
96
97 #define MAX_SOUND_WARNINGS 50 // The number of user defined sound warnings
98 #define MAX_SND_WARNING_STRING 256 // Max size of warning string
99
100 typedef enum
101 {
102 STAGE_UNUSED = -1, STAGE_INTRO, STAGE_MAIN, STAGE_OUTRO, num_STAGES, STAGE_STREAM
103 } SOUND_STAGE;
104
105 typedef struct _source_list
106 {
107 ALuint source; // The physical address of this source (not the array id of source_data as that changes)
108 struct _source_list *next;
109 struct _source_list *last;
110 } source_list;
111
112 typedef struct
113 {
114 char file_path[MAX_FILENAME_LENGTH]; // Where to load the file from
115 int sample_num; // Sample array ID (if loaded)
116 } sound_file;
117
118 typedef struct
119 {
120 sound_file *part[num_STAGES]; // Pointers to the files used for each stage
121 float gain; // The gain of this sound (default 1.0)
122 // The same sample may be defined under 2 sound names, with different gains.
123 } sound_variants;
124
125 typedef struct
126 {
127 char name[MAX_SOUND_NAME_LENGTH];
128 sound_variants variant[MAX_SOUND_VARIANTS];
129 int num_variants;
130 int stereo; // 1 is stereo, 0 is mono (default mono)
131 float distance; // Distance it can be heard, in meters
132 int positional; // 1=positional, 0=omni (default positional)
133 int loops; // 0=infinite, otherwise the number of loops (default 1)
134 int fadeout_time; // In milliseconds, only for omni sounds that loop. (default 0) -- NOT USED
135 int echo_delay; // The value is the echo in MS. If 0, no echo (default 0) -- NOT USED
136 int echo_volume; // In percent, 0 means no sound, 100 means as loud as the original sound (default 50) -- NOT USED
137 int time_of_the_day_flags; // Bits 0-11 set each 1/2 hour of the 6-hour day (default 0xffff)
138 unsigned int priority; // If there are too many sounds to be played, highest value priority get culled (default 5)
139 int type; // The type of sound - environmental, actor, walking etc. (default Enviro)
140 } sound_type;
141
142 typedef struct
143 {
144 ALuint buffer; // If the sample is loaded, a buffer ID to play it.
145 ALenum format;
146 ALsizei size; // Size of the sound data in bytes
147 ALfloat freq; // Frequency
148 ALint channels; // Number of sound channels
149 ALint bits; // Bits per channel per sample
150 int length; // Duration in milliseconds
151 source_list *sources; // List of sources using this sample
152 } sound_sample;
153
154 typedef struct
155 {
156 int sound; // The ID of the sound type
157 int variant; // The variant of the sound type being played
158 int x;
159 int y;
160 int loaded; // Has this sound been loaded into a buffer
161 int playing; // Is this sound loaded into a source and currently playing
162 float base_gain; // The initial gain (before adjustments for weather and sound type volume etc)
163 float cur_gain; // The last actual gain. If the calculated new gain is different then do an alSourcef command
164 unsigned int cookie;
165 int lifetime; // The length of time in ms the sound has existed
166 } sound_loaded;
167
168 typedef struct
169 {
170 ALuint source; // A handle for the source
171 int priority; // Include this here for streams and to force a priority if needed
172 int play_duration;
173 int loaded_sound; // Sound ID loaded into this source (Not used for streams)
174 SOUND_STAGE current_stage; // Set as STAGE_STREAMS for streams
175 unsigned int cookie;
176 int sample[num_STAGES]; // The samples currently in use by this source
177 } source_data;
178
179 typedef struct
180 {
181 int sound;
182 int time_of_day_flags; // As for sound time_of_day_flags
183 int map_type; // At the moment, only 0 (outside) and 1 (dungeon). Checked against the dungeon flag.
184 } background_default;
185
186 typedef struct
187 {
188 int x;
189 int y;
190 double a; // Angle of the line between this point and the next (not used for outer bounding rect)
191 } bound_point;
192
193 typedef struct
194 {
195 int bg_sound;
196 int crowd_sound;
197 int time_of_day_flags; // As for sound time_of_day_flags
198 int is_default; // There can be up to 4 defaults for any one map, with unique times of day
199 // Coords are ignored if is_default set.
200 bound_point p[4]; // Details of this point and its corresponding angle
201 int int_point; // Index of the internal point or -1 for no internal point
202 bound_point o[2]; // Outer bounding rectangle (0 = lower left, 1 = upper right)
203 } map_sound_boundary_def;
204
205 typedef struct
206 {
207 int id;
208 char file_name[256];
209 char name[MAX_SOUND_MAP_NAME_LENGTH]; // This isn't used, it is simply helpful when editing the config
210 map_sound_boundary_def boundaries[MAX_SOUND_MAP_BOUNDARIES]; // This is the boundaries for backgound and crowd sounds
211 map_sound_boundary_def walk_boundaries[MAX_SOUND_WALK_BOUNDARIES]; // This is the boundaries for walking sounds (to fake 3d objects)
212 int num_boundaries;
213 int num_walk_boundaries;
214 int defaults[MAX_MAP_BACKGROUND_DEFAULTS]; // ID of the default boundaries
215 int num_defaults;
216 } map_sound_data;
217
218 typedef struct
219 {
220 int id; // ID's in the config should match those of special_effect_enum
221 int sound;
222 } effect_sound_data;
223
224 typedef struct
225 {
226 char file[30]; // This is the filename (without extension) for a particle
227 int sound;
228 } particle_sound_data;
229
230 typedef struct
231 {
232 int image_id[MAX_ITEM_SOUND_IMAGE_IDS];
233 int num_imageids;
234 int sound;
235 } item_sound_data;
236
237 typedef struct
238 {
239 char actor_types[1024];
240 int sound;
241 } tile_sounds;
242
243 typedef struct
244 {
245 int tile_type[MAX_SOUND_TILES];
246 int num_tile_types;
247 tile_sounds sounds[MAX_SOUND_TILES_SOUNDS];
248 int num_sounds;
249 int default_sound;
250 } tile_sound_data;
251
252 typedef struct
253 {
254 int sound;
255 char string[MAX_SND_WARNING_STRING];
256 } sound_warnings;
257
258 typedef struct
259 {
260 int type; // The type of this stream
261 ALuint source; // The source for this stream
262 unsigned int cookie; // A cookie for the source
263 ALuint buffers[NUM_STREAM_BUFFERS]; // The stream buffers
264 OggVorbis_File stream; // The Ogg file handle for this stream
265 int stream_opened; // If try, its OK to call ov_clear()
266 vorbis_info * info; // The Ogg info for this file handle
267 int fade; // The current fade value for this stream
268 int fade_length; // The length of the fade in or out (number of update_stream loops)
269 int processed; // Processed value (temporary storage)
270 int playing; // Is this stream currently playing
271 int sound; // The sound this stream is playing (not used for music)
272 int variant; // The variant of the sound playing (not used for music)
273 int is_default; // Is this sound a default sound for this type (not used for music)
274 map_sound_boundary_def * boundary; // This is a pointer to the boundary in use
275 } stream_data;
276
277 typedef struct {
278 char file_name[MAX_PLAYLIST_FILENAME];
279 int min_x;
280 int max_x;
281 int min_y;
282 int max_y;
283 int time;
284 } playlist_entry;
285
286
287 int have_sound = 0;
288 int have_music = 0;
289 int no_sound = 0;
290 int sound_on = 1;
291 int music_on = 1;
292 Uint8 inited = 0;
293
294 SDL_Thread *sound_streams_thread = NULL;
295 SDL_mutex *sound_list_mutex = NULL;
296
297 stream_data * music_stream = NULL;
298 stream_data *streams = NULL;
299
300 ALfloat sound_gain = 1.0f;
301 ALfloat music_gain = 1.0f;
302 ALfloat crowd_gain = 1.0f;
303 ALfloat enviro_gain = 1.0f;
304 ALfloat actor_gain = 1.0f;
305 ALfloat walking_gain = 1.0f;
306 ALfloat gamewin_gain = 1.0f;
307 ALfloat client_gain = 1.0f;
308 ALfloat warnings_gain = 1.0f;
309
310 int used_sources = 0; // the number of sources currently playing
311
312 char sound_device[30] = ""; // Set up a string to store the names of the selected sound device
313 char sound_devices[1000] = ""; // Set up a string to store the names of the available sound devices
314 int max_sources = MAX_SOURCES; // Initialise our local maximum number of sources to the default
315 int max_streams = MAX_STREAMS; // Initialise our local maximum number of streams to the default
316
317 int num_types = 0; // Number of distinct sound types
318 int num_samples = 0; // Number of actual sound files - a sound type can have > 1 sample
319 int num_sound_files = 0; // Number of individual sound files
320 int num_sounds = 0; // Number of sounds in the sounds_list
321 int sound_num_background_defaults = 0; // Number of default background sounds
322 int sound_num_maps = 0; // Number of maps we have sounds for
323 int sound_num_effects = 0; // Number of effects we have sounds for
324 int sound_num_particles = 0; // Number of particles we have sounds for
325 int sound_num_items = 0; // Number of "Use item" actions we have sounds for
326 int sound_num_tile_types = 0; // Number of tile type groups we have sounds for
327 int num_sound_warnings = 0; // Number of string warnings
328 int have_sound_config = 0; // true if the sound config file was found
329 static int must_restart_spell_sounds = 0; // true if sounds have been stopped, triggeres an attempt to restart
330
331 int snd_cur_map = -1;
332 int cur_boundary = 0;
333
334 unsigned int next_cookie = 1; // Each playing source is identified by a unique cookie.
335 sound_loaded *sounds_list = NULL; // The loaded sounds
336 source_data *sound_source_data = NULL; // The active (playing) sources
337 sound_type *sound_type_data = NULL; // Configuration of the sound types
338 sound_sample *sound_sample_data = NULL; // Buffer data for each sample
339 sound_file *sound_files = NULL; // File names for each individual sound file
340 background_default *sound_background_defaults = NULL;// Default background sounds
341 // (must have non-overlapping time of day flags)
342 int crowd_default = -1; // Default sound for crowd effects
343 int walking_default = -1; // Default sound for walking
344 map_sound_data *sound_map_data = NULL; // Data for map sfx
345 effect_sound_data *sound_effect_data = NULL; // Data for effect sfx
346 particle_sound_data *sound_particle_data = NULL; // Data for particle sfx
347 item_sound_data *sound_item_data = NULL; // Data for item sfx
348 tile_sound_data *sound_tile_data = NULL; // Data for tile (walking) sfx
349 int *server_sound = NULL; // Map of server sounds to sound def ids
350 int *sound_spell_data = NULL; // Map of id's for spells-that-affect-you to sounds
351 sound_warnings *warnings_list = NULL; // List of strings to monitor for warning sounds
352 int afk_snd_warning = 0; // Whether to play a sound on receiving a message while AFK
353
354 playlist_entry *playlist = NULL;
355 int loop_list = 1;
356 int list_pos = -1;
357
358
359 /* *** Declare some local functions ****
360 * These functions shouldn't need to be accessed outside sound.c
361 */
362
363 /* Ogg handling */
364 int load_ogg_file(char *file_name, OggVorbis_File *oggFile);
365 int stream_ogg_file(char *file_name, stream_data * stream, int numBuffers);
366 int stream_ogg(ALuint buffer, OggVorbis_File * inStream, vorbis_info * info);
367 /* Stream handling */
368 static char * get_stream_type(int type);
369 void play_stream(int sound, stream_data * stream, ALfloat gain);
370 int start_stream(stream_data * stream);
371 void stop_stream(stream_data * stream);
372 void reset_stream(stream_data * stream);
373 int init_sound_stream(stream_data * stream, int type, int priority);
374 void destroy_stream(stream_data * stream);
375 int add_stream(int sound, int type, int boundary);
376 int check_for_valid_stream_sound(int tx, int ty, int type);
377 void check_for_new_streams(int tx, int ty);
378 int process_stream(stream_data * stream, ALfloat gain, int * sleep);
379 int check_stream(stream_data * stream, int day_time, int tx, int ty);
380 /* Music functions */
381 void play_song(int list_pos);
382 void find_next_song(int tx, int ty, int day_time);
383
384 /* Source functions */
385 source_data * get_available_source(int priority);
386 source_data *insert_sound_source_at_index(unsigned int index);
387 void release_source(source_data *pSource, int index);
388 int stop_sound_source_at_index(int index);
389 void set_sound_gain(source_data * pSource, int loaded_sound_num, float initial_gain);
390 /* Sample functions */
391 int ensure_sample_loaded(char * in_filename);
392 int load_samples(sound_type * pType);
393 void release_sample(int sample_num);
394 void unload_sample(int sample_num);
395 /* Individual sound functions */
396 int play_sound(int loaded_sound_num, int x, int y, float initial_gain);
397 unsigned int get_next_cookie();
398 int get_loaded_sound_num();
399 void unload_sound(int index);
400 /* General functions */
401 int get_3d_obj_walk_sound(char * filename);
402 int get_2d_obj_walk_sound(char * filename);
403 int get_boundary_walk_sound(int x_pos, int y_pos);
404 int get_tile_sound(int tile_type, char * actor_type);
405 int find_sound_from_cookie(unsigned int cookie);
406 int time_of_day_valid(int flags);
407 int sound_bounds_check(int x, int y, map_sound_boundary_def * bounds);
408 int test_bounds_angles(int x, int y, int point, map_sound_boundary_def * bounds);
409 double calculate_bounds_angle(int x, int y, int point, map_sound_boundary_def * bounds);
410 #ifdef DEBUG_MAP_SOUND
411 void print_sound_boundary_coords(const char *mapname);
412 #endif // DEBUG_MAP_SOUND
413 /* Init functions */
414 void parse_snd_devices(ALCchar * in_array, char * sound_devs);
415 static void clear_playlist(void);
416
417
418 /**************************
419 * SOUND OPTION FUNCTIONS *
420 **************************/
421
turn_sound_on()422 void turn_sound_on()
423 {
424 int i, state = 0;
425 ALuint source, error;
426
427 if (!video_mode_set)
428 return; // Don't load the config until we have video (so we don't load before the loading screen)
429 if (!inited)
430 init_sound();
431 if (!have_sound)
432 return;
433 LOCK_SOUND_LIST();
434 sound_on = 1;
435 for (i = 0; i < used_sources; i++)
436 {
437 source = sound_source_data[i].source;
438 alGetSourcei(source, AL_SOURCE_STATE, &state);
439 if (state == AL_PAUSED)
440 alSourcePlay(source);
441 }
442 UNLOCK_SOUND_LIST();
443 if ((error=alGetError()) != AL_NO_ERROR)
444 {
445 #ifdef _EXTRA_SOUND_DEBUG
446 printf("Error turning sound on\n");
447 #endif // _EXTRA_SOUND_DEBUG
448 }
449 must_restart_spell_sounds = 1;
450 }
451
turn_sound_off()452 void turn_sound_off()
453 {
454 int i = 0;
455 ALuint error;
456 if (!inited)
457 return;
458 if (!have_music || !music_on)
459 {
460 destroy_sound();
461 return;
462 }
463 LOCK_SOUND_LIST();
464 sound_on = 0;
465 while (i < used_sources)
466 {
467 if (sound_source_data[i].current_stage == STAGE_STREAM)
468 {
469 i++; // This source is being used by a stream and handled lower down so ignore
470 continue;
471 }
472 #ifdef _EXTRA_SOUND_DEBUG
473 printf("Removing source with index %d\n", i);
474 #endif //_EXTRA_SOUND_DEBUG
475 stop_sound_source_at_index(0);
476 continue;
477 }
478 for (i = 0; i < max_streams; i++)
479 {
480 if (streams[i].type != STREAM_TYPE_MUSIC)
481 {
482 destroy_stream(&streams[i]);
483 }
484 }
485 UNLOCK_SOUND_LIST();
486 if ((error=alGetError()) != AL_NO_ERROR)
487 {
488 #ifdef _EXTRA_SOUND_DEBUG
489 printf("Error turning sound off\n");
490 #endif //_EXTRA_SOUND_DEBUG
491 }
492 }
493
turn_music_on()494 void turn_music_on()
495 {
496 if (!video_mode_set)
497 return; // Don't load the config until we have video (so we don't load before the loading screen)
498 music_on = 1; // Set this here so if ness we will init the sound
499 if (!inited)
500 {
501 init_sound();
502 }
503 if (!have_music)
504 return;
505 get_map_playlist();
506 }
507
turn_music_off()508 void turn_music_off()
509 {
510 if (!inited)
511 return;
512 if (!have_sound || !sound_on)
513 {
514 destroy_sound();
515 return;
516 }
517 if (!have_music)
518 return;
519
520 LOCK_SOUND_LIST();
521 music_on = 0;
522 if (sound_streams_thread != NULL)
523 {
524 if (music_stream)
525 {
526 destroy_stream(music_stream);
527 }
528 }
529 UNLOCK_SOUND_LIST();
530 }
531
toggle_sounds(int * var)532 void toggle_sounds(int *var)
533 {
534 *var = !*var;
535 if (!sound_on) {
536 turn_sound_off();
537 } else {
538 turn_sound_on();
539 }
540 }
541
toggle_music(int * var)542 void toggle_music(int * var) {
543 *var = !*var;
544 if (!music_on) {
545 turn_music_off();
546 } else {
547 turn_music_on();
548 }
549 }
550
disable_sound(int * var)551 void disable_sound(int *var)
552 {
553 *var = !*var;
554 if (no_sound) {
555 destroy_sound();
556 clear_sound_data();
557 have_sound_config = 0;
558 } else {
559 if (sound_on)
560 turn_sound_on();
561 if (music_on)
562 turn_music_on();
563 }
564 }
565
566
567 /************************
568 * OGG VORBIS FUNCTIONS *
569 ************************/
570
ogg_error(int code)571 void ogg_error(int code)
572 {
573 switch(code)
574 {
575 case OV_EREAD:
576 LOG_ERROR(snd_media_read); break;
577 case OV_ENOTVORBIS:
578 LOG_ERROR(snd_media_notvorbis); break;
579 case OV_EVERSION:
580 LOG_ERROR(snd_media_ver_mismatch); break;
581 case OV_EBADHEADER:
582 LOG_ERROR(snd_media_invalid_header); break;
583 case OV_EFAULT:
584 LOG_ERROR(snd_media_internal_error); break;
585 case OV_EOF:
586 LOG_ERROR(snd_media_eof); break;
587 case OV_HOLE:
588 LOG_ERROR(snd_media_hole); break;
589 case OV_EINVAL:
590 LOG_ERROR(snd_media_einval); break;
591 case OV_EBADLINK:
592 LOG_ERROR(snd_media_ebadlink); break;
593 case OV_FALSE:
594 LOG_ERROR(snd_media_false); break;
595 case OV_ENOSEEK:
596 LOG_ERROR(snd_media_enoseek); break;
597 default:
598 LOG_ERROR(snd_media_ogg_error);
599 }
600 }
601
load_ogg_file(char * file_name,OggVorbis_File * oggFile)602 int load_ogg_file(char * file_name, OggVorbis_File *oggFile)
603 {
604 FILE *file;
605 int result = 0;
606
607 file = my_fopen(file_name, "rb");
608
609 if (file == NULL)
610 {
611 return 0;
612 }
613
614 #ifndef _MSC_VER // MS's compiler breaks things with files opened from different DLL's
615 result = ov_open(file, oggFile, NULL, 0);
616 #else // !_MSC_VER
617 result = ov_open_callbacks(file, oggFile, NULL, 0, OV_CALLBACKS_DEFAULT);
618 #endif
619 if (result < 0)
620 {
621 LOG_ERROR("Error opening ogg file: %s. Ogg error: %d\n", file_name, result);
622 fclose(file);
623 return 0;
624 }
625
626 return 1;
627 }
628
stream_ogg_file(char * in_filename,stream_data * stream,int numBuffers)629 int stream_ogg_file(char * in_filename, stream_data * stream, int numBuffers)
630 {
631 int result, more_stream = 0, i;
632 char filename[200];
633
634 stop_stream(stream);
635 if (stream->stream_opened)
636 {
637 ov_clear(&stream->stream);
638 stream->stream_opened = 0;
639 }
640
641 // Add the datadir to the input filename and try to open it
642 safe_strncpy(filename, datadir, sizeof(filename));
643 safe_strcat(filename, in_filename, sizeof(filename));
644 result = load_ogg_file(filename, &stream->stream);
645 if (!result) {
646 LOG_ERROR("Error loading ogg file: %s\n", filename);
647 return -1;
648 }
649 stream->stream_opened = 1;
650
651 stream->info = ov_info(&stream->stream, -1);
652 for (i = 0; i < numBuffers; i++)
653 {
654 more_stream = stream_ogg(stream->buffers[i], &stream->stream, stream->info);
655 if (!more_stream)
656 {
657 LOG_ERROR("Error playing ogg file: %s\n", filename);
658 return more_stream; // There was an error, probably too little data to fill the buffers
659 }
660 }
661
662 alSourceQueueBuffers(stream->source, numBuffers, stream->buffers);
663 result = start_stream(stream);
664
665 return result;
666 }
667
stream_ogg(ALuint buffer,OggVorbis_File * inStream,vorbis_info * info)668 int stream_ogg(ALuint buffer, OggVorbis_File * inStream, vorbis_info * info)
669 {
670 char data[STREAM_BUFFER_SIZE];
671 int size = 0;
672 int section = 0;
673 int result = 0;
674 int error = 0;
675 char str[256];
676 ALenum format;
677
678 // Clear any previous AL errors
679 if ((error = alGetError()) != AL_NO_ERROR) { }
680
681 size = 0;
682 while (size < STREAM_BUFFER_SIZE)
683 {
684 #ifndef EL_BIG_ENDIAN
685 result = ov_read(inStream, data + size, STREAM_BUFFER_SIZE - size, 0, 2, 1, §ion);
686 #else
687 result = ov_read(inStream, data + size, STREAM_BUFFER_SIZE - size, 1, 2, 1, §ion);
688 #endif
689 safe_snprintf(str, sizeof(str), "%d", result); //prevents optimization errors under Windows, but how/why?
690 if (result > 0)
691 size += result;
692 else if (result == OV_HOLE)
693 // OV_HOLE is informational so ignore it
694 continue;
695 else if(result < 0)
696 ogg_error(result);
697 else
698 break;
699 }
700
701 if (!size)
702 return 0; // The file is finished, quit trying to play
703
704 // Check the number of channels... always use 16-bit samples
705 if (info->channels == 1)
706 format = AL_FORMAT_MONO16;
707 else
708 format = AL_FORMAT_STEREO16;
709
710 alBufferData(buffer, format, data, size, info->rate);
711
712 if ((error = alGetError()) != AL_NO_ERROR)
713 {
714 #ifdef _EXTRA_SOUND_DEBUG
715 printf("stream_ogg %s: %s, buffer: %d, format: %d, size: %d, rate: %ld", my_tolower(reg_error_str), alGetString(error), buffer, format, size, info->rate);
716 #endif // _EXTRA_SOUND_DEBUG
717 }
718 return 1;
719 }
720
load_ogg_into_memory(char * szPath,ALenum * inFormat,ALsizei * inSize,ALfloat * inFreq)721 ALvoid * load_ogg_into_memory(char * szPath, ALenum *inFormat, ALsizei *inSize, ALfloat *inFreq)
722 {
723 int bitStream;
724 int result;
725 vorbis_info *pInfo;
726 OggVorbis_File oggFile;
727 ALenum format;
728 ALsizei size;
729 ALfloat freq;
730 char * data;
731
732 // Load the file
733 result = load_ogg_file(szPath, &oggFile);
734 if (!result)
735 return NULL;
736
737 // Get some information about the OGG file
738 pInfo = ov_info(&oggFile, -1);
739
740 // Check the number of channels... always use 16-bit samples
741 format = (pInfo->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
742
743 // The frequency of the sampling rate
744 freq = pInfo->rate;
745
746 data = malloc(OGG_BUFFER_SIZE);
747 if (!data)
748 {
749 ov_clear(&oggFile);
750 return NULL;
751 }
752
753 // Reset the variables
754 bitStream = 0;
755 size = 0;
756
757 // Hope OGG_BUFFER_SIZE is large enough for this sample - 1MB should be! Anything more should be streamed.
758 while (size < OGG_BUFFER_SIZE)
759 {
760 #ifndef EL_BIG_ENDIAN
761 result = ov_read(&oggFile, data + size, OGG_BUFFER_SIZE - size, 0, 2, 1, &bitStream);
762 #else
763 result = ov_read(&oggFile, data + size, OGG_BUFFER_SIZE - size, 1, 2, 1, &bitStream);
764 #endif
765 if (result > 0)
766 size += result;
767 else if (result < 0 && result != OV_HOLE) // OV_HOLE is informational
768 ogg_error(result);
769 else
770 break;
771 }
772
773 ov_clear(&oggFile);
774
775 *inFormat = format;
776 *inSize = size;
777 *inFreq = freq;
778 return data;
779 }
780
781
782 /**************************
783 * SOUND STREAM FUNCTIONS *
784 **************************/
785
get_stream_type(int type)786 static char * get_stream_type(int type)
787 {
788 return type == STREAM_TYPE_MUSIC ? "Music" :
789 (type == STREAM_TYPE_CROWD ? "Crowd" :
790 (type == STREAM_TYPE_SOUNDS ? "Background" : "None"));
791 }
792
play_stream(int sound,stream_data * stream,ALfloat gain)793 void play_stream(int sound, stream_data * stream, ALfloat gain)
794 {
795 char * file;
796 char tmp_file_name[80];
797
798 // Find the filename to play
799 if (stream->type == STREAM_TYPE_MUSIC)
800 {
801 if (!have_music || sound<0 || sound>=MAX_PLAYLIST_ENTRIES) return;
802
803 if (playlist[sound].file_name[0]!='.' && playlist[sound].file_name[0]!='/')
804 safe_snprintf (tmp_file_name, sizeof (tmp_file_name), "./music/%s", playlist[sound].file_name);
805 else
806 safe_snprintf(tmp_file_name, sizeof (tmp_file_name), "%s", playlist[sound].file_name);
807 file = tmp_file_name;
808 }
809 else
810 {
811 if (sound<0 || sound>=MAX_SOUNDS || sound_type_data[sound].num_variants <= 0) return;
812
813 // Choose a variant
814 stream->variant = rand() % sound_type_data[sound].num_variants;
815 file = sound_type_data[sound].variant[stream->variant].part[STAGE_MAIN]->file_path;
816 if (!have_sound || sound == -1 || !strcmp(file, "")) return;
817 }
818
819 // Set the gain for this stream
820 alSourcef(stream->source, AL_GAIN, gain * (stream->type == STREAM_TYPE_MUSIC ? 1.0f : sound_type_data[sound].variant[stream->variant].gain));
821
822 // Load the Ogg file and start the stream
823 if (stream_ogg_file(file, stream, NUM_STREAM_BUFFERS) < 0)
824 {
825 LOG_ERROR("%s:%d stream_ogg_file() returned error so not playing", __FUNCTION__, __LINE__);
826 stream->playing = 0;
827 }
828 stream->sound = sound;
829 }
830
start_stream(stream_data * stream)831 int start_stream(stream_data * stream)
832 {
833 int state = 0, error;
834 alGetSourcei(stream->source, AL_SOURCE_STATE, &state);
835 if (state != AL_PLAYING) {
836 alSourcePlay(stream->source);
837 }
838 stream->playing = 1;
839 if ((error = alGetError()) != AL_NO_ERROR)
840 {
841 LOG_ERROR("start_stream - Error starting stream - %s: %s", my_tolower(reg_error_str), alGetString(error));
842 stream->playing = 0;
843 return 0;
844 }
845 return 1;
846 }
847
stop_stream(stream_data * stream)848 void stop_stream(stream_data * stream)
849 {
850 ALuint buffer;
851 int queued = 0, state = 0, error;
852
853 stream->playing = 0;
854 alGetSourcei(stream->source, AL_SOURCE_STATE, &state);
855 if (state != AL_PAUSED)
856 alSourceStop(stream->source);
857 alGetSourcei(stream->source, AL_BUFFERS_PROCESSED, &stream->processed);
858 alGetSourcei(stream->source, AL_BUFFERS_QUEUED, &queued);
859 while ((alGetError() == AL_NO_ERROR) && (queued-- > 0))
860 {
861 alSourceUnqueueBuffers(stream->source, 1, &buffer);
862 }
863 if ((error = alGetError()) != AL_NO_ERROR)
864 {
865 LOG_ERROR("stop_stream - Error stopping stream - %s: %s", my_tolower(reg_error_str), alGetString(error));
866 }
867 }
868
reset_stream(stream_data * stream)869 void reset_stream(stream_data * stream)
870 {
871 #ifdef _EXTRA_SOUND_DEBUG
872 // printf("Resetting stream: Type: %s, sound: %d, cookie: %d, source: %d\n", get_stream_type(stream->type), stream->sound, stream->cookie, stream->source);
873 #endif // _EXTRA_SOUND_DEBUG
874 // Reset the data (not sources or buffers)
875 stream->playing = 0;
876 stream->info = NULL;
877 stream->processed = 0;
878 stream->sound = -1;
879 stream->is_default = 0;
880 stream->boundary = NULL;
881 stream->fade = 0;
882 stream->fade_length = 10;
883 }
884
init_sound_stream(stream_data * stream,int type,int priority)885 int init_sound_stream(stream_data * stream, int type, int priority)
886 {
887 source_data * source;
888 int error;
889
890 alGenBuffers(NUM_STREAM_BUFFERS, stream->buffers);
891
892 LOCK_SOUND_LIST();
893 source = get_available_source(priority);
894 if (!source || !alIsSource(source->source))
895 {
896 UNLOCK_SOUND_LIST();
897 return 0;
898 }
899 // Set some details so non-streamed functions see this source as used
900 source->cookie = get_next_cookie();
901 source->current_stage = STAGE_STREAM;
902 source->loaded_sound = 0;
903 // Make sure the data for this stream is clean
904 reset_stream(stream);
905 stream->type = type;
906 stream->source = source->source;
907 stream->cookie = source->cookie;
908 UNLOCK_SOUND_LIST();
909
910 // Reset the source details
911 alSource3f(stream->source, AL_POSITION, 0.0, 0.0, 0.0);
912 alSource3f(stream->source, AL_VELOCITY, 0.0, 0.0, 0.0);
913 alSource3f(stream->source, AL_DIRECTION, 0.0, 0.0, 0.0);
914 alSourcef (stream->source, AL_ROLLOFF_FACTOR, 0.0 );
915 alSourcei (stream->source, AL_SOURCE_RELATIVE, AL_TRUE );
916 alSourcef (stream->source, AL_GAIN, 0.0);
917 alSourcei (stream->source, AL_LOOPING, AL_FALSE);
918 alSourceStop(stream->source);
919 alSourcei (stream->source, AL_BUFFER, 0); // Make sure there are no buffers attached
920
921 // Reset the error buffer
922 if ((error = alGetError()) != AL_NO_ERROR)
923 {
924 #ifdef _EXTRA_SOUND_DEBUG
925 printf("Error initalising stream: Type: %s, %s\n", get_stream_type(type), alGetString(error));
926 #endif // _EXTRA_SOUND_DEBUG
927 }
928
929 return 1;
930 }
931
destroy_stream(stream_data * stream)932 void destroy_stream(stream_data * stream)
933 {
934 int error, i;
935
936 #ifdef _EXTRA_SOUND_DEBUG
937 // printf("Destroying stream: Type: %s, sound: %d, cookie: %d, source: %d\n", get_stream_type(stream->type), stream->sound, stream->cookie, stream->source);
938 #endif // _EXTRA_SOUND_DEBUG
939 if (stream->type == STREAM_TYPE_NONE)
940 return; // In theory this stream isn't initialised
941
942 if (stream->playing)
943 {
944 stop_stream(stream);
945 }
946 if (stream->type == STREAM_TYPE_MUSIC)
947 {
948 music_stream = NULL;
949 }
950
951 if (stream->cookie != 0)
952 {
953 // Find which of our playing sources matches the handle for this stream
954 i = find_sound_source_from_cookie(stream->cookie);
955 if (i >= 0)
956 {
957 stop_sound_source_at_index(i);
958 }
959 }
960 stream->source = 0;
961 stream->cookie = 0;
962 reset_stream(stream);
963 for (i = 0; i < NUM_STREAM_BUFFERS; i++)
964 {
965 if (alIsBuffer(stream->buffers[i]))
966 alDeleteBuffers(1, stream->buffers+i);
967 }
968 if (stream->stream_opened)
969 {
970 ov_clear(&stream->stream);
971 stream->stream_opened = 0;
972 }
973 stream->type = STREAM_TYPE_NONE;
974
975 // Reset the error buffer
976 if ((error = alGetError()) != AL_NO_ERROR)
977 {
978 #ifdef _EXTRA_SOUND_DEBUG
979 printf("Error destroying stream: Type: %s, %s\n", get_stream_type(stream->type), alGetString(error));
980 #endif // _EXTRA_SOUND_DEBUG
981 }
982 }
983
984 /* add_stream
985 *
986 * Processes adding a new stream if possible
987 *
988 * sound the sound to play in the stream
989 * type the type of stream
990 * boundary the map boundary def being used for this stream (-1 for default sounds)
991 */
add_stream(int sound,int type,int boundary)992 int add_stream(int sound, int type, int boundary)
993 {
994 stream_data * stream = NULL;
995 int priority = 0, i, default_found = -1, type_count = 0;
996
997 if (sound == -1)
998 return 0;
999
1000 // Check we aren't creating another music stream if one exists
1001 if (type == STREAM_TYPE_MUSIC && music_stream)
1002 {
1003 LOG_ERROR("Sound stream error: Tried to create additional music stream. This is a bug!\n");
1004 return 0;
1005 }
1006
1007 for (i = 0; i < max_streams; i++)
1008 {
1009 // Check this sound isn't already being played in a stream
1010 if (streams[i].sound == sound && streams[i].type == type)
1011 {
1012 return 0;
1013 }
1014 if (streams[i].type == type)
1015 {
1016 // Count the number of streams of this type (for the priority calculation)
1017 type_count++;
1018 // Check if there is a default stream of this type that needs to be stopped
1019 if (streams[i].is_default)
1020 {
1021 default_found = i;
1022 }
1023 }
1024 // Find a spot in the array
1025 if (!stream && streams[i].type == STREAM_TYPE_NONE)
1026 {
1027 stream = &streams[i];
1028 }
1029 }
1030 if (!stream)
1031 {
1032 return 0;
1033 }
1034 // Calculate the priority of this stream (give the first 2 streams of this type top priority and then according to sound)
1035 if (type_count > 2)
1036 priority = sound_type_data[sound].priority;
1037 else
1038 priority = 1;
1039
1040 // Init the stream
1041 if (!init_sound_stream(stream, type, priority))
1042 return 0; // We couldn't get a source. Sad but you get that.
1043
1044 // Play the stream
1045 play_stream(sound, stream, 0.0f); // Fade the stream up
1046 if (!stream->playing)
1047 {
1048 // There was an error so remove the stream and bail
1049 #ifdef _EXTRA_SOUND_DEBUG
1050 printf("add_stream: Eek, there was an error adding this stream! sound: %d\n", sound);
1051 #endif // _EXTRA_SOUND_DEBUG
1052 LOCK_SOUND_LIST();
1053 if (type == STREAM_TYPE_MUSIC)
1054 destroy_stream(stream);
1055 UNLOCK_SOUND_LIST();
1056 return 0;
1057 }
1058 stream->type = type;
1059 stream->fade = 1;
1060 stream->fade_length = 10;
1061 if (boundary == -1)
1062 {
1063 stream->is_default = 1;
1064 stream->boundary = NULL;
1065 }
1066 else
1067 {
1068 stream->boundary = &sound_map_data[snd_cur_map].boundaries[boundary];
1069 stream->is_default = 0;
1070 }
1071 #ifdef _EXTRA_SOUND_DEBUG
1072 printf("add_stream: Started stream. Type: %s, Sound: %d, Cookie: %u, Source: %d, Fade: %d, Default: %d\n", get_stream_type(stream->type), stream->sound, stream->cookie, stream->source, stream->fade, stream->is_default);
1073 #endif // _EXTRA_SOUND_DEBUG
1074 // If this is the music stream, set the pointer
1075 if (type == STREAM_TYPE_MUSIC)
1076 music_stream = stream;
1077 // We have definitely started this stream so stop any default we found
1078 if (default_found > -1)
1079 streams[default_found].fade = -1;
1080
1081 return 1; // Return success
1082 }
1083
check_for_valid_stream_sound(int tx,int ty,int type)1084 int check_for_valid_stream_sound(int tx, int ty, int type)
1085 {
1086 int i, j, snd = -1, playing, found = 0;
1087
1088 if (snd_cur_map > -1 && (sound_map_data[snd_cur_map].file_name[0] != '\0' || sound_map_data[snd_cur_map].id > -1) )
1089 {
1090 for (i = 0; i < sound_map_data[snd_cur_map].num_boundaries; i++)
1091 {
1092 if (i == sound_map_data[snd_cur_map].num_boundaries)
1093 i = 0;
1094 if (type == STREAM_TYPE_SOUNDS)
1095 {
1096 snd = sound_map_data[snd_cur_map].boundaries[i].bg_sound;
1097 }
1098 else if (type == STREAM_TYPE_CROWD)
1099 {
1100 snd = sound_map_data[snd_cur_map].boundaries[i].crowd_sound;
1101 }
1102 if (snd > -1 && sound_bounds_check(tx, ty, &sound_map_data[snd_cur_map].boundaries[i]))
1103 {
1104 playing = 0;
1105 for (j = 0; j < max_streams; j++)
1106 {
1107 if (streams[j].sound == snd)
1108 playing = 1;
1109 }
1110 if (!playing)
1111 {
1112 #ifdef _EXTRA_SOUND_DEBUG
1113 printf("Starting stream (%s) sound: %d, boundary: %d\n", get_stream_type(type), snd, i);
1114 #endif //_EXTRA_SOUND_DEBUG
1115 add_stream(snd, type, i);
1116 found = 1;
1117 }
1118 }
1119 }
1120 }
1121 return found;
1122 }
1123
check_for_new_streams(int tx,int ty)1124 void check_for_new_streams(int tx, int ty)
1125 {
1126 int i, found_bg = 0, found_crowd = 0;
1127
1128 found_bg = check_for_valid_stream_sound(tx, ty, STREAM_TYPE_SOUNDS);
1129 if (no_near_enhanced_actors >= 5)
1130 found_crowd = check_for_valid_stream_sound(tx, ty, STREAM_TYPE_CROWD);
1131
1132 if (!found_bg && !found_crowd)
1133 {
1134
1135 #ifdef _EXTRA_SOUND_DEBUG
1136 // printf("check_for_new_streams - Checking if we need a default background/crowd sound. Pos: %d, %d\n", tx, ty);
1137 #endif //_EXTRA_SOUND_DEBUG
1138
1139 // Check if we need a default background or default crowd sound (no other bg/crowd sounds, or they are fading out)
1140 for (i = 0; i < max_streams; i++)
1141 {
1142 if (no_near_enhanced_actors < 5 || (streams[i].type == STREAM_TYPE_CROWD && streams[i].fade >= 0))
1143 found_crowd = 1; // We have a crowd sound already (or don't need one) so we don't need a default one
1144 if (streams[i].type == STREAM_TYPE_SOUNDS && streams[i].fade >= 0)
1145 found_bg = 1; // We have a bg sound already so we don't need a default one
1146 if (found_bg && found_crowd)
1147 return; // We have both so we don't need to continue
1148 }
1149
1150 #ifdef _EXTRA_SOUND_DEBUG
1151 // printf("check_for_new_streams - Background found: %s, Crowd found: %s. Checking for defaults for this map\n", found_bg == 0 ? "No" : "Yes", found_crowd == 0 ? "No" : "Yes");
1152 #endif //_EXTRA_SOUND_DEBUG
1153
1154 // We still aren't playing a sound for one type, so check for a map based sound
1155 if ((snd_cur_map > -1) && (sound_map_data[snd_cur_map].num_defaults > 0))
1156 {
1157 map_sound_data * cur_map = &sound_map_data[snd_cur_map];
1158 for (i = 0; i < cur_map->num_defaults; i++)
1159 {
1160 if (!found_bg && time_of_day_valid(cur_map->boundaries[cur_map->defaults[i]].time_of_day_flags) &&
1161 cur_map->boundaries[cur_map->defaults[i]].bg_sound > -1)
1162 {
1163 #ifdef _EXTRA_SOUND_DEBUG
1164 // printf("check_for_new_streams - Playing map default background sound: %d\n", cur_map->boundaries[cur_map->defaults[i]].bg_sound);
1165 #endif //_EXTRA_SOUND_DEBUG
1166 add_stream(cur_map->boundaries[cur_map->defaults[i]].bg_sound, STREAM_TYPE_SOUNDS, -1);
1167 found_bg = 1;
1168 }
1169 if (!found_crowd && time_of_day_valid(cur_map->boundaries[cur_map->defaults[i]].time_of_day_flags) &&
1170 cur_map->boundaries[cur_map->defaults[i]].crowd_sound > -1)
1171 {
1172 #ifdef _EXTRA_SOUND_DEBUG
1173 printf("check_for_new_streams - Playing map default crowd sound: %d\n", cur_map->boundaries[cur_map->defaults[i]].crowd_sound);
1174 #endif //_EXTRA_SOUND_DEBUG
1175 add_stream(cur_map->boundaries[cur_map->defaults[i]].crowd_sound, STREAM_TYPE_CROWD, -1);
1176 found_crowd = 1;
1177 }
1178 if (found_bg && found_crowd)
1179 break;
1180 }
1181 }
1182
1183 // Check if we need to find a global default background
1184 if (!found_bg && sound_num_background_defaults > 0)
1185 {
1186 #ifdef _EXTRA_SOUND_DEBUG
1187 // printf("check_for_new_streams - No map defaults found, checking for global defaults\n");
1188 #endif //_EXTRA_SOUND_DEBUG
1189 for (i = 0; i < sound_num_background_defaults; i++)
1190 {
1191 if (time_of_day_valid(sound_background_defaults[i].time_of_day_flags) &&
1192 (sound_background_defaults[i].map_type == dungeon && sound_background_defaults[i].sound > -1))
1193 {
1194 #ifdef _EXTRA_SOUND_DEBUG
1195 // printf("check_for_new_streams - Playing default background sound: %d\n", sound_background_defaults[i].sound);
1196 #endif //_EXTRA_SOUND_DEBUG
1197 add_stream(sound_background_defaults[i].sound, STREAM_TYPE_SOUNDS, -1);
1198 break;
1199 }
1200 }
1201 }
1202
1203 // If we still aren't playing a crowd sound, check for a global default
1204 if (!found_crowd && crowd_default > -1)
1205 {
1206 #ifdef _EXTRA_SOUND_DEBUG
1207 printf("check_for_new_streams - Playing default crowd sound: %d\n", crowd_default);
1208 #endif //_EXTRA_SOUND_DEBUG
1209 add_stream(crowd_default, STREAM_TYPE_CROWD, -1);
1210 }
1211 }
1212 }
1213
process_stream(stream_data * stream,ALfloat gain,int * sleep)1214 int process_stream(stream_data * stream, ALfloat gain, int * sleep)
1215 {
1216 int error, state = AL_STOPPED; // , state2;
1217 ALfloat new_gain = gain;
1218 ALuint buffer;
1219
1220 // Check if we are starting/stopping this stream and continue the fade
1221 if (stream->fade < 0)
1222 {
1223 new_gain = gain - ((float)(-stream->fade) * (gain / stream->fade_length));
1224 #ifdef _EXTRA_SOUND_DEBUG
1225 printf("Doing stream fade - stream: %s, sound: %d, fade: %d, gain: %f\n", get_stream_type(stream->type), stream->sound, stream->fade, new_gain);
1226 #endif // _EXTRA_SOUND_DEBUG
1227 stream->fade -= 1;
1228 }
1229 else if (stream->fade > 0)
1230 {
1231 new_gain = gain - ((float)(stream->fade_length - stream->fade) * (gain / stream->fade_length));
1232 #ifdef _EXTRA_SOUND_DEBUG
1233 printf("Doing stream fade - stream: %s, sound: %d, fade: %d, gain: %f\n", get_stream_type(stream->type), stream->sound, stream->fade, new_gain);
1234 #endif // _EXTRA_SOUND_DEBUG
1235 stream->fade += 1;
1236 }
1237
1238 // Check if we need to dim down the sounds due to rain
1239 if (stream->type != STREAM_TYPE_MUSIC)
1240 {
1241 new_gain = weather_adjust_gain(new_gain, -1);
1242 #ifdef _EXTRA_SOUND_DEBUG
1243 // if (new_gain != gain)
1244 // printf("Volume adjusted by fade/weather for stream %s - Original gain: %f, New gain: %f\n", get_stream_type(stream->type), gain, new_gain);
1245 #endif // _EXTRA_SOUND_DEBUG
1246 }
1247
1248 alSourcef(stream->source, AL_GAIN, new_gain);
1249 if ((error=alGetError()) != AL_NO_ERROR)
1250 {
1251 #ifdef _EXTRA_SOUND_DEBUG
1252 printf("process_stream - Error setting gain: %s, Stream type: %s, Source: %d\n", alGetString(error), get_stream_type(stream->type), stream->source);
1253 #endif // _EXTRA_SOUND_DEBUG
1254 }
1255
1256 // Process the next portion of the stream
1257 alGetSourcei(stream->source, AL_BUFFERS_PROCESSED, &stream->processed);
1258 if ((error=alGetError()) != AL_NO_ERROR)
1259 {
1260 #ifdef _EXTRA_SOUND_DEBUG
1261 printf("process_stream - Error retrieving buffers processed value: %s, Stream type: %s, Source: %d\n", alGetString(error), get_stream_type(stream->type), stream->source);
1262 #endif // _EXTRA_SOUND_DEBUG
1263 }
1264 if (!stream->processed)
1265 {
1266 if (*sleep < SLEEP_TIME)
1267 *sleep += (SLEEP_TIME / 100);
1268 return 1; // Skip error checking et al
1269 }
1270 while (stream->processed-- > 0)
1271 {
1272 alSourceUnqueueBuffers(stream->source, 1, &buffer);
1273 if ((error = alGetError()) != AL_NO_ERROR)
1274 LOG_ERROR("process_stream - Error unqueuing buffers: %s, Stream type: %s, Source: %d", alGetString(error), get_stream_type(stream->type), stream->source);
1275
1276 stream->playing = stream_ogg(buffer, &stream->stream, stream->info);
1277
1278 if (stream->playing)
1279 {
1280 alSourceQueueBuffers(stream->source, 1, &buffer);
1281 if ((error = alGetError()) != AL_NO_ERROR)
1282 LOG_ERROR("process_stream - Error requeuing buffers: %s, Stream type: %s, Source: %d, Playing: %s", alGetString(error), get_stream_type(stream->type), stream->source, stream->playing == 0 ? "No" : "Yes");
1283 }
1284 }
1285
1286 // Check if the stream is still playing, and handle if not
1287 alGetSourcei(stream->source, AL_SOURCE_STATE, &state);
1288 if ((error=alGetError()) != AL_NO_ERROR)
1289 {
1290 #ifdef _EXTRA_SOUND_DEBUG
1291 printf("process_stream - Error retrieving state: %s, Stream type: %s, Source: %d\n", alGetString(error), get_stream_type(stream->type), stream->source);
1292 #endif // _EXTRA_SOUND_DEBUG
1293 }
1294 if (state != AL_PLAYING)
1295 {
1296 LOG_TO_CONSOLE(c_red1, snd_skip_speedup);
1297 #ifdef _EXTRA_SOUND_DEBUG
1298 printf("process_stream - Stream Skip!! Sleep: %d\n", *sleep);
1299 #endif //_EXTRA_SOUND_DEBUG
1300 // Let streams skip up to 10 times. If it skips more, then stop the music/sound (not the best option).
1301 if (*sleep > (SLEEP_TIME / 10))
1302 *sleep -= (SLEEP_TIME / 10);
1303 else if (*sleep > 1) *sleep = 1;
1304 else
1305 {
1306 LOG_TO_CONSOLE(c_red1, snd_too_slow);
1307 LOG_ERROR(snd_too_slow);
1308 if (stream->type == STREAM_TYPE_MUSIC)
1309 turn_music_off();
1310 else
1311 turn_sound_off();
1312 *sleep = SLEEP_TIME;
1313 return 0;
1314 }
1315 alSourcePlay(stream->source);
1316 }
1317
1318 // Check if the stream has finished and needs to be requeued
1319 if (!stream->playing)
1320 {
1321 // Clear any remaining buffers, just in case
1322 alSourceStop(stream->source);
1323 alSourcei(stream->source, AL_BUFFER, 0);
1324 if ((error=alGetError()) != AL_NO_ERROR) { } // Clear any errors before trying to replay the stream
1325 play_stream(stream->sound, stream, gain);
1326 }
1327
1328 // Clear any OpenAL errors
1329 if ((error=alGetError()) != AL_NO_ERROR)
1330 {
1331 #ifdef _EXTRA_SOUND_DEBUG
1332 printf("process_stream - OpenAL error: %s, Stream type: %s, Source: %d\n", alGetString(error), get_stream_type(stream->type), stream->source);
1333 #endif // _EXTRA_SOUND_DEBUG
1334 }
1335
1336 return 1;
1337 }
1338
check_stream(stream_data * stream,int day_time,int tx,int ty)1339 int check_stream(stream_data * stream, int day_time, int tx, int ty)
1340 {
1341 // Check if we have finished fading this stream down and can stop it
1342 if (stream->fade < -stream->fade_length)
1343 {
1344 stop_stream(stream);
1345 // If this stream isn't the music stream then destroy it
1346 if (stream->type != STREAM_TYPE_MUSIC)
1347 {
1348 LOCK_SOUND_LIST();
1349 destroy_stream(stream);
1350 UNLOCK_SOUND_LIST();
1351 }
1352 return 0; // Stream is not continuing
1353 }
1354 // Check if we have finished fading this stream up and can stop the fade
1355 else if (stream->fade > stream->fade_length)
1356 {
1357 stream->fade = 0;
1358 }
1359
1360 // Check if we need to trigger a stop in this stream
1361 if (stream->fade >= 0)
1362 {
1363 switch (stream->type)
1364 {
1365 case STREAM_TYPE_MUSIC:
1366 if ((list_pos >= 0) && playlist[list_pos].file_name[0] && (tx < playlist[list_pos].min_x ||
1367 tx > playlist[list_pos].max_x ||
1368 ty < playlist[list_pos].min_y ||
1369 ty > playlist[list_pos].max_y ||
1370 (playlist[list_pos].time != 2 &&
1371 playlist[list_pos].time != day_time)))
1372 {
1373 stream->fade = -1;
1374 }
1375 break;
1376 case STREAM_TYPE_SOUNDS:
1377 case STREAM_TYPE_CROWD:
1378 if (stream->type == STREAM_TYPE_CROWD && no_near_enhanced_actors < 2)
1379 {
1380 // Don't stop until there are less than 2 people around so it will fade down more naturally
1381 stream->fade = -1;
1382 }
1383 if (stream->is_default)
1384 {
1385 #ifdef _EXTRA_SOUND_DEBUG
1386 // printf("process_stream - Checking for valid %s sound. Pos: %d, %d\n", get_stream_type(stream->type), tx, ty);
1387 #endif //_EXTRA_SOUND_DEBUG
1388 if (check_for_valid_stream_sound(tx, ty, stream->type))
1389 stream->fade = -1;
1390 }
1391 else
1392 {
1393 if (!sound_bounds_check(tx, ty, stream->boundary))
1394 {
1395 #ifdef _EXTRA_SOUND_DEBUG
1396 printf("process_stream - %s sound failed bounds check. Pos: %d, %d\n", get_stream_type(stream->type), tx, ty);
1397 #endif //_EXTRA_SOUND_DEBUG
1398 stream->fade = -1;
1399 }
1400 }
1401 break;
1402 }
1403 }
1404
1405 return 1; // Stream is continuing (but may be fading down)
1406 }
1407
update_streams(void * dummy)1408 int update_streams(void * dummy)
1409 {
1410 int sleep, day_time, i, tx, ty;
1411 ALfloat gain = 0.0;
1412
1413 sleep = SLEEP_TIME;
1414
1415 init_thread_log("update_streams");
1416
1417 #ifdef _EXTRA_SOUND_DEBUG
1418 printf("Starting streams thread\n");
1419 #endif //_EXTRA_SOUND_DEBUG
1420 while (!exit_now && ((have_music && music_on) || (have_sound && sound_on)))
1421 {
1422 SDL_Delay(sleep);
1423
1424 day_time = (game_minute >= 30 && game_minute < 60 * 3 + 30);
1425
1426 LOCK_ACTORS_LISTS();
1427 // Get our position
1428 if (your_actor)
1429 {
1430 tx = your_actor->x_pos * 2;
1431 ty = your_actor->y_pos * 2;
1432 }
1433 else
1434 {
1435 tx = 0;
1436 ty = 0;
1437 }
1438 if (have_a_map && (tx > 0 || ty > 0))
1439 {
1440 // Check if we need to start or stop any streams
1441 if (have_music && music_on && (!music_stream || !music_stream->playing))
1442 {
1443 find_next_song(tx, ty, day_time);
1444 }
1445 if (have_sound && sound_on)
1446 {
1447 check_for_new_streams(tx, ty);
1448 }
1449
1450 // Handle the streams
1451 LOCK_SOUND_LIST();
1452 for (i = 0; i < max_streams; i++)
1453 {
1454 if (streams[i].playing)
1455 {
1456 switch (streams[i].type)
1457 {
1458 case STREAM_TYPE_MUSIC:
1459 if (!have_music || !music_on)
1460 continue; // We aren't playing music so skip this stream
1461 gain = music_gain;
1462 break;
1463 case STREAM_TYPE_SOUNDS:
1464 if (!have_sound || !sound_on)
1465 continue; // We aren't playing sounds so skip this stream
1466 gain = sound_gain * enviro_gain * sound_type_data[streams[i].sound].variant[streams[i].variant].gain;
1467 break;
1468 case STREAM_TYPE_CROWD:
1469 if (!have_sound || !sound_on)
1470 continue; // We aren't playing sounds so skip this stream
1471 if (distanceSq_to_near_enhanced_actors == 0)
1472 distanceSq_to_near_enhanced_actors = 100.0f; // Due to no actors when calc'ing
1473 // SSE optimized sqrt gain = sound_gain * crowd_gain * sound_type_data[streams[i].sound].variant[streams[i].variant].gain
1474 // * fastsqrt(fastsqrt(no_near_enhanced_actors)) * invsqrt(distanceSq_to_near_enhanced_actors) * 2;
1475 gain = sound_gain * crowd_gain * sound_type_data[streams[i].sound].variant[streams[i].variant].gain
1476 * sqrt(sqrt(no_near_enhanced_actors)) / sqrt(distanceSq_to_near_enhanced_actors) * 2;
1477 break;
1478 }
1479 if (check_stream(&streams[i], day_time, tx, ty))
1480 process_stream(&streams[i], gain, &sleep);
1481 }
1482 }
1483 UNLOCK_SOUND_LIST();
1484 }
1485 UNLOCK_ACTORS_LISTS();
1486 }
1487 #ifdef _EXTRA_SOUND_DEBUG
1488 printf("Exiting streams thread. have_music: %d, music_on: %d, have_sound: %d, sound_on: %d, exit_now: %d\n", have_music, music_on, have_sound, sound_on, exit_now);
1489 #endif //_EXTRA_SOUND_DEBUG
1490 return 1;
1491 }
1492
1493
1494
1495
1496 /*******************
1497 * MUSIC FUNCTIONS *
1498 *******************/
1499
get_map_playlist()1500 void get_map_playlist()
1501 {
1502 int i=0, len;
1503 char map_list_file_name[256];
1504 char tmp_buf[1024];
1505 FILE *fp;
1506 char strLine[255];
1507 char *tmp;
1508 // NOTE: keep the max length in this format line in sync with
1509 // the size of tmp_buf
1510 static const char pl_line_fmt[] = "%d %d %d %d %d %1023s";
1511
1512 if(!have_music)return;
1513
1514 clear_playlist();
1515
1516 tmp = strrchr (map_file_name, '/');
1517 if (tmp == NULL)
1518 tmp = map_file_name;
1519 else
1520 tmp++;
1521 safe_snprintf (map_list_file_name, sizeof (map_list_file_name), "music/%s", tmp);
1522 len = strlen (map_list_file_name);
1523 tmp = strrchr (map_list_file_name, '.');
1524 if (tmp == NULL)
1525 tmp = &map_list_file_name[len];
1526 else
1527 tmp++;
1528 len -= strlen (tmp);
1529 safe_snprintf (tmp, sizeof (map_list_file_name) - len, "pll");
1530
1531 fp=open_file_data(map_list_file_name,"r");
1532 if (fp == NULL) return;
1533
1534 while(1)
1535 {
1536 if (fscanf (fp, pl_line_fmt, &playlist[i].min_x, &playlist[i].min_y, &playlist[i].max_x, &playlist[i].max_y, &playlist[i].time, tmp_buf) == 6)
1537 {
1538 // check for a comment
1539 tmp = strstr (tmp_buf, "--");
1540 if (tmp)
1541 {
1542 *tmp = '\0';
1543 len = strlen (tmp_buf);
1544 while (len > 0 && isspace (tmp_buf[len-1]))
1545 {
1546 len--;
1547 tmp_buf[len]= '\0';
1548 }
1549 }
1550 safe_strncpy (playlist[i].file_name, tmp_buf, MAX_PLAYLIST_FILENAME);
1551 playlist[i].file_name[MAX_PLAYLIST_FILENAME-1]= '\0';
1552 if (++i >= MAX_PLAYLIST_ENTRIES)
1553 break;
1554 }
1555 if (!fgets (strLine, 100, fp)) break;
1556 }
1557 fclose(fp);
1558 loop_list=1;
1559 list_pos=-1;
1560 }
1561
play_music(int list)1562 void play_music(int list)
1563 {
1564 int i=0;
1565 char list_file_name[256];
1566 FILE *fp;
1567 char strLine[255];
1568
1569 if(!have_music)return;
1570
1571 clear_playlist();
1572
1573 safe_snprintf(list_file_name, sizeof(list_file_name), "music/%d.pll", list);
1574 fp=open_file_data(list_file_name, "r");
1575 if(!fp)return;
1576
1577 while (1)
1578 {
1579 if (fscanf (fp, "%254s", strLine) == 1)
1580 {
1581 safe_strncpy(playlist[i].file_name, strLine, MAX_PLAYLIST_FILENAME);
1582 playlist[i].min_x = 0;
1583 playlist[i].min_y = 0;
1584 playlist[i].max_x = 10000;
1585 playlist[i].max_y = 10000;
1586 playlist[i].time = 2;
1587 if (++i > MAX_PLAYLIST_ENTRIES)
1588 break;
1589 if (!fgets (strLine, 100, fp))
1590 break;
1591 }
1592 }
1593 fclose(fp);
1594 loop_list=0;
1595 list_pos=0;
1596 play_song(list_pos);
1597 }
1598
display_song_name()1599 int display_song_name()
1600 {
1601 if (!music_stream || !music_stream->playing)
1602 {
1603 LOG_TO_CONSOLE(c_grey1, snd_media_music_stopped);
1604 }
1605 else
1606 {
1607 char musname[100];
1608 int t_played_min, t_played_sec, t_total_min, t_total_sec;
1609 char *title = NULL, *artist = NULL;
1610 int i=0;
1611 vorbis_comment *comments;
1612
1613 t_played_min = (int)(ov_time_tell(&music_stream->stream) / 60);
1614 t_played_sec = (int)ov_time_tell(&music_stream->stream) % 60;
1615 t_total_min = (int)(ov_time_total(&music_stream->stream, -1) / 60);
1616 t_total_sec = (int)ov_time_total(&music_stream->stream, -1) % 60;
1617
1618 comments = ov_comment(&music_stream->stream, -1);
1619 if(comments == NULL)
1620 {
1621 safe_snprintf(musname, sizeof(musname), snd_media_ogg_info_noartist, playlist[list_pos].file_name, t_played_min, t_played_sec, t_total_min, t_total_sec);
1622 LOG_TO_CONSOLE(c_grey1, musname);
1623 return 1;
1624 }
1625 for (; i < comments->comments; ++i)
1626 {
1627 if ((artist == NULL) && (comments->comment_lengths[i] > 6) && (!strncasecmp(comments->user_comments[i],"artist", 6)))
1628 {
1629 artist = comments->user_comments[i] + 7;
1630 if(title)
1631 break;
1632 }
1633 else if ((title == NULL) && (comments->comment_lengths[i] > 6) && (!strncasecmp(comments->user_comments[i],"title", 5)))
1634 {
1635 title = comments->user_comments[i] + 6;
1636 if(artist)
1637 break;
1638 }
1639 }
1640 if (artist && title)
1641 {
1642 safe_snprintf(musname, sizeof(musname), snd_media_ogg_info, title, artist, t_played_min, t_played_sec, t_total_min, t_total_sec);
1643 }
1644 else if (title)
1645 {
1646 safe_snprintf(musname, sizeof(musname), snd_media_ogg_info_noartist, title, t_played_min, t_played_sec, t_total_min, t_total_sec);
1647 }
1648 else
1649 {
1650 safe_snprintf(musname, sizeof(musname), snd_media_ogg_info_noartist, playlist[list_pos].file_name, t_played_min, t_played_sec, t_total_min, t_total_sec);
1651 }
1652 LOG_TO_CONSOLE(c_grey1, musname);
1653 }
1654 return 1;
1655 }
1656
play_song(int list_pos)1657 void play_song(int list_pos)
1658 {
1659 // Find the music stream
1660 if (music_stream)
1661 {
1662 play_stream(list_pos, music_stream, 0.0f);
1663 music_stream->fade = 1;
1664 return;
1665 }
1666 // Don't have a music stream yet so create one
1667 add_stream(list_pos, STREAM_TYPE_MUSIC, -1);
1668 }
1669
find_next_song(int tx,int ty,int day_time)1670 void find_next_song(int tx, int ty, int day_time)
1671 {
1672 if (playlist[list_pos+1].file_name[0])
1673 {
1674 list_pos++;
1675 if (tx > playlist[list_pos].min_x &&
1676 tx < playlist[list_pos].max_x &&
1677 ty > playlist[list_pos].min_y &&
1678 ty < playlist[list_pos].max_y &&
1679 (playlist[list_pos].time == 2 ||
1680 playlist[list_pos].time == day_time))
1681 {
1682 // Found a song so play it
1683 play_song(list_pos);
1684 }
1685 }
1686 else if (loop_list)
1687 list_pos = -1;
1688 else
1689 get_map_playlist();
1690 }
1691
1692
1693
1694
1695 /*****************************
1696 * SOURCE HANDLING FUNCTIONS *
1697 *****************************/
add_source_to_lists(source_data * pSource)1698 static void add_source_to_lists(source_data *pSource)
1699 {
1700 int samples[num_STAGES];
1701 int nr_samples = 0;
1702 int i;
1703 source_list *new_source_id;
1704
1705 for (i = 0; i < num_STAGES; i++)
1706 {
1707 if (pSource->sample[i] > -1)
1708 samples[nr_samples++] = pSource->sample[i];
1709 }
1710
1711 if (nr_samples == 0)
1712 return;
1713
1714 new_source_id = calloc(1, sizeof(source_list));
1715 new_source_id->source = pSource->source;
1716 new_source_id->next = NULL;
1717 new_source_id->last = NULL;
1718
1719 for (i = 0; i < nr_samples; i++)
1720 {
1721 // Get the current list of sources for this sample
1722 source_list *source_id = sound_sample_data[samples[i]].sources;
1723 if (source_id)
1724 {
1725 // Find the end of the list and add this source to it
1726 while (source_id->next)
1727 source_id = source_id->next;
1728 source_id->next = new_source_id;
1729 new_source_id->last = source_id;
1730 }
1731 else
1732 {
1733 // Create this source as the start of the list
1734 sound_sample_data[samples[i]].sources = new_source_id;
1735 }
1736 }
1737 }
1738
remove_source_from_lists(source_data * pSource)1739 static void remove_source_from_lists(source_data *pSource)
1740 {
1741 int i;
1742 source_list *source_id;
1743
1744 for (i = 0; i < num_STAGES; i++)
1745 {
1746 if (pSource->sample[i] > -1)
1747 {
1748 for (source_id = sound_sample_data[pSource->sample[i]].sources;
1749 source_id; source_id = source_id->next)
1750 {
1751 if (source_id->source == pSource->source)
1752 break;
1753 }
1754
1755 if (source_id)
1756 {
1757 if (source_id->next)
1758 source_id->next->last = source_id->last;
1759 if (source_id->last)
1760 source_id->last->next = source_id->next;
1761 else
1762 sound_sample_data[pSource->sample[i]].sources = source_id->next;
1763 free(source_id);
1764 }
1765 }
1766 }
1767 }
1768
clear_source(source_data * pSource)1769 void clear_source(source_data *pSource)
1770 {
1771 // Reset the source
1772 if (pSource->source > 0)
1773 {
1774 alSourceStop(pSource->source);
1775 alSourcei(pSource->source, AL_BUFFER, 0);
1776 }
1777 // If this source is attached to samples, clear it from their list
1778 remove_source_from_lists(pSource);
1779 // Reset the details of this source
1780 pSource->priority = 0;
1781 pSource->play_duration = 0;
1782 pSource->current_stage = STAGE_UNUSED;
1783 pSource->loaded_sound = -1;
1784 pSource->cookie = 0;
1785 pSource->sample[STAGE_INTRO] = -1;
1786 pSource->sample[STAGE_MAIN] = -1;
1787 pSource->sample[STAGE_OUTRO] = -1;
1788 }
1789
get_available_source(int priority)1790 source_data * get_available_source(int priority)
1791 {
1792 source_data * pSource;
1793 int i;
1794
1795 if (used_sources == max_sources)
1796 return NULL;
1797
1798 // Search for an available source. The sources are ordered by decreasing play priority
1799 for (pSource = sound_source_data, i = 0; i < max_sources - 1; ++i, ++pSource)
1800 {
1801 if (pSource->loaded_sound < 0 && pSource->current_stage != STAGE_STREAM)
1802 {
1803 #ifdef _EXTRA_SOUND_DEBUG
1804 printf("Found available source at index %d/%d, Source: %d\n", i, used_sources, pSource->source);
1805 #endif //_EXTRA_SOUND_DEBUG
1806 pSource->priority = priority;
1807 used_sources++;
1808 return pSource;
1809 }
1810 else if (priority <= pSource->priority)
1811 {
1812 #ifdef _EXTRA_SOUND_DEBUG
1813 printf("Inserting new source at index %d/%d", i, used_sources);
1814 #endif //_EXTRA_SOUND_DEBUG
1815 pSource = insert_sound_source_at_index(i);
1816 #ifdef _EXTRA_SOUND_DEBUG
1817 printf(", Source: %d\n", pSource->source);
1818 #endif //_EXTRA_SOUND_DEBUG
1819 pSource->priority = priority;
1820 used_sources++;
1821 return pSource;
1822 }
1823 }
1824
1825 // All sources are used by higher-priority sounds
1826 return NULL;
1827 }
1828
1829 // This takes a copy the first unused source object (or last one in the list if all used),
1830 // moves all objects after #index along one place, and inserts the copied object at #index;
1831 // It is ensured the source at #index is stopped with no buffers queued
insert_sound_source_at_index(unsigned int index)1832 source_data *insert_sound_source_at_index(unsigned int index)
1833 {
1834 int i;
1835 source_data tempSource;
1836 // Take a copy of the source about to be overwritten
1837 tempSource = sound_source_data[min2i(used_sources, max_sources - 1)];
1838 // Ensure it is stopped and ready
1839 clear_source(&tempSource);
1840
1841 // Shunt source objects down a place
1842 for (i = min2i(used_sources, max_sources - 1); i > index; --i)
1843 {
1844 sound_source_data[i] = sound_source_data[i - 1];
1845 }
1846
1847 // Now insert our stored object at #index
1848 sound_source_data[index] = tempSource;
1849
1850 // Return a pointer to this new source
1851 return &sound_source_data[index];
1852 }
1853
release_source(source_data * pSource,int index)1854 void release_source(source_data *pSource, int index)
1855 {
1856 source_data sourceTemp;
1857
1858 // Check we have the index for this source
1859 if (index == -1)
1860 for (index = 0; &sound_source_data[index] != pSource; index++) {}
1861 // Reset the data for this source
1862 clear_source(pSource);
1863 // We can't lose a source handle - copy this...
1864 sourceTemp = *pSource;
1865 //...shift all the next sources up a place, overwriting the stopped source...
1866 memmove(pSource, pSource+1, sizeof(source_data) * (used_sources - (index + 1)));
1867 //...and put the saved object back in after them
1868 sound_source_data[used_sources - 1] = sourceTemp;
1869 // Note that one less source is playing!
1870 --used_sources;
1871 }
1872
1873 // This stops the source for sound_source_data[index]. Because this array will change, the index
1874 // associated with a source will change, so this function should only be called if the index is
1875 // known for certain.
stop_sound_source_at_index(int index)1876 int stop_sound_source_at_index(int index)
1877 {
1878 ALuint error = AL_NO_ERROR;
1879 source_data *pSource;
1880
1881 if (index < 0 || index >= used_sources)
1882 {
1883 #ifdef _EXTRA_SOUND_DEBUG
1884 printf("Trying to unload invalid source! Index: %d, Num Sources: %d\n", index, used_sources);
1885 #endif //_EXTRA_SOUND_DEBUG
1886 return 0;
1887 }
1888
1889 // This should not happen
1890 if (index >= max_sources)
1891 {
1892 LOG_ERROR("Trying to unload invalid source! Index: %d, Num Sources: %d, Max Sources: %d\n", index, used_sources, max_sources);
1893 return 0;
1894 }
1895
1896 pSource = &sound_source_data[index];
1897
1898 // Error if source is invalid (lost)
1899 if (!alIsSource(sound_source_data[index].source))
1900 {
1901 LOG_ERROR("Attempting to stop invalid sound source %d with index %d", (int)pSource->source, index);
1902 }
1903
1904 release_source(pSource, index);
1905
1906 // Clear any errors so as to not confuse other error handlers
1907 if ((error=alGetError()) != AL_NO_ERROR)
1908 {
1909 #ifdef _EXTRA_SOUND_DEBUG
1910 printf("Error '%s' stopping sound source with index: %d/%d.\n", alGetString(error), index, used_sources + 1);
1911 #endif //_EXTRA_SOUND_DEBUG
1912 }
1913
1914 return 1;
1915 }
1916
1917 // Find the index of the source associated with this cookie.
1918 // Note that this result must not be stored, but used immediately;
find_sound_source_from_cookie(unsigned int cookie)1919 int find_sound_source_from_cookie(unsigned int cookie)
1920 {
1921 int n;
1922 source_data *pSource;
1923
1924 if (!cookie)
1925 return -1;
1926
1927 for (n = 0, pSource = sound_source_data; n < used_sources; ++n, ++pSource)
1928 {
1929 if (pSource->cookie == cookie)
1930 return n;
1931 }
1932
1933 return -1;
1934 }
1935
sound_source_set_gain(unsigned long int cookie,float gain)1936 void sound_source_set_gain(unsigned long int cookie, float gain)
1937 {
1938 int n;
1939 source_data *pSource;
1940
1941 // Source handle of 0 is a null source
1942 if (!have_sound || !cookie)
1943 return;
1944
1945 // Find which of our playing sources matches the handle passed
1946 LOCK_SOUND_LIST();
1947 n = find_sound_source_from_cookie(cookie);
1948 if (n > 0)
1949 {
1950 pSource = &sound_source_data[n];
1951 set_sound_gain(pSource, pSource->loaded_sound, gain);
1952 }
1953 UNLOCK_SOUND_LIST();
1954 return;
1955 }
1956
set_sound_gain(source_data * pSource,int loaded_sound_num,float new_gain)1957 void set_sound_gain(source_data * pSource, int loaded_sound_num, float new_gain)
1958 {
1959 float type_gain = 1.0f;
1960 int error;
1961 sound_type * this_snd = &sound_type_data[sounds_list[loaded_sound_num].sound];
1962 sound_variants * this_variant = &this_snd->variant[sounds_list[loaded_sound_num].variant];
1963 // Check what type this sound is and match it to the "type gain"
1964 switch (this_snd->type)
1965 {
1966 case SOUNDS_CROWD:
1967 type_gain = crowd_gain;
1968 break;
1969 case SOUNDS_CLIENT:
1970 type_gain = client_gain;
1971 break;
1972 case SOUNDS_WALKING:
1973 type_gain = walking_gain;
1974 break;
1975 case SOUNDS_ACTOR:
1976 type_gain = actor_gain;
1977 break;
1978 case SOUNDS_MAP:
1979 type_gain = enviro_gain;
1980 break;
1981 case SOUNDS_ENVIRO:
1982 type_gain = enviro_gain;
1983 break;
1984 case SOUNDS_GAMEWIN:
1985 type_gain = gamewin_gain;
1986 break;
1987 case SOUNDS_WARNINGS:
1988 type_gain = warnings_gain;
1989 break;
1990 }
1991 // Check if we need to update the base gain for this sound
1992 if (new_gain != sounds_list[loaded_sound_num].base_gain)
1993 sounds_list[loaded_sound_num].base_gain = new_gain;
1994
1995 // Check if we need to dim down the sounds due to rain
1996 if (this_snd->type != SOUNDS_CLIENT && this_snd->type != SOUNDS_GAMEWIN && this_snd->type != SOUNDS_WARNINGS && this_snd->type != SOUNDS_ENVIRO)
1997 new_gain = weather_adjust_gain(new_gain, pSource->cookie);
1998
1999 // Check if we need to update the overall gain for this source
2000 if (sound_gain * type_gain * this_variant->gain * new_gain != sounds_list[loaded_sound_num].cur_gain)
2001 {
2002 sounds_list[loaded_sound_num].cur_gain = sound_gain * type_gain * this_variant->gain * new_gain;
2003 alSourcef(pSource->source, AL_GAIN, sounds_list[loaded_sound_num].cur_gain);
2004 }
2005 if ((error=alGetError()) != AL_NO_ERROR)
2006 {
2007 #ifdef _EXTRA_SOUND_DEBUG
2008 printf("Error setting sound gain: %f, sound: %d, error: %s\n", new_gain, loaded_sound_num, alGetString(error));
2009 #endif //_EXTRA_SOUND_DEBUG
2010 }
2011 return;
2012 }
2013
2014
2015
2016
2017 /*******************************
2018 * SAMPLE PROCESSING FUNCTIONS *
2019 *******************************/
2020
2021 /* If the sample given by the filename is not currently loaded, create a
2022 * buffer and load it from the path given.
2023 * Returns the sample number for success or -1 on failure.
2024 *
2025 * This function is likely to be very expensive as it initially traverses the types array
2026 * checking if the sample is loaded, then checks for a space in the buffer array, and
2027 * if it still hasn't found a spot, traverses the buffer and source arrays looking for a
2028 * buffer that isn't currently being played by a source!
2029 */
ensure_sample_loaded(char * in_filename)2030 int ensure_sample_loaded(char * in_filename)
2031 {
2032 int i, j, k, l, sample_num, error;
2033 ALvoid *data;
2034 ALsizei datasize;
2035 ALuint *pBuffer;
2036 sound_sample *pSample;
2037 char filename[200]; // This is for the full path to the file
2038
2039 // Check if this sample is already loaded and if so, return the sample ID
2040 for (i = 0; i < MAX_SOUND_FILES; i++)
2041 {
2042 if (!strcasecmp(sound_files[i].file_path, in_filename) && sound_files[i].sample_num > -1)
2043 {
2044 #ifdef _EXTRA_SOUND_DEBUG
2045 printf("Found this sample already loaded: %s, sound file: %d, sample num: %d\n", in_filename, i, sound_files[i].sample_num);
2046 #endif //_EXTRA_SOUND_DEBUG
2047 return sound_files[i].sample_num;
2048 }
2049 }
2050
2051 // Sample isn't loaded so find a space in the array
2052 sample_num = -1;
2053 for (i = 0; i < MAX_BUFFERS; i++)
2054 {
2055 // Check if this sample is free (no buffer exists)
2056 if (sound_sample_data[i].buffer == 0 || !alIsBuffer(sound_sample_data[i].buffer))
2057 {
2058 sample_num = i;
2059 #ifdef _EXTRA_SOUND_DEBUG
2060 printf("Found a spot for this sample: %s, sample %d\n", in_filename, i);
2061 #endif //_EXTRA_SOUND_DEBUG
2062 break;
2063 }
2064 }
2065
2066 if (sample_num == -1)
2067 {
2068 // Don't have a spot yet so check for any inactive samples (not loaded into a source)
2069 // -- This part will be expensive!! Let's hope we don't get here often --
2070 int found;
2071 #ifdef _EXTRA_SOUND_DEBUG
2072 char tmp[1000] = "";
2073 snprintf(tmp, sizeof(tmp), "Eek! Didn't want to get here. Sample (%s) is apparently not loaded and there is no space for it!", in_filename);
2074 LOG_TO_CONSOLE(c_red1, tmp);
2075 printf("Eek, nowhere for the sample: %s\n", in_filename);
2076 #endif //_EXTRA_SOUND_DEBUG
2077 for (i = 0; i < MAX_BUFFERS; i++)
2078 {
2079 found = 0;
2080 for (j = 0; j < used_sources; j++)
2081 {
2082 for (k = 0; k < sound_type_data[sounds_list[sound_source_data[j].loaded_sound].sound].num_variants; k++)
2083 {
2084 for (l = STAGE_INTRO; l <= STAGE_OUTRO; l++)
2085 {
2086 // Check if this sample is loaded into a source atm
2087 if (sound_type_data[sounds_list[sound_source_data[j].loaded_sound].sound].variant[k].part[l] &&
2088 sound_type_data[sounds_list[sound_source_data[j].loaded_sound].sound].variant[k].part[l]->sample_num == i)
2089 {
2090 found = 1;
2091 break;
2092 }
2093 }
2094 if (found)
2095 break; // No need to keep looking
2096 }
2097 if (found)
2098 break; // No need to keep looking
2099 }
2100 if (!found)
2101 {
2102 // This is an unused sample
2103 unload_sample(i);
2104 sample_num = i;
2105 #ifdef _EXTRA_SOUND_DEBUG
2106 printf("Found unused sample slot: %d\n", i);
2107 #endif //_EXTRA_SOUND_DEBUG
2108 break;
2109 }
2110 }
2111 if (sample_num == -1)
2112 {
2113 // We didn't find an available sample slot so error and bail
2114 #ifdef _EXTRA_SOUND_DEBUG
2115 LOG_ERROR("Error: Too many samples loaded. Unable to load sample: %s, num samples: %d\n", in_filename, num_samples);
2116 #endif //_EXTRA_SOUND_DEBUG
2117 return -1;
2118 }
2119 }
2120
2121 #ifdef _EXTRA_SOUND_DEBUG
2122 printf("Got sample num: %d, Attemping to load sound: File: %s\n", sample_num, in_filename);
2123 #endif //_EXTRA_SOUND_DEBUG
2124
2125 num_samples++;
2126 pSample = &sound_sample_data[sample_num];
2127
2128 // Add the data dir to the front of the input filename
2129 safe_strncpy(filename, datadir, sizeof(filename));
2130 safe_strcat(filename, in_filename, sizeof(filename));
2131
2132 // Load the file into memory
2133 data = load_ogg_into_memory(filename, &pSample->format, &datasize, &pSample->freq);
2134 if (!data)
2135 {
2136 // Couldn't load the file, so release this sample num
2137 num_samples--;
2138 // We have already dumped an error message so just return
2139 return -1;
2140 }
2141
2142 #ifdef _EXTRA_SOUND_DEBUG
2143 printf("Result: File: %s, Format: %d, Size: %d, Freq: %f\n", filename, (int)pSample->format, (int)datasize, (float)pSample->freq);
2144 #endif //_EXTRA_SOUND_DEBUG
2145
2146 // Create a buffer for the sample
2147 pBuffer = &pSample->buffer;
2148 alGenBuffers(1, pBuffer);
2149 if ((error=alGetError()) != AL_NO_ERROR)
2150 {
2151 // Couldn't generate a buffer
2152 LOG_ERROR("Error generating buffer: %s", alGetString(error));
2153 #ifdef _EXTRA_SOUND_DEBUG
2154 printf("Error generating buffer: %s\n", alGetString(error));
2155 #endif //_EXTRA_SOUND_DEBUG
2156 *pBuffer = 0;
2157 // Get rid of the temporary data
2158 free(data);
2159 return -1;
2160 }
2161
2162 // Send this data to the buffer
2163 alBufferData(*pBuffer, pSample->format, data, datasize, pSample->freq);
2164 if ((error=alGetError()) != AL_NO_ERROR)
2165 {
2166 LOG_ERROR("Error loading buffer: %s", alGetString(error));
2167 #ifdef _EXTRA_SOUND_DEBUG
2168 printf("Error loading buffer: %s\n", alGetString(error));
2169 #endif //_EXTRA_SOUND_DEBUG
2170 alDeleteBuffers(1, pBuffer);
2171 // Get rid of the temporary data
2172 free(data);
2173 return -1;
2174 }
2175
2176 alGetBufferi(*pBuffer, AL_BITS, &pSample->bits);
2177 alGetBufferi(*pBuffer, AL_CHANNELS, &pSample->channels);
2178 alGetBufferi(*pBuffer, AL_SIZE, &pSample->size);
2179
2180 pSample->length = (pSample->size * 1000) / ((pSample->bits >> 3) * pSample->channels * pSample->freq);
2181
2182 // Get rid of the temporary data
2183 free(data);
2184
2185 if ((error=alGetError()) != AL_NO_ERROR)
2186 {
2187 #ifdef _EXTRA_SOUND_DEBUG
2188 printf("Error in ensure_sample_loaded: %s, Filename: %s\n", alGetString(error), filename);
2189 #endif //_EXTRA_SOUND_DEBUG
2190 }
2191 return sample_num;
2192 }
2193
load_samples(sound_type * pType)2194 int load_samples(sound_type * pType)
2195 {
2196 int i, j;
2197 // Choose a variant
2198 j = rand() % pType->num_variants;
2199 // Check we can load all samples used by this type
2200 for (i = 0; i < num_STAGES; ++i)
2201 {
2202 if (pType->variant[j].part[i] && pType->variant[j].part[i]->sample_num < 0 && strcasecmp(pType->variant[j].part[i]->file_path, ""))
2203 {
2204 pType->variant[j].part[i]->sample_num = ensure_sample_loaded(pType->variant[j].part[i]->file_path);
2205 if (pType->variant[j].part[i]->sample_num < 0)
2206 {
2207 #ifdef _EXTRA_SOUND_DEBUG
2208 printf("Error: problem loading sample: %s\n", pType->variant[j].part[i]->file_path);
2209 #endif //_EXTRA_SOUND_DEBUG
2210 return -1;
2211 }
2212 }
2213 }
2214 return j; // Return the variant we chose
2215 }
2216
release_sample(int sample_num)2217 void release_sample(int sample_num)
2218 {
2219 sound_sample * pSample;
2220
2221 // Check we have a valid sample_num
2222 if (sample_num < 0 || sample_num >= MAX_BUFFERS)
2223 return;
2224
2225 pSample = &sound_sample_data[sample_num];
2226
2227 // Release the buffer used by this sample
2228 if (alIsBuffer(pSample->buffer))
2229 alDeleteBuffers(1, &pSample->buffer);
2230 // Reset the array element
2231 pSample->buffer = 0;
2232 pSample->format = 0;
2233 pSample->size = 0;
2234 pSample->freq = 0;
2235 pSample->channels = 0;
2236 pSample->bits = 0;
2237 pSample->length = 0;
2238 }
2239
unload_sample(int sample_num)2240 void unload_sample(int sample_num)
2241 {
2242 int i, j, k;
2243
2244 // Check we have a valid sample_num
2245 if (sample_num < 0 || sample_num >= MAX_BUFFERS)
2246 return;
2247
2248 // Find the places this sample is listed and reset them
2249 for (i = 0; i < num_types; i++)
2250 {
2251 for (j = 0; j < sound_type_data[i].num_variants; j++)
2252 {
2253 for (k = 0; k < num_STAGES; k++)
2254 {
2255 if (sound_type_data[i].variant[j].part[k] && sound_type_data[i].variant[j].part[k]->sample_num == sample_num)
2256 {
2257 sound_type_data[i].variant[j].part[k]->sample_num = -1;
2258 }
2259 }
2260 }
2261 }
2262 // Release the buffer used by this sample and reset the array element
2263 release_sample(sample_num);
2264 }
2265
2266
2267
2268
2269 /*****************************************
2270 * INDIVIDUAL SOUND PROCESSING FUNCTIONS *
2271 *****************************************/
2272
add_server_sound(int type,int x,int y,int gain)2273 unsigned int add_server_sound(int type, int x, int y, int gain)
2274 {
2275 int snd = -1;
2276 // Find the sound for this server sound type
2277 snd = server_sound[type];
2278 if (snd > -1)
2279 {
2280 #ifdef _EXTRA_SOUND_DEBUG
2281 printf("Adding server sound: %d\n", type);
2282 #endif //_EXTRA_SOUND_DEBUG
2283 return add_sound_object_gain(snd, x, y, 0, gain);
2284 }
2285 else
2286 {
2287 LOG_ERROR("Unable to find server sound: %i", type);
2288 return 0;
2289 }
2290 }
2291
2292 // Wrapper function for adding walking sounds.
add_walking_sound(int type,int x,int y,int me,float scale)2293 unsigned int add_walking_sound(int type, int x, int y, int me, float scale)
2294 {
2295 return add_sound_object_gain(type, x, y, me, scale);
2296 }
2297
2298 /* Wrapper function for adding map based particle sounds
2299 *
2300 * Due to only a subset of sound information being programmed into the map data, sounds
2301 * are triggered by the addition of each particle system. This causes problems for fires,
2302 * fountains, waterfalls and anything that is made of multiple particle systems.
2303 *
2304 * To fix this, this function checks for any existing sounds in a similar location before
2305 * loading this one.
2306 */
add_map_sound(int type,int x,int y)2307 unsigned int add_map_sound(int type, int x, int y)
2308 {
2309 int i;
2310 const int buffer = 5;
2311 // Check if there is another sound within +/-5 (buffer) tiles around this position
2312 for (i = 0; i < MAX_BUFFERS * 2; i++)
2313 {
2314 if (x >= sounds_list[i].x - buffer
2315 && x <= sounds_list[i].x + buffer
2316 && y >= sounds_list[i].y - buffer
2317 && y <= sounds_list[i].y + buffer
2318 && type == sounds_list[i].sound)
2319 {
2320 // There is a sound of this type already within this space so ignore this one
2321 return 0;
2322 }
2323 }
2324 return add_sound_object_gain(type, x, y, 0, 1.0f);
2325 }
2326
2327 // Wrapper for regular particle sounds (non-map based) to avoid the location check
add_particle_sound(int type,int x,int y)2328 unsigned int add_particle_sound(int type, int x, int y)
2329 {
2330 return add_sound_object_gain(type, x, y, 0, 1.0f);
2331 }
2332
2333 // Add a wrapper for under-the-influence-of-spell sounds
add_spell_sound(int spell)2334 unsigned int add_spell_sound(int spell)
2335 {
2336 if (spell >= 0 && spell < NUM_ACTIVE_SPELLS && sound_spell_data[spell] > -1)
2337 {
2338 // Add the sound
2339 return add_sound_object_gain(sound_spell_data[spell], 0, 0, 1, 1.0f);
2340 }
2341 return 0;
2342 }
2343
add_death_sound(actor * act)2344 unsigned int add_death_sound(actor * act)
2345 {
2346 int snd;
2347 // Check the type of this actor has a death sound (only used for enhanced actors as simple
2348 // actors are triggered though the cal animation)
2349 if (!act)
2350 return 0;
2351 snd = actors_defs[act->actor_type].cal_frames[cal_actor_die1_frame].sound;
2352 if (snd > -1)
2353 {
2354 return add_sound_object_gain(snd, act->x_pos, act->y_pos, act == your_actor ? 1 : 0, 1.0f);
2355 }
2356 return 0;
2357 }
2358
add_battlecry_sound(actor * act)2359 unsigned int add_battlecry_sound(actor * act)
2360 {
2361 // Maybe play a battlecry sound
2362 if (act && rand() % 3 == 2) // 1 chance in 3 to play
2363 {
2364 return add_sound_object_gain(actors_defs[act->actor_type].battlecry.sound,
2365 act->x_pos * 2,
2366 act->x_pos * 2,
2367 act == your_actor ? 1 : 0,
2368 actors_defs[act->actor_type].battlecry.scale
2369 );
2370 }
2371 return 0;
2372 }
2373
add_sound_object(int type,int x,int y,int me)2374 unsigned int add_sound_object(int type, int x, int y, int me)
2375 {
2376 return add_sound_object_gain(type, x, y, me, 1.0f);
2377 }
2378
add_sound_object_gain(int type,int x,int y,int me,float initial_gain)2379 unsigned int add_sound_object_gain(int type, int x, int y, int me, float initial_gain)
2380 {
2381 int tx, ty, distanceSq, sound_num, cookie;
2382 sound_type *pNewType;
2383 float maxDistanceSq = 0.0f;
2384
2385 /* Torg: Checks for sound enabled etc have been removed as we should load sounds even if currently
2386 disabled, as they may be enabled within the duration of this sound (eg. rain and map sounds). We just
2387 won't play them yet.
2388 */
2389
2390 // Check if we have a sound config, and thus if its worth doing anything
2391 if (num_types < 1)
2392 return 0;
2393
2394 // Get our position
2395 if (your_actor)
2396 {
2397 tx = your_actor->x_pos * 2;
2398 ty = your_actor->y_pos * 2;
2399 }
2400 else
2401 {
2402 tx = 0;
2403 ty = 0;
2404 }
2405 #ifdef _EXTRA_SOUND_DEBUG
2406 printf("Trying to add sound: %d (%s) at %d, %d. Position: %d, %d, Gain: %f\n", type, type > -1 ? sound_type_data[type].name : "not defined", x, y, tx, ty, initial_gain);
2407 #endif //_EXTRA_SOUND_DEBUG
2408 if (type == -1) // Invalid sound, ignore
2409 return 0;
2410
2411 if (me)
2412 {
2413 // Override the x & y values to use the camera (listener) position because its me
2414 x = tx;
2415 y = ty;
2416 }
2417
2418 // Check it's a valid type, get pType as a pointer to the type data
2419 if (type >= MAX_SOUNDS || type >= num_types || type < 0)
2420 {
2421 LOG_ERROR("%s: %i", snd_invalid_number, type);
2422 #ifdef _EXTRA_SOUND_DEBUG
2423 printf("Apparently an invalid type: %d\n", type);
2424 #endif //_EXTRA_SOUND_DEBUG
2425 return 0;
2426 }
2427 pNewType = &sound_type_data[type];
2428
2429 // Check if this sound is played at this time of day
2430 if (!time_of_day_valid(pNewType->time_of_the_day_flags))
2431 {
2432 #ifdef _EXTRA_SOUND_DEBUG
2433 printf("Not playing this sound at this time of the day: Flags: 0x%x, Time: %d\n", pNewType->time_of_the_day_flags, game_minute);
2434 #endif //_EXTRA_SOUND_DEBUG
2435 return 0;
2436 }
2437
2438 // Check this sound doesn't already exist in the sounds list and just isn't loaded
2439 /* for (i = 0; i < MAX_BUFFERS * 2; i++)
2440 {
2441 if (sounds_list[i].sound == type && sounds_list[i].x == x && sounds_list[i].y == y && sounds_list)
2442 return 0; // This sound already exists so let update_sound handle it
2443 }
2444 */
2445 // Find a spot in the sounds list for this sound
2446 sound_num = get_loaded_sound_num();
2447 if (sound_num == -1)
2448 {
2449 // Check if we should bother erroring - an overflow of sounds when sound is disabled we can ignore
2450 if (have_sound && sound_on)
2451 {
2452 #ifdef _EXTRA_SOUND_DEBUG
2453 printf("Error: Too many sounds loaded!! n00b! Not playing this sound: %d (%s)\n", type, pNewType->name);
2454 #endif //_EXTRA_SOUND_DEBUG
2455 LOG_ERROR("Error: Too many sounds loaded. Not playing this sound: %d (%s)\n", type, pNewType->name);
2456 }
2457 return 0;
2458 }
2459
2460 // We got this far so add this sound to the list and assign it a cookie
2461 LOCK_SOUND_LIST();
2462
2463 sounds_list[sound_num].sound = type;
2464 sounds_list[sound_num].variant = -1; // Haven't chosen a variant yet - that's done by load_samples()
2465 sounds_list[sound_num].x = x;
2466 sounds_list[sound_num].y = y;
2467 sounds_list[sound_num].loaded = 0;
2468 sounds_list[sound_num].playing = 0;
2469 sounds_list[sound_num].base_gain = initial_gain;
2470 sounds_list[sound_num].cur_gain = -1.0f; // Make sure we set the gain when we first play the sound
2471 cookie = get_next_cookie();
2472 sounds_list[sound_num].cookie = cookie;
2473 num_sounds++;
2474
2475 // Check if we should try to load the samples (sound is enabled)
2476 if (inited && have_sound && sound_on)
2477 {
2478 // Load all samples used by this type
2479 sounds_list[sound_num].variant = load_samples(pNewType);
2480 if (sounds_list[sound_num].variant < 0)
2481 {
2482 // Unable to load all the samples. We have already errored so mark it as not loaded and bail.
2483 sounds_list[sound_num].loaded = 0;
2484 UNLOCK_SOUND_LIST();
2485 return cookie;
2486 }
2487 sounds_list[sound_num].loaded = 1;
2488
2489 // Check if we are playing this sound now (and need to load it into a source)
2490 distanceSq = (tx - x) * (tx - x) + (ty - y) * (ty - y);
2491 maxDistanceSq = pNewType->distance * pNewType->distance;
2492
2493 if (!pNewType->positional || (distanceSq <= maxDistanceSq))
2494 {
2495 if (!play_sound(sound_num, x, y, initial_gain))
2496 {
2497 #ifdef _EXTRA_SOUND_DEBUG
2498 printf("There was an error so not playing this sound: %d, Cookie: %d\n", type, cookie);
2499 #endif //_EXTRA_SOUND_DEBUG
2500 }
2501 }
2502 #ifdef _EXTRA_SOUND_DEBUG
2503 else
2504 {
2505 printf("Not playing this sound as we are out of range! maxDistanceSq: %d, distanceSq: %d. Loaded as: %d, Cookie: %d\n", (int)maxDistanceSq, distanceSq, sound_num, cookie);
2506 }
2507 #endif //_EXTRA_SOUND_DEBUG
2508 }
2509 #ifdef _EXTRA_SOUND_DEBUG
2510 else
2511 {
2512 // Sound isn't enabled so bail now. When sound is enabled, these sounds (if applicable) will be
2513 // loaded and played then
2514 printf("Not playing this sound as sound isn't enabled yet. Inited: %d, Have sound: %d, Sound on: %d, Cookie: %d\n", inited, have_sound, sound_on, cookie);
2515 }
2516 #endif //_EXTRA_SOUND_DEBUG
2517
2518 // We have added the sound to the list so return the cookie
2519 UNLOCK_SOUND_LIST();
2520 return cookie;
2521 }
2522
play_sound(int sound_num,int x,int y,float initial_gain)2523 int play_sound(int sound_num, int x, int y, float initial_gain)
2524 {
2525 int loops, error;
2526 #ifdef _EXTRA_SOUND_DEBUG
2527 int err = 0;
2528 #endif // _EXTRA_SOUND_DEBUG
2529 ALuint buffer = 0;
2530 SOUND_STAGE stage;
2531 ALfloat sourcePos[] = {x, y, 0.0};
2532 ALfloat sourceVel[] = {0.0, 0.0, 0.0};
2533 source_data * pSource;
2534 sound_variants * pVariant;
2535 sound_type * pNewType = &sound_type_data[sounds_list[sound_num].sound];
2536
2537 // Check if we have a sound device and its worth continuing
2538 if (!inited)
2539 return 0;
2540
2541 #ifdef _EXTRA_SOUND_DEBUG
2542 printf("Playing this sound: %d, Sound num: %d, Cookie: %d\n", sounds_list[sound_num].sound, sound_num, sounds_list[sound_num].cookie);
2543 #endif //_EXTRA_SOUND_DEBUG
2544
2545 // Check if we need to load the samples into buffers
2546 if (!sounds_list[sound_num].loaded)
2547 {
2548 sounds_list[sound_num].variant = load_samples(pNewType);
2549 if (sounds_list[sound_num].variant < 0)
2550 {
2551 return 0;
2552 }
2553 sounds_list[sound_num].loaded = 1;
2554 }
2555 pVariant = &pNewType->variant[sounds_list[sound_num].variant];
2556
2557 pSource = get_available_source(pNewType->priority);
2558 if (!pSource)
2559 {
2560 #ifdef _EXTRA_SOUND_DEBUG
2561 printf("Sound overflow: %s, %d\n", pNewType->name, max_sources);
2562 #endif //_EXTRA_SOUND_DEBUG
2563 LOG_ERROR("%s: %d sources allocated", snd_sound_overflow, max_sources);
2564 return 0;
2565 }
2566
2567 // Check if we have an intro. We already quit if the sound doesn't have a main.
2568 stage = !pVariant->part[STAGE_INTRO] || pVariant->part[STAGE_INTRO]->sample_num < 0 ? STAGE_MAIN : STAGE_INTRO;
2569
2570 // Initialise the source data to the first sample to be played for this sound
2571 pSource->play_duration = 0;
2572 pSource->loaded_sound = sound_num;
2573 pSource->current_stage = stage;
2574
2575 alSourcef(pSource->source, AL_PITCH, 1.0f);
2576 set_sound_gain(pSource, sound_num, initial_gain);
2577 alSourcefv(pSource->source, AL_VELOCITY, sourceVel);
2578 alSourcefv(pSource->source, AL_POSITION, sourcePos);
2579 if ((error=alGetError()) != AL_NO_ERROR)
2580 {
2581 #ifdef _EXTRA_SOUND_DEBUG
2582 printf("Error with alSourcef calls: %s. Name: %s. Source: %d: %s\n", snd_source_error, pNewType->name, pSource->source, alGetString(error));
2583 #endif //_EXTRA_SOUND_DEBUG
2584 }
2585
2586 #ifdef _EXTRA_SOUND_DEBUG
2587 if (!alIsSource(pSource->source))
2588 {
2589 printf("Source corruption! %d, %d, %d\n", pSource->source, sounds_list[sound_num].sound, sounds_list[sound_num].cookie);
2590 release_source(pSource, -1);
2591 return 0;
2592 }
2593 else
2594 {
2595 int tmp = 0;
2596 alGetSourcei(pSource->source, AL_SOURCE_TYPE, &tmp);
2597 if ((error=alGetError()) != AL_NO_ERROR)
2598 {
2599 printf("Error getting source status! %s, %d, %d, %d\n", alGetString(error), pSource->source, sounds_list[sound_num].sound, sounds_list[sound_num].cookie);
2600 }
2601 else if (tmp == AL_STATIC)
2602 {
2603 printf("Found a static source! This isn't meant to exist! %d, %d\n", pSource->source, sounds_list[sound_num].sound);
2604 }
2605 }
2606 #endif //_EXTRA_SOUND_DEBUG
2607
2608 // Ensure the source is ready for queueing (attach a NULL buffer to reset it)
2609 alSourcei(pSource->source, AL_BUFFER, 0);
2610 #ifdef _EXTRA_SOUND_DEBUG
2611 if ((error=alGetError()) != AL_NO_ERROR)
2612 {
2613 printf("Error resetting source! %d, %d\n", pSource->source, sounds_list[sound_num].sound);
2614 }
2615 #endif //_EXTRA_SOUND_DEBUG
2616
2617 for (; stage < num_STAGES; ++stage)
2618 {
2619 // Get the buffer to be queued.
2620 if (!pVariant->part[stage] || pVariant->part[stage]->sample_num < 0)
2621 continue;
2622 buffer = sound_sample_data[pVariant->part[stage]->sample_num].buffer;
2623 pSource->sample[stage] = pVariant->part[stage]->sample_num;
2624 #ifdef _EXTRA_SOUND_DEBUG
2625 printf("Stage: %d, Buffer address: %d\n", stage, buffer);
2626 #endif //_EXTRA_SOUND_DEBUG
2627
2628 // If there are a finite number of loops for main sample, queue them all here
2629 if (stage == STAGE_MAIN)
2630 {
2631 if (pNewType->loops > 0)
2632 {
2633 for (loops = 0; loops < pNewType->loops; ++loops)
2634 {
2635 alSourceQueueBuffers(pSource->source, 1, &buffer);
2636 #ifdef _EXTRA_SOUND_DEBUG
2637 if ((error=alGetError()) != AL_NO_ERROR)
2638 {
2639 printf("Error with sample alSourceQueueBuffers: %s, Name: %s. Source: %d, Loops: %d/%d\n", alGetString(error), pNewType->name, pSource->source, loops, pNewType->loops);
2640 err = 1;
2641 }
2642 #endif //_EXTRA_SOUND_DEBUG
2643 }
2644 }
2645 else
2646 {
2647 alSourceQueueBuffers(pSource->source, 1, &buffer);
2648 #ifdef _EXTRA_SOUND_DEBUG
2649 if ((error=alGetError()) != AL_NO_ERROR)
2650 {
2651 printf("Error with looped sample alSourceQueueBuffers: %s, Name: %s. Source: %d\n", alGetString(error), pNewType->name, pSource->source);
2652 err = 1;
2653 }
2654 #endif //_EXTRA_SOUND_DEBUG
2655 // Dont queue an outro that will never get played!
2656 break;
2657 }
2658 }
2659 else
2660 {
2661 alSourceQueueBuffers(pSource->source, 1, &buffer);
2662 #ifdef _EXTRA_SOUND_DEBUG
2663 if ((error=alGetError()) != AL_NO_ERROR)
2664 {
2665 printf("Error with intro/outro sample alSourceQueueBuffers: %s, Name: %s. Source: %d\n", alGetString(error), pNewType->name, pSource->source);
2666 err = 1;
2667 }
2668 #endif //_EXTRA_SOUND_DEBUG
2669 }
2670 }
2671 add_source_to_lists(pSource);
2672 #ifdef _EXTRA_SOUND_DEBUG
2673 if (err != 0)
2674 {
2675 #else //_EXTRA_SOUND_DEBUG
2676 if ((error=alGetError()) != AL_NO_ERROR)
2677 {
2678 LOG_ERROR("Error with alSourceQueueBuffers: %s, Name: %s. Source: %d\n", alGetString(error), pNewType->name, pSource->source);
2679 #endif //_EXTRA_SOUND_DEBUG
2680 release_source(pSource, -1);
2681 return 0;
2682 }
2683
2684 if (!pNewType->positional)
2685 {
2686 alSourcei(pSource->source, AL_SOURCE_RELATIVE, AL_TRUE);
2687 }
2688 else
2689 {
2690 alSourcei(pSource->source, AL_SOURCE_RELATIVE, AL_FALSE);
2691 alSourcef(pSource->source, AL_REFERENCE_DISTANCE , 10.0f);
2692 alSourcef(pSource->source, AL_ROLLOFF_FACTOR , 4.0f);
2693 }
2694 if ((pVariant->part[STAGE_INTRO] && pVariant->part[STAGE_INTRO]->sample_num < 0 && pNewType->loops == 0) ||
2695 (!pVariant->part[STAGE_INTRO] && pNewType->loops == 0))
2696 // 0 is infinite looping
2697 alSourcei(pSource->source,AL_LOOPING,AL_TRUE);
2698 else
2699 alSourcei(pSource->source,AL_LOOPING,AL_FALSE);
2700
2701 alSourcePlay(pSource->source);
2702 sounds_list[sound_num].playing = 1;
2703
2704 pSource->cookie = sounds_list[sound_num].cookie;
2705
2706 // Check and clear any AL error
2707 if ((error=alGetError()) != AL_NO_ERROR)
2708 {
2709 #ifdef _EXTRA_SOUND_DEBUG
2710 printf("Error setting source properties/playing source: %s, Name: %s. Source: %d, Cookie: %d\n", alGetString(error), pNewType->name, pSource->source, sounds_list[sound_num].cookie);
2711 #endif // _EXTRA_SOUND_DEBUG
2712 }
2713
2714 #ifdef _EXTRA_SOUND_DEBUG
2715 printf("Playing %d sources\n", used_sources);
2716 #endif // _EXTRA_SOUND_DEBUG
2717
2718 return 1; // Return success
2719 }
2720
2721 unsigned int get_next_cookie()
2722 {
2723 unsigned int cookie = next_cookie;
2724
2725 // If next_cookie wraps around back to 0 then address this.
2726 if (++next_cookie == 0) ++next_cookie;
2727
2728 return cookie;
2729 }
2730
2731 int get_loaded_sound_num()
2732 {
2733 int i;
2734 // Loop through the array looking for an unused spot (sound = -1 && cookie = 0)
2735 for (i = 0; i < MAX_BUFFERS * 2; i++)
2736 {
2737 if (sounds_list[i].sound == -1 && sounds_list[i].cookie == 0)
2738 {
2739 return i;
2740 }
2741 }
2742 return -1;
2743 }
2744
2745 // This is passed a cookie, and searches for a sound and source (if ness) with this cookie
2746 void stop_sound(unsigned long int cookie)
2747 {
2748 int n, m;
2749
2750 // Cookie of 0 is an invalid sound handle
2751 if (!cookie)
2752 return;
2753
2754 // Find which sound matches this cookie
2755 n = find_sound_from_cookie(cookie);
2756 #ifdef _EXTRA_SOUND_DEBUG
2757 printf("Removing cookie: %ld, Sound number: %d\n", cookie, n);
2758 #endif //_EXTRA_SOUND_DEBUG
2759 if (n >= 0)
2760 {
2761 #ifdef _EXTRA_SOUND_DEBUG
2762 printf("Stopping cookie %ld with sound index %d. It is currently %splaying.\n", cookie, n, sounds_list[n].playing ? "" : "not ");
2763 #endif //_EXTRA_SOUND_DEBUG
2764 if (sounds_list[n].playing)
2765 {
2766 // Find which of our playing sources matches the handle passed
2767 LOCK_SOUND_LIST();
2768 m = find_sound_source_from_cookie(cookie);
2769 if (m >= 0)
2770 {
2771 stop_sound_source_at_index(m);
2772 }
2773 #ifdef _EXTRA_SOUND_DEBUG
2774 else
2775 {
2776 printf("ERROR! Unable to find source for cookie %ld with sound index %d. It is meant to be currently playing.\n", cookie, n);
2777 }
2778 #endif //_EXTRA_SOUND_DEBUG
2779 UNLOCK_SOUND_LIST();
2780 }
2781 sounds_list[n].playing = 0;
2782 unload_sound(n);
2783 }
2784 }
2785
2786 void stop_sound_at_location(int x, int y)
2787 {
2788 int i = 0;
2789
2790 // Search for a sound at the given location
2791 for (i = 0; i < MAX_BUFFERS * 2; i++)
2792 {
2793 if (sounds_list[i].x == x && sounds_list[i].y == y)
2794 {
2795 stop_sound(sounds_list[i].cookie);
2796 }
2797 }
2798 }
2799
2800 // Kill all the not playing and looping sounds. Useful when we change maps, etc.
2801 void stop_all_sounds()
2802 {
2803 int i;
2804 ALuint error;
2805
2806 if (!inited) return;
2807
2808 LOCK_SOUND_LIST();
2809
2810 #ifdef _EXTRA_SOUND_DEBUG
2811 printf("Stopping all individual sounds\n");
2812 #endif //_EXTRA_SOUND_DEBUG
2813 for (i = 0; i < MAX_BUFFERS * 2; i++)
2814 {
2815 // Check if this is a loaded sound that isn't going to finish by itself (not playing or loops)
2816 if (sounds_list[i].cookie != 0 && (!sounds_list[i].playing || sound_type_data[sounds_list[i].sound].loops == 0))
2817 {
2818 #ifdef _EXTRA_SOUND_DEBUG
2819 printf("Stopping sound %d (%s), cookie: %d, used_sources: %d\n", i, sound_type_data[sounds_list[i].sound].name, sounds_list[i].cookie, used_sources);
2820 #endif //_EXTRA_SOUND_DEBUG
2821 stop_sound(sounds_list[i].cookie);
2822 }
2823 }
2824
2825 for (i = 0; i < max_streams; i++)
2826 {
2827 // Fade the music stream down (we can use it again after the map change) but destroy any other streams
2828 if (streams[i].type == STREAM_TYPE_MUSIC)
2829 streams[i].fade = -1;
2830 else
2831 {
2832 #ifdef _EXTRA_SOUND_DEBUG
2833 printf("Stopping %s stream source: %d\n", get_stream_type(streams[i].type), streams[i].source);
2834 #endif //_EXTRA_SOUND_DEBUG
2835 destroy_stream(&streams[i]);
2836 }
2837 }
2838
2839 UNLOCK_SOUND_LIST();
2840
2841 if ((error=alGetError()) != AL_NO_ERROR)
2842 {
2843 #ifdef _EXTRA_SOUND_DEBUG
2844 printf("Error killing all sounds\n");
2845 #endif //_EXTRA_SOUND_DEBUG
2846 }
2847
2848 must_restart_spell_sounds = 1;
2849 }
2850
2851 void unload_sound(int index)
2852 {
2853 // Reset this sound
2854 sounds_list[index].sound = -1;
2855 sounds_list[index].x = -1;
2856 sounds_list[index].y = -1;
2857 sounds_list[index].playing = 0;
2858 sounds_list[index].loaded = 0;
2859 sounds_list[index].cookie = 0;
2860 sounds_list[index].lifetime = 0;
2861 num_sounds--;
2862 }
2863
2864 // -- Update the sound system --
2865 // We update our listener position and any sounds being played, as well as
2866 // rebuilding the list of active sources, as some may have become inactive
2867 // due to the sound ending or being out of range, or some may be back in
2868 // range and need to be played. We also adjust volumes if ness.
2869 void update_sound(int ms)
2870 {
2871 int i = 0, error = AL_NO_ERROR;
2872 source_data *pSource;
2873 #ifdef USE_ALGETSOURCEI_AL_BUFFER
2874 sound_sample *pSample;
2875 ALuint deadBuffer;
2876 ALint numProcessed, buffer;
2877 #endif
2878 sound_type *pSoundType;
2879 sound_variants *pVariant;
2880 ALint state;
2881
2882 int source;
2883 int x, y, distanceSq, maxDistSq;
2884 int relative;
2885 int tx = 0, ty = 0;
2886 ALfloat sourcePos[3] = {0.0f, 0.0f, 0.0f};
2887 ALfloat listenerPos[3] = {0.0f, 0.0f, 0.0f};
2888 ALfloat listenerVel[3] = {0.0f, 0.0f, 0.0f};
2889 ALfloat listenerOri[6] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
2890 #ifdef _EXTRA_SOUND_DEBUG
2891 int j;
2892 #endif // _EXTRA_SOUND_DEBUG
2893 int l;
2894
2895 // Check if we have a sound config, and thus if its worth doing anything (or sound is disabled)
2896 if (num_types < 1 || no_sound)
2897 return;
2898
2899 LOCK_ACTORS_LISTS();
2900 // Check if we have our actor
2901 if (your_actor)
2902 {
2903 // Set our position and the listener variables
2904 tx = your_actor->x_pos * 2;
2905 ty = your_actor->y_pos * 2;
2906 listenerPos[0] = tx;
2907 listenerPos[1] = ty;
2908 if (your_actor->z_rot > 0 && your_actor->z_rot < 180) {
2909 listenerOri[0] = 1;
2910 } else if (your_actor->z_rot > 180 && your_actor->z_rot < 360) {
2911 listenerOri[0] = -1;
2912 } else {
2913 listenerOri[0] = 0;
2914 }
2915 if (your_actor->z_rot > 315 || your_actor->z_rot < 90) {
2916 listenerOri[1] = 1;
2917 } else if (your_actor->z_rot > 135 && your_actor->z_rot < 225) {
2918 listenerOri[1] = -1;
2919 } else {
2920 listenerOri[1] = 0;
2921 }
2922 // a map change or sound-off will have stopped spell sounds,
2923 // now we have our actor, we can re-enable the spell sounds
2924 if (must_restart_spell_sounds && !disconnected)
2925 {
2926 restart_active_spell_sounds();
2927 must_restart_spell_sounds = 0;
2928 }
2929 }
2930
2931 // Start to process the sounds
2932 LOCK_SOUND_LIST();
2933
2934 // Check the sounds_list for anything to be loaded/played
2935 for (i = 0; i < MAX_BUFFERS * 2; i++)
2936 {
2937 // If this sound is "live"
2938 if (sounds_list[i].sound > -1)
2939 {
2940 pSoundType = &sound_type_data[sounds_list[i].sound];
2941 // Update the length of time this sound has been alive
2942 sounds_list[i].lifetime += ms;
2943 // Check for any non-looping sounds in the sounds_list that aren't being played that have passed their time
2944 if (sounds_list[i].lifetime >= 1000 && !sounds_list[i].playing && pSoundType->loops != 0)
2945 {
2946 #ifdef _EXTRA_SOUND_DEBUG
2947 printf("Sound (%d) timed out: %d (%s), Cookie: %d, Lifetime: %d\n", i, sounds_list[i].sound, pSoundType->name, sounds_list[i].cookie, sounds_list[i].lifetime);
2948 #endif //_EXTRA_SOUND_DEBUG
2949 stop_sound(sounds_list[i].cookie);
2950 continue;
2951 }
2952 // Check for any sounds that aren't being played and check if they need to be because
2953 // sound has now been enabled or they have come back into range
2954 x = sounds_list[i].x;
2955 y = sounds_list[i].y;
2956 if (inited && !sounds_list[i].playing && x > -1 && y > -1 && sounds_list[i].sound > -1)
2957 {
2958 distanceSq = (tx - x) * (tx - x) + (ty - y) * (ty - y);
2959 maxDistSq = pSoundType->distance * pSoundType->distance;
2960 if (sound_on && (distanceSq < maxDistSq))
2961 {
2962 // This sound is back in range so load it into a source and play it
2963 #ifdef _EXTRA_SOUND_DEBUG
2964 printf("Sound now in-range: %d (%s), Distance squared: %d, Max: %d\n", sounds_list[i].sound, pSoundType->name, distanceSq, maxDistSq);
2965 #endif //_EXTRA_SOUND_DEBUG
2966 sounds_list[i].cur_gain = -1.0f; // Make sure we recalculate this sound's volume
2967 if (!play_sound(i, x, y, sounds_list[i].base_gain))
2968 {
2969 #ifdef _EXTRA_SOUND_DEBUG
2970 printf("Error restarting sound!!\n");
2971 #endif //_EXTRA_SOUND_DEBUG
2972 }
2973 }
2974 }
2975 }
2976 }
2977
2978 // Check if we have a sound device and its worth continuing
2979 if (!inited)
2980 {
2981 UNLOCK_SOUND_LIST();
2982 UNLOCK_ACTORS_LISTS();
2983 return;
2984 }
2985
2986 // Update the position of the listener
2987 alListenerfv(AL_POSITION, listenerPos);
2988 alListenerfv(AL_VELOCITY, listenerVel);
2989 alListenerfv(AL_ORIENTATION, listenerOri);
2990
2991 // Check if we have any sounds playing currently (this includes streams so is sometimes a little redundant)
2992 if (!used_sources)
2993 {
2994 UNLOCK_SOUND_LIST();
2995 UNLOCK_ACTORS_LISTS();
2996 return;
2997 }
2998
2999 #ifdef _EXTRA_SOUND_DEBUG
3000 j = 0;
3001 #endif // _EXTRA_SOUND_DEBUG
3002 // Now, update the position of actor (animation) sounds
3003 for (i = 0; i < max_actors; i++)
3004 {
3005 if (!actors_list[i] || !actors_list[i]->cur_anim_sound_cookie)
3006 continue;
3007
3008 source = find_sound_source_from_cookie(actors_list[i]->cur_anim_sound_cookie);
3009 if (source < 0)
3010 continue;
3011
3012 // Check if this is the correct tile type, or if we need to play another sound
3013 if (actors_list[i]->moving && !actors_list[i]->fighting)
3014 {
3015 UNLOCK_SOUND_LIST();
3016 handle_walking_sound(actors_list[i], actors_list[i]->cur_anim.sound);
3017 LOCK_SOUND_LIST();
3018 }
3019 if (actors_list[i]->actor_id == yourself)
3020 {
3021 // If this is you, use the same position as the listener
3022 sourcePos[0] = tx;
3023 sourcePos[1] = ty;
3024 }
3025 else
3026 {
3027 sourcePos[0] = actors_list[i]->x_pos * 2;
3028 sourcePos[1] = actors_list[i]->y_pos * 2;
3029 }
3030 sourcePos[2] = 0.0f;
3031 alSourcefv(sound_source_data[source].source, AL_POSITION, sourcePos);
3032 }
3033
3034 UNLOCK_ACTORS_LISTS();
3035
3036 // Finally, update all the sources
3037 i = 0;
3038 #ifdef _EXTRA_SOUND_DEBUG
3039 j = 0;
3040 #endif // _EXTRA_SOUND_DEBUG
3041
3042 while (i < used_sources)
3043 {
3044 pSource = &sound_source_data[i];
3045 #ifdef _EXTRA_SOUND_DEBUG
3046 j++;
3047 if (j > max_sources)
3048 {
3049 LOG_ERROR("update_sound race condition!! i = %d, used_sources = %d\n", i, used_sources);
3050 printf("update_sound race condition!! i = %d, used_sources = %d\n", i, used_sources);
3051 break;
3052 }
3053 #endif // _EXTRA_SOUND_DEBUG
3054
3055 // Check if this is a source we should ignore (streams)
3056 if (pSource->current_stage == STAGE_STREAM)
3057 {
3058 pSource->play_duration += ms;
3059 ++i;
3060 ++pSource;
3061 continue;
3062 }
3063
3064 // Check for invalid sources -- This test should be redundant!
3065 if (pSource->cookie == 0 || pSource->loaded_sound < 0 || sounds_list[pSource->loaded_sound].sound < 0 || pSource->current_stage == STAGE_UNUSED)
3066 {
3067 #ifdef _EXTRA_SOUND_DEBUG
3068 printf("Removing dud sound %d. Cookie: %d, Source Num: %d, Source: %d. Current stage: %d\n", pSource->loaded_sound, pSource->cookie, i, pSource->source, pSource->current_stage);
3069 #endif //_EXTRA_SOUND_DEBUG
3070 if (pSource->loaded_sound >= 0)
3071 unload_sound(pSource->loaded_sound);
3072 stop_sound_source_at_index(i);
3073 continue;
3074 }
3075
3076 // Update the gain for this source if nessessary
3077 set_sound_gain(pSource, pSource->loaded_sound, sounds_list[pSource->loaded_sound].base_gain);
3078
3079 pSoundType = &sound_type_data[sounds_list[pSource->loaded_sound].sound];
3080 pVariant = &pSoundType->variant[sounds_list[pSource->loaded_sound].variant];
3081 #ifdef USE_ALGETSOURCEI_AL_BUFFER
3082 pSample = &sound_sample_data[pVariant->part[pSource->current_stage]->sample_num];
3083 #endif
3084
3085 // Is this source still playing?
3086 alGetSourcei(pSource->source, AL_SOURCE_STATE, &state);
3087 if (state == AL_STOPPED)
3088 {
3089 #ifdef _EXTRA_SOUND_DEBUG
3090 // printf("'%s' has stopped after sample '%s'\n", pSoundType->name, pVariant->part[pSource->current_stage]->file_path);
3091 #endif //_EXTRA_SOUND_DEBUG
3092 // Flag the sound as finished
3093 pSource->current_stage = num_STAGES;
3094 }
3095 else
3096 {
3097 // TBD - Fix properly
3098 // Newer versions of openal do not suppport using alGetSourcei() in this way.
3099 // Older versions appear to have always returned (buffer == pSample->buffer) so fall to the else block.
3100 // Newer versions always return buffer == 0 so the if block is always called, resulting in most sounds never playing.
3101 // The else catches completed sounds anyway so just force the older behavour for now.
3102 // The links below cover the openal library change and suggested way to achieve the same behavout ... TDB....
3103 // https://github.com/kcat/openal-soft/issues/126
3104 // https://github.com/kcat/openal-soft/commit/5c859af24ea44dabbbb31631309bb08a858a523e
3105 #ifdef USE_ALGETSOURCEI_AL_BUFFER // exclude block
3106 // Find which buffer is playing
3107 alGetSourcei(pSource->source, AL_BUFFER, &buffer);
3108 if (buffer != pSample->buffer)
3109 {
3110 // The source has moved on to the next queued sample
3111 #ifdef _EXTRA_SOUND_DEBUG
3112 printf("Cookie: %d, Loaded sound: %d, sound: %d, '%s' - sample '%s' has ended...", pSource->cookie, pSource->loaded_sound, sounds_list[pSource->loaded_sound].sound, pSoundType->name, pVariant->part[pSource->current_stage]->file_path);
3113 k = 0;
3114 #endif //_EXTRA_SOUND_DEBUG
3115 while (++pSource->current_stage <= num_STAGES)
3116 {
3117 #ifdef _EXTRA_SOUND_DEBUG
3118 k++;
3119 if (k > num_STAGES)
3120 {
3121 LOG_ERROR("update_sound race condition!! cur stage = %d, num_stages = %d\n", pSource->current_stage, num_STAGES);
3122 printf("update_sound race condition!! cur stage = %d, num_stages = %d\n", pSource->current_stage, num_STAGES);
3123 pSource->current_stage = num_STAGES;
3124 break;
3125 }
3126 #endif // _EXTRA_SOUND_DEBUG
3127 if (!pVariant->part[pSource->current_stage] || pVariant->part[pSource->current_stage]->sample_num < 0)
3128 {
3129 // No more samples to play
3130 #ifdef _EXTRA_SOUND_DEBUG
3131 printf("no more samples for this type!\n");
3132 #endif //_EXTRA_SOUND_DEBUG
3133 pSource->current_stage = num_STAGES;
3134 break;
3135 }
3136 pSample = &sound_sample_data[pVariant->part[pSource->current_stage]->sample_num];
3137 // Found the currently-playing buffer
3138
3139 if (pSample->buffer == buffer)
3140 {
3141 #ifdef _EXTRA_SOUND_DEBUG
3142 printf("next sample is '%s'\n", pVariant->part[pSource->current_stage]->file_path);
3143 #endif //_EXTRA_SOUND_DEBUG
3144 if (pSource->current_stage == STAGE_MAIN && pSoundType->loops == 0)
3145 {
3146 // We've progressed to the main sample which loops infinitely.
3147 #ifdef _EXTRA_SOUND_DEBUG
3148 l = 0;
3149 #endif // _EXTRA_SOUND_DEBUG
3150 do
3151 {
3152 #ifdef _EXTRA_SOUND_DEBUG
3153 l++;
3154 if (l > 10)
3155 {
3156 LOG_ERROR("update_sound race condition!! cur buffer = %d, k = %d\n", numProcessed, l);
3157 printf("update_sound race condition!! cur buffer = %d, k = %d\n", numProcessed, l);
3158 break;
3159 }
3160 #endif // _EXTRA_SOUND_DEBUG
3161 // We only unqueue buffers explicitly here so that there's only the
3162 // MAIN sample queued for the looping. Normally we just set a zero
3163 // buffer to the source which automatically unqueues any buffers
3164 alGetSourcei(pSource->source, AL_BUFFERS_PROCESSED, &numProcessed);
3165 if (numProcessed-- > 0)
3166 alSourceUnqueueBuffers(pSource->source, 1, &deadBuffer);
3167 }
3168 while (numProcessed > 0);
3169
3170 alSourcei(pSource->source, AL_LOOPING, AL_TRUE);
3171 if ((error=alGetError()) != AL_NO_ERROR)
3172 {
3173 LOG_ERROR("update_sound error: %s", alGetString(error));
3174 }
3175 }
3176 break;
3177 }
3178 }
3179 }
3180 else
3181 #endif // end USE_ALGETSOURCEI_AL_BUFFER exclude block
3182 {
3183 if (pSoundType->loops != 0)
3184 {
3185 // Check if something odd happened and this source wasn't stopped when the sample finished (lifetime > sum of sample lengths)
3186 int lifetime = 0;
3187 for (l = 0; l <= pSource->current_stage; l++)
3188 if (pVariant->part[l])
3189 lifetime += sound_sample_data[pVariant->part[l]->sample_num].length;
3190 if (sounds_list[pSource->loaded_sound].lifetime > lifetime)
3191 {
3192 #ifdef _EXTRA_SOUND_DEBUG
3193 printf("This sound has passed its lifetime (%d ms)! It should have been stopped!: %d (%s). Playing: %d, lifetime: %d, cookie: %d\n",
3194 lifetime, sounds_list[pSource->loaded_sound].sound, pSoundType->name, sounds_list[pSource->loaded_sound].playing,
3195 sounds_list[pSource->loaded_sound].lifetime, sounds_list[pSource->loaded_sound].cookie);
3196 #endif //_EXTRA_SOUND_DEBUG
3197 unload_sound(pSource->loaded_sound);
3198 stop_sound_source_at_index(i);
3199 continue;
3200 }
3201 }
3202 }
3203 }
3204
3205 // Check if we need to remove this sound because its finished
3206 // If the state is num_STAGES then the sound has ended (or gone wrong)
3207 if (pSource->current_stage == num_STAGES)
3208 {
3209 #ifdef _EXTRA_SOUND_DEBUG
3210 printf("Removing finished sound %d (%s) at cookie %d, source index %d, source %d, loaded_sound: %d\n", sounds_list[pSource->loaded_sound].sound, pSoundType->name, pSource->cookie, i, pSource->source, pSource->loaded_sound);
3211 #endif //_EXTRA_SOUND_DEBUG
3212 unload_sound(pSource->loaded_sound);
3213 stop_sound_source_at_index(i);
3214 continue;
3215 }
3216
3217 // Check if this source is out of range, or back in range (an error!)
3218 alGetSourcei(pSource->source, AL_SOURCE_RELATIVE, &relative);
3219 if (relative != AL_TRUE)
3220 {
3221 alGetSourcei(pSource->source, AL_SOURCE_STATE, &state);
3222 alGetSourcefv(pSource->source, AL_POSITION, sourcePos);
3223 x = sourcePos[0]; y = sourcePos[1];
3224 distanceSq = (tx - x) * (tx - x) + (ty - y) * (ty - y);
3225 maxDistSq = pSoundType->distance * pSoundType->distance;
3226
3227 if ((state == AL_PLAYING) && (distanceSq > maxDistSq))
3228 {
3229 #ifdef _EXTRA_SOUND_DEBUG
3230 printf("Pausing sound: %d (%s), Distance squared: %d, Max: %d\n", i, pSoundType->name, distanceSq, maxDistSq);
3231 #endif //_EXTRA_SOUND_DEBUG
3232 // Free up this source
3233 sounds_list[pSource->loaded_sound].playing = 0;
3234 stop_sound_source_at_index(i);
3235 continue;
3236 }
3237 else if (sound_on && (state == AL_PAUSED) && (distanceSq < maxDistSq))
3238 {
3239 LOG_ERROR("Sound error: We found a wasted source. Sound %d (%s) was loaded into a source and paused!!\n", i, pSoundType->name);
3240 alSourcePlay(pSource->source);
3241 sounds_list[pSource->loaded_sound].playing = 1;
3242 }
3243 if ((error=alGetError()) != AL_NO_ERROR)
3244 {
3245 LOG_ERROR("update_sound %s: %s", my_tolower(reg_error_str), alGetString(error));
3246 }
3247 }
3248 pSource->play_duration += ms;
3249 ++i;
3250 ++pSource;
3251 }
3252
3253 UNLOCK_SOUND_LIST();
3254
3255 if ((error=alGetError()) != AL_NO_ERROR)
3256 {
3257 #ifdef _EXTRA_SOUND_DEBUG
3258 printf("Error updating sound: %s\n", alGetString(error));
3259 #endif //_EXTRA_SOUND_DEBUG
3260 }
3261 }
3262
3263
3264 /*********************
3265 * GENERAL FUNCTIONS *
3266 *********************/
3267
3268
3269 void handle_walking_sound(actor * pActor, int def_snd)
3270 {
3271 float x, y;
3272 int snd, cur_sound;
3273
3274 if (pActor->cur_anim.sound_scale > 0.0f)
3275 {
3276 // This creature is large enough for a walking sound so look for one
3277 x = pActor->x_pos;
3278 y = pActor->y_pos;
3279
3280 // Start with the sound from the animation
3281 snd = def_snd;
3282
3283 /* Unfortunatly these functions aren't ready for release.
3284 They need help to be accurate, possibly from the under_mouse or get_intersect type code.
3285 Alternatively a check for objects around the actor and then checking the size and rotation
3286 of each object to determine if the actor is standing on it might work.
3287
3288 // Check for a 3d object we have a sound for
3289 snd = get_3d_obj_walk_sound(get_3dobject_at_location(x, y));
3290
3291 // Check if we need to look for a 2d obj, and look if necessary
3292 if (snd == -1)
3293 snd = get_2d_obj_walk_sound(get_2dobject_at_location(x, y));
3294 */
3295
3296 // If we still don't have a sound, check for a defined area (the same as map boundary areas).
3297 // NOTE: This code can and should be removed when the above functions are fixed.
3298 if (snd == -1)
3299 snd = get_boundary_walk_sound((int)(x * 2), (int)(y * 2));
3300
3301 // Finally, check if we need to look for a tile, and look if necessary
3302 if (snd == -1)
3303 snd = get_tile_sound(get_tile_type((int)(x * 2), (int)(y * 2)), actors_defs[pActor->actor_type].actor_name);
3304
3305 #ifdef _EXTRA_SOUND_DEBUG
3306 // printf("Actor: %s, Pos: %f, %f, Found sound: %d, Scale: %f\n", pActor->actor_name, pActor->x_pos, pActor->y_pos, snd, actors_defs[pActor->actor_type].walk_snd_scale);
3307 #endif // _EXTRA_SOUND_DEBUG
3308
3309 if (snd == -1)
3310 // Still no sound, so fall back on the global default
3311 snd = walking_default;
3312
3313 // Check for something to do
3314 if (snd > -1)
3315 {
3316 // Check if we have a sound and it is different to the current one
3317 cur_sound = find_sound_from_cookie(pActor->cur_anim_sound_cookie);
3318 if (cur_sound >= 0 && sounds_list[cur_sound].sound != snd && sound_type_data[sounds_list[cur_sound].sound].type == SOUNDS_WALKING)
3319 {
3320 // It is valid and different so remove the current sound before we add the new one
3321 stop_sound(pActor->cur_anim_sound_cookie);
3322 }
3323 if (cur_sound < 0 || sounds_list[cur_sound].sound != snd)
3324 {
3325 // Add the new sound
3326 pActor->cur_anim_sound_cookie = add_walking_sound( snd,
3327 2 * pActor->x_pos,
3328 2 * pActor->y_pos,
3329 pActor->actor_id == yourself ? 1 : 0,
3330 pActor->cur_anim.sound_scale
3331 );
3332 }
3333 }
3334 }
3335 }
3336
3337 int get_boundary_walk_sound(int tx, int ty)
3338 {
3339 int i, snd = -1;
3340
3341 if (snd_cur_map > -1 && (sound_map_data[snd_cur_map].file_name[0] != '\0' || sound_map_data[snd_cur_map].id > -1) )
3342 {
3343 for (i = 0; i < sound_map_data[snd_cur_map].num_walk_boundaries; i++)
3344 {
3345 if (i == sound_map_data[snd_cur_map].num_walk_boundaries)
3346 i = 0;
3347 snd = sound_map_data[snd_cur_map].walk_boundaries[i].bg_sound;
3348 if (snd > -1 && sound_bounds_check(tx, ty, &sound_map_data[snd_cur_map].walk_boundaries[i]))
3349 {
3350 return snd;
3351 }
3352 }
3353 }
3354 return -1;
3355 }
3356
3357 int get_3d_obj_walk_sound(char * filename)
3358 {
3359 if (!strcasecmp(filename, ""))
3360 return -1;
3361 #ifdef _EXTRA_SOUND_DEBUG
3362 printf("Searching for the sound for 3D object: %s\n", filename);
3363 #endif //_EXTRA_SOUND_DEBUG
3364 return -1;
3365 }
3366
3367 int get_2d_obj_walk_sound(char * filename)
3368 {
3369 if (!strcasecmp(filename, ""))
3370 return -1;
3371 #ifdef _EXTRA_SOUND_DEBUG
3372 printf("Searching for the sound for 2D object: %s\n", filename);
3373 #endif //_EXTRA_SOUND_DEBUG
3374 return -1;
3375 }
3376
3377 int get_tile_sound(int tile_type, char * actor_type)
3378 {
3379 int i, j, k;
3380
3381 // Check for unknown/invalid tile type
3382 if (tile_type == -1)
3383 return -1;
3384
3385 for (i = 0; i < MAX_SOUND_TILE_TYPES; i++)
3386 {
3387 for (j = 0; j < sound_tile_data[i].num_tile_types; j++)
3388 {
3389 if (sound_tile_data[i].tile_type[j] == tile_type)
3390 {
3391 // Found a matching tile type so find the actor type
3392 for (k = 0; k < sound_tile_data[i].num_sounds; k++)
3393 {
3394 if (get_string_occurance(actor_type, sound_tile_data[i].sounds[k].actor_types, strlen(actor_type), 0) > -1)
3395 {
3396 // Return the sound
3397 return sound_tile_data[i].sounds[k].sound;
3398 }
3399 }
3400 // Didn't find a sound, so return a default if it exists
3401 return sound_tile_data[i].default_sound;
3402 }
3403 }
3404 }
3405 // If we got here, we don't have a sound for this tile type
3406 return -1;
3407 }
3408
3409
3410 void setup_map_sounds (const char * mapname)
3411 {
3412 int i;
3413 #ifdef DEBUG_MAP_SOUND
3414 char str[100];
3415 safe_snprintf(str, sizeof(str), "Map file name: %s", mapname);
3416 LOG_TO_CONSOLE(c_red1, str);
3417 #endif // DEBUG_MAP_SOUND
3418 // Find the index for this map in our data
3419 snd_cur_map = -1;
3420 for (i = 0; i < sound_num_maps; i++)
3421 {
3422 if (strcmp (sound_map_data[i].file_name, mapname) == 0 || get_cur_map(mapname) == sound_map_data[i].id)
3423 {
3424 snd_cur_map = i;
3425 #ifdef DEBUG_MAP_SOUND
3426 safe_snprintf(str, sizeof(str), "Snd config map name: %s", sound_map_data[i].name);
3427 LOG_TO_CONSOLE(c_red1, str);
3428 print_sound_boundary_coords(mapname);
3429 #endif // DEBUG_MAP_SOUND
3430 return;
3431 }
3432 }
3433 }
3434
3435 // Find the index of the sound associated with this cookie.
3436 int find_sound_from_cookie(unsigned int cookie)
3437 {
3438 int n;
3439
3440 if (!cookie || cookie == 0)
3441 return -1;
3442
3443 for (n = 0; n < MAX_BUFFERS * 2; n++)
3444 {
3445 if (sounds_list[n].cookie == cookie)
3446 return n;
3447 }
3448
3449 return -1;
3450 }
3451
3452 int get_index_for_sound_type_name(const char *name)
3453 {
3454 int i;
3455 for(i = 0; i < num_types; ++i)
3456 {
3457 if (strcasecmp(sound_type_data[i].name, name) == 0)
3458 return i;
3459 }
3460 return -1;
3461 }
3462
3463 // Look for a particle sound def matching the input filename
3464 // (minus the directory ./particles/ and extension .part)
3465 int get_sound_index_for_particle_file_name(const char *name)
3466 {
3467 char my_name[MAX_FILENAME_LENGTH];
3468 int i;
3469 safe_strncpy(my_name, name+12, sizeof(my_name));
3470 my_name[strlen(my_name) - 5] = '\0';
3471 for(i = 0; i < sound_num_particles; ++i)
3472 {
3473 if (strcasecmp(sound_particle_data[i].file, my_name) == 0)
3474 return sound_particle_data[i].sound;
3475 }
3476 return -1;
3477 }
3478
3479 // Looks for a sound effect def matching the input special effect
3480 int get_sound_index_for_sfx(int sfx)
3481 {
3482 int i;
3483 for(i = 0; i < sound_num_effects; ++i)
3484 {
3485 if (sound_effect_data[i].id == sfx)
3486 return sound_effect_data[i].sound;
3487 }
3488 return -1;
3489 }
3490
3491 int get_index_for_inv_usewith_item_sound(int use_image_id, int with_image_id)
3492 {
3493 char name[MAX_SOUND_NAME_LENGTH];
3494
3495 #ifdef _EXTRA_SOUND_DEBUG
3496 printf("Searching for the sound for: %d on %d\n", use_image_id, with_image_id);
3497 #endif //_EXTRA_SOUND_DEBUG
3498 snprintf(name, sizeof(name), "%d on %d", use_image_id, with_image_id);
3499 return get_index_for_sound_type_name(name);
3500 }
3501
3502 int get_index_for_inv_use_item_sound(int image_id)
3503 {
3504 int i, j;
3505 #ifdef _EXTRA_SOUND_DEBUG
3506 printf("Searching for the sound for image ID: %d\n", image_id);
3507 #endif //_EXTRA_SOUND_DEBUG
3508 for (i = 0; i < sound_num_items; ++i)
3509 {
3510 for (j = 0; j < sound_item_data[i].num_imageids; j++)
3511 {
3512 if (sound_item_data[i].image_id[j] == image_id)
3513 return sound_item_data[i].sound;
3514 }
3515 }
3516 return -1;
3517 }
3518
3519 int check_sound_loops(unsigned int cookie)
3520 {
3521 int snd = find_sound_from_cookie(cookie);
3522 if (snd > -1 && sound_type_data[sounds_list[snd].sound].loops == 0)
3523 return 1;
3524 return 0;
3525 }
3526
3527 void check_sound_alerts(const Uint8* text, size_t len, Uint8 channel)
3528 {
3529 int i;
3530 for (i = 0; i < num_sound_warnings; i++)
3531 {
3532 if (safe_strcasestr((char *)text, len, warnings_list[i].string, strlen(warnings_list[i].string)))
3533 {
3534 add_sound_object_gain(warnings_list[i].sound, 0, 0, 1, 1.0f);
3535 return; // Only play one sound
3536 }
3537 }
3538 return;
3539 }
3540
3541 // Compare the input flags to the current time and return true if they match
3542 int time_of_day_valid(int flags)
3543 {
3544 return flags & (1 << (game_minute / 30));
3545 }
3546
3547 /* sound_bounds_check
3548 *
3549 * Check if input point (x, y) is within the input boundary
3550 *
3551 * Initially test to see if the point given is within the outer boundary given by the extreme of the coords. If
3552 * it is, then continue with the more complex test of each boundary line.
3553 *
3554 * We will do this by checking the angle of the line created between each of the 4 points of the boundaries and
3555 * comparing that angle to the line created by each point and our test point.
3556 *
3557 */
3558 int sound_bounds_check(int x, int y, map_sound_boundary_def * bounds)
3559 {
3560 int pX, pY, npX, npY;
3561 int i, j, result;
3562
3563 // Initially check if we are on or inside the outermost box
3564 if (x < bounds->o[0].x || y < bounds->o[0].y || x > bounds->o[1].x || y > bounds->o[1].y)
3565 return 0; // We are outside the outer rectangle so can't be inside the polygon
3566
3567 // Check if we have only 2 points (rectangle) and are therefore don't need to do anything more
3568 if (bounds->p[2].x == -1 || bounds->p[2].y == -1 || bounds->p[3].x == -1 || bounds->p[3].y == -1)
3569 return 1;
3570
3571 // Check if we are inside the 4 lines of the polygon
3572 for (i = 0; i < 4; i++)
3573 {
3574 j = i + 1;
3575 if (j == 4) j = 0; // Wrap the next point var around to 0
3576 pX = bounds->p[i].x;
3577 pY = bounds->p[i].y;
3578 npX = bounds->p[j].x;
3579 npY = bounds->p[j].y;
3580
3581 /* Psuedo-code to explain this block of nastiness
3582
3583 If (this is not an internal point, OR
3584 (if the x coord of our test point is within the x bounds of the line with p <= np AND
3585 ((the y coord is within the line with p <= np AND the point is within the y bounds of the line (bottom left quadrant)) OR
3586 (the y coord is within the line with p > np AND the point is within the y bounds of the line (top left quadrant))
3587 ) OR
3588 (if the x coord is within the x bounds of the line with p > np AND
3589 ((the y coord is within the line with p <= np AND the point is within the y bounds of the line (bottom right quadrant)) OR
3590 (the y coord is within the line with p > np AND the the point is within the y bounds of the line (top right quadrant))
3591 )
3592 ) ...then we need to test the angle otherwise we can ignore this point
3593 */
3594 if (bounds->int_point != i ||
3595 (pX <= npX && x >= pX && x <= pX &&
3596 ((pY <= npY && y >= pY && y <= pY) ||
3597 (pY > npY && y <= pY && y >= pY))
3598 ) ||
3599 (pX > npX && x <= pX && x >= pX &&
3600 ((pY <= npY && y >= pY && y <= pY) ||
3601 (pY > npY && y <= pY && y >= pY))
3602 )
3603 )
3604 {
3605 result = test_bounds_angles(x, y, i, bounds);
3606 if (result == 0) return 0;
3607 }
3608 }
3609
3610 // This point is inside the 4 lines
3611 return 1;
3612 }
3613
3614 int test_bounds_angles(int x, int y, int point, map_sound_boundary_def * bounds)
3615 {
3616 double a = calculate_bounds_angle(x, y, point, bounds);
3617
3618 // If our angle for the test point is greater than the angle of the boundary line, then the point is outside
3619 if (a > bounds->p[point].a)
3620 return 0;
3621 return 1;
3622 }
3623
3624 /* This function is the complex one!
3625 *
3626 * If you notice the pattern for the subsitutions below, it is because we are rotating the 0 degree angle around
3627 * the axis to keep it on the outside of the polygon. We need to do this because if our test line crosses from
3628 * > 2pi to < 2pi it will give a false positive.
3629 *
3630 * For point 0 the "illegal zone" is straight down, for point 1 horizontally left, for point 2 straight up, and
3631 * for point 3 horizontally right.
3632 *
3633 * This is why point 0 (or A in my diagrams) is the bottom left as nothing should cross it there, and so on for
3634 * the other points around the polygon. Each "illegal zone" should be pointing outside almost all permutations of
3635 * a polygon.
3636 *
3637 * If none of this makes sense then grab one of my drawings and if it still doesn't then ask. Grab me and ask.
3638 * - Torg -
3639 *
3640 * Inputs:
3641 * x The x coord of our test point
3642 * y The y coord of our test point
3643 * point The ID of the boundary point we are calculating from
3644 * bounds The boundary we are calculating this point of
3645 */
3646 double calculate_bounds_angle(int x, int y, int point, map_sound_boundary_def * bounds)
3647 {
3648 int A = 0,
3649 B = 0,
3650 C = 0,
3651 D = 0;
3652 double pi = 3.1415;
3653 double ra = pi / 2; // ra = Right angle... meh
3654 double a;
3655
3656 // Set up the subsitutions for the actual equation. (This is such a waste of space. Grrr)
3657 switch (point)
3658 {
3659 case 0:
3660 // Check the angle of the line from the bottom left corner to our test point (point0 -> pointT)
3661 A = bounds->p[0].y;
3662 B = y;
3663 C = bounds->p[0].x;
3664 D = x;
3665 break;
3666 case 1:
3667 // Check the angle of the line from the top left corner to our test point (point1 -> pointT)
3668 A = bounds->p[1].x;
3669 B = x;
3670 C = y;
3671 D = bounds->p[1].y;
3672 break;
3673 case 2:
3674 // Check the angle of the line from the top right corner to our test point (point2 -> pointT)
3675 A = y;
3676 B = bounds->p[2].y;
3677 C = x;
3678 D = bounds->p[2].x;
3679 break;
3680 case 3:
3681 // Check the angle of the line from the bottom right corner to our test point (point3 -> pointT)
3682 A = x;
3683 B = bounds->p[3].x;
3684 C = bounds->p[3].y;
3685 D = y;
3686 break;
3687 }
3688 // If the line aligns to an axis, arctan has no value, so we need to check for this and use 90 degrees (pi / 2)
3689 // Otherwise calculate the angle and adjust the negative
3690 if (A == B && C < D) a = ra; // If axis 1 is aligned and the coord on axis 2 of the first point is less
3691 else if (A == B && C > D) a = -ra; // If axis 1 is aligned and the coord on axis 2 of the first point is greater
3692 else a = atan2((D - C), (A - B)); // If we aren't on the axis, find the angle
3693 if (D < C) a += pi * 2; // If the second point is below the axis (-pi) then boost the angle to the positive (2pi)
3694 // This gives us a proper range from 0 to 2pi counter clockwise around the polygon
3695
3696 return a;
3697 }
3698
3699 #ifdef DEBUG_MAP_SOUND
3700 // Print the sound area boundaries onto the tab-map (called from interface.c)
3701 //
3702 // It is a known bug that this _does not_ scale to the map selected. The scale will stay the same as your currently loaded map!
3703 //
3704 void print_sound_boundaries(const char *mapname)
3705 {
3706 int i, i_max, j, id = -1, scale = 6, num_def = 0;
3707 char buf[256];
3708 map_sound_boundary_def *bounds;
3709 bound_point p[4];
3710
3711 // Check if this map matches an array id
3712 for (i = 0; i < MAX_SOUND_MAPS; i++) {
3713 if (strcmp (sound_map_data[i].file_name, mapname) == 0 || get_cur_map(mapname) == sound_map_data[i].id ) {
3714 id = i;
3715 break;
3716 }
3717 }
3718 if (id == -1) return; // Didn't find the map in our array so bail
3719
3720 // count default boundary sounds - they do not have points
3721 for (i=0; i<sound_map_data[id].num_boundaries; i++)
3722 if (sound_map_data[id].boundaries[i].is_default)
3723 num_def++;
3724
3725 glEnable (GL_TEXTURE_2D);
3726 glColor3f (1.0f, 1.0f, 1.0f);
3727 safe_snprintf(buf, sizeof(buf), "Map File Name: %s, Array ID: %d\nMap Name: %s\nNum Bound: %d (%d def), Num Walk: %d", mapname, id, sound_map_data[id].name,
3728 sound_map_data[id].num_boundaries, num_def, sound_map_data[id].num_walk_boundaries);
3729 draw_string_zoomed_width_font(main_map_screen_x_left, main_map_screen_y_bottom/10, (unsigned char*)buf, main_map_screen_x_right-main_map_screen_x_left,3,UI_FONT, get_global_scale());
3730 glDisable(GL_TEXTURE_2D);
3731 glBegin(GL_LINES);
3732 // Draw boundaries for this map
3733 for (j = 0; j < 2; j++) {
3734 if (j == 0) {
3735 i_max = sound_map_data[id].num_walk_boundaries;
3736 } else {
3737 i_max = sound_map_data[id].num_boundaries;
3738 }
3739 for (i = 0; i < i_max; i++) {
3740 if (j == 0) {
3741 bounds = &sound_map_data[id].walk_boundaries[i];
3742 glColor3f (0.0f, 0.0f, 1.0f);
3743 } else {
3744 bounds = &sound_map_data[id].boundaries[i];
3745 if (bounds->is_default)
3746 continue;
3747 glColor3f (1.0f, 0.0f, 0.0f);
3748 }
3749 if (bounds->p[2].x == -1 || bounds->p[2].y == -1 || bounds->p[3].x == -1 || bounds->p[3].y == -1)
3750 {
3751 p[0].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[0].x / (tile_map_size_x * scale);
3752 p[1].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[1].x / (tile_map_size_x * scale);
3753 p[2].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[1].x / (tile_map_size_x * scale);
3754 p[3].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[0].x / (tile_map_size_x * scale);
3755 p[0].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[0].y / (tile_map_size_y * scale);
3756 p[1].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[0].y / (tile_map_size_y * scale);
3757 p[2].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[1].y / (tile_map_size_y * scale);
3758 p[3].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[1].y / (tile_map_size_y * scale);
3759 }
3760 else
3761 {
3762 p[0].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[0].x / (tile_map_size_x * scale);
3763 p[1].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[1].x / (tile_map_size_x * scale);
3764 p[2].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[2].x / (tile_map_size_x * scale);
3765 p[3].x = main_map_screen_x_left + (main_map_screen_x_right - main_map_screen_x_left) * bounds->p[3].x / (tile_map_size_x * scale);
3766 p[0].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[0].y / (tile_map_size_y * scale);
3767 p[1].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[1].y / (tile_map_size_y * scale);
3768 p[2].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[2].y / (tile_map_size_y * scale);
3769 p[3].y = main_map_screen_y_bottom - (main_map_screen_y_bottom - main_map_screen_y_top) * bounds->p[3].y / (tile_map_size_y * scale);
3770 }
3771
3772 glVertex2i(p[0].x, p[0].y);
3773 glVertex2i(p[1].x, p[1].y);
3774
3775 glVertex2i(p[1].x, p[1].y);
3776 glVertex2i(p[2].x, p[2].y);
3777
3778 glVertex2i(p[2].x, p[2].y);
3779 glVertex2i(p[3].x, p[3].y);
3780
3781 glVertex2i(p[3].x, p[3].y);
3782 glVertex2i(p[0].x, p[0].y);
3783 }
3784 }
3785 glEnd();
3786 }
3787
3788 // Prints the sound boundary coords for the input map to stdout
3789 void print_sound_boundary_coords(const char *mapname)
3790 {
3791 int i, i_max, j, id = -1;
3792 map_sound_boundary_def *bounds;
3793
3794 // Check if this map matches an array id
3795 for (i = 0; i < MAX_SOUND_MAPS; i++) {
3796 if (strcmp (sound_map_data[i].file_name, mapname) == 0 || get_cur_map(mapname) == sound_map_data[i].id ) {
3797 id = i;
3798 break;
3799 }
3800 }
3801 if (id == -1) return; // Didn't find the map in our array so bail
3802
3803 printf("Map File Name: %s, Array ID: %d, Map Name: %s, ", mapname, id, sound_map_data[id].name);
3804 // Print boundaries for this map
3805 for (j = 0; j < 2; j++) {
3806 if (j == 0) {
3807 i_max = sound_map_data[id].num_walk_boundaries;
3808 printf("Num Walk Boundaries: %d\n", i_max);
3809 } else {
3810 i_max = sound_map_data[id].num_boundaries;
3811 printf("Num Boundaries: %d\n", i_max);
3812 }
3813 for (i = 0; i < i_max; i++) {
3814 if (j == 0) {
3815 bounds = &sound_map_data[id].walk_boundaries[i];
3816 } else {
3817 bounds = &sound_map_data[id].boundaries[i];
3818 }
3819 printf("Outer - 1: %d, %d; 2: %d, %d\n", bounds->o[0].x, bounds->o[0].y, bounds->o[1].x, bounds->o[1].y);
3820 printf("Points - 1: %d, %d; 2: %d, %d; 3: %d, %d; 4: %d, %d\n", bounds->p[0].x, bounds->p[0].y, bounds->p[1].x, bounds->p[1].y
3821 , bounds->p[2].x, bounds->p[2].y, bounds->p[3].x, bounds->p[3].y);
3822 }
3823 }
3824 }
3825 #endif // DEBUG_MAP_SOUND
3826
3827
3828
3829 /******************
3830 * INIT FUNCTIONS *
3831 ******************/
3832
3833 void clear_variant(sound_variants *pVariant)
3834 {
3835 int i;
3836 for (i = 0; i < num_STAGES; i++)
3837 {
3838 pVariant->part[i] = NULL;
3839 }
3840 pVariant->gain = 1.0f;
3841 }
3842
3843 void clear_sound_type(int type)
3844 {
3845 int i;
3846 sound_type * sound;
3847
3848 if (type < 0 || type > MAX_SOUNDS)
3849 return;
3850
3851 sound = &sound_type_data[type];
3852
3853 sound->name[0] = '\0';
3854 for (i = 0; i < MAX_SOUND_VARIANTS; i++)
3855 {
3856 clear_variant(&sound->variant[i]);
3857 }
3858 sound->num_variants = 0;
3859 sound->stereo = 0;
3860 sound->distance = 100.0f;
3861 sound->positional = 1;
3862 sound->loops = 1;
3863 sound->fadeout_time = 0;
3864 sound->echo_delay = 0;
3865 sound->echo_volume = 50;
3866 sound->time_of_the_day_flags = 0xffff;
3867 sound->priority = 5;
3868 sound->type = SOUNDS_ENVIRO;
3869 }
3870
3871 void clear_boundary_data(map_sound_boundary_def * pBoundary)
3872 {
3873 int i;
3874
3875 pBoundary->bg_sound = -1;
3876 pBoundary->crowd_sound = -1;
3877 pBoundary->time_of_day_flags = 0xffff;
3878 pBoundary->is_default = 0;
3879 for (i = 0; i < 4; i++)
3880 {
3881 pBoundary->p[i].x = -1;
3882 pBoundary->p[i].y = -1;
3883 pBoundary->p[i].a = -1;
3884 }
3885 pBoundary->o[0].x = -1;
3886 pBoundary->o[0].y = -1;
3887 pBoundary->o[1].x = -1;
3888 pBoundary->o[1].y = -1;
3889 pBoundary->int_point = -1;
3890 }
3891
3892 void clear_sound_data()
3893 {
3894 int i, j;
3895
3896 for (i = 0; i < MAX_BUFFERS * 2; i++)
3897 {
3898 sounds_list[i].sound = -1;
3899 sounds_list[i].x = -1;
3900 sounds_list[i].y = -1;
3901 sounds_list[i].cookie = 0;
3902 sounds_list[i].loaded = 0;
3903 sounds_list[i].playing = 0;
3904 sounds_list[i].base_gain = 0.0f;
3905 sounds_list[i].cur_gain = 0.0f;
3906 }
3907 for (i = 0; i < MAX_STREAMS; i++)
3908 {
3909 destroy_stream(&streams[i]);
3910 }
3911 for (i = 0; i < MAX_SOUNDS; i++)
3912 {
3913 clear_sound_type(i);
3914 }
3915 for (i = 0; i < MAX_BUFFERS; i++)
3916 {
3917 unload_sample(i);
3918 }
3919 for (i = 0; i < MAX_BACKGROUND_DEFAULTS; i++)
3920 {
3921 sound_background_defaults[i].time_of_day_flags = 0xffff;
3922 sound_background_defaults[i].map_type = 0;
3923 sound_background_defaults[i].sound = -1;
3924 }
3925 crowd_default = -1;
3926 walking_default = -1;
3927 for (i = 0; i < MAX_SOUND_MAPS; i++)
3928 {
3929 sound_map_data[i].id = -1;
3930 sound_map_data[i].file_name[0] = '\0';
3931 sound_map_data[i].name[0] = '\0';
3932 sound_map_data[i].num_boundaries = 0;
3933 for (j = 0; j < MAX_SOUND_MAP_BOUNDARIES; j++)
3934 {
3935 clear_boundary_data(&sound_map_data[i].boundaries[j]);
3936 }
3937 sound_map_data[i].num_walk_boundaries = 0;
3938 for (j = 0; j < MAX_SOUND_WALK_BOUNDARIES; j++)
3939 {
3940 clear_boundary_data(&sound_map_data[i].walk_boundaries[j]);
3941 }
3942 sound_map_data[i].num_defaults = 0;
3943 for (j = 0; j < MAX_MAP_BACKGROUND_DEFAULTS; j++)
3944 {
3945 sound_map_data[i].defaults[j] = 0;
3946 }
3947 }
3948 for (i = 0; i < MAX_SOUND_EFFECTS; i++)
3949 {
3950 sound_effect_data[i].id = 0;
3951 sound_effect_data[i].sound = -1;
3952 }
3953 for (i = 0; i < MAX_SOUND_PARTICLES; i++)
3954 {
3955 sound_particle_data[i].file[0] = '\0';
3956 sound_particle_data[i].sound = -1;
3957 }
3958 for (i = 0; i < MAX_SOUND_ITEMS; i++)
3959 {
3960 for (j = 0; j < MAX_ITEM_SOUND_IMAGE_IDS; j++)
3961 {
3962 sound_item_data[i].image_id[j] = -1;
3963 }
3964 sound_item_data[i].num_imageids = 0;
3965 sound_item_data[i].sound = -1;
3966 }
3967 for (i = 0; i < MAX_SOUND_TILE_TYPES; i++)
3968 {
3969 for (j = 0; j < MAX_SOUND_TILES; j++)
3970 {
3971 sound_tile_data[i].tile_type[j] = -1;
3972 }
3973 sound_tile_data[i].num_tile_types = 0;
3974 for (j = 0; j < MAX_SOUND_TILES_SOUNDS; j++)
3975 {
3976 sound_tile_data[i].sounds[j].actor_types[0] = '\0';
3977 sound_tile_data[i].sounds[j].sound = -1;
3978 }
3979 sound_tile_data[i].num_sounds = 0;
3980 sound_tile_data[i].default_sound = -1;
3981 }
3982 for (i = 0; i < MAX_SERVER_SOUNDS; i++)
3983 {
3984 server_sound[i] = -1;
3985 }
3986 for (i = 0; i < NUM_ACTIVE_SPELLS; i++)
3987 {
3988 sound_spell_data[i] = -1;
3989 }
3990 for (i = 0; i < MAX_SOUND_WARNINGS; i++)
3991 {
3992 warnings_list[i].sound = -1;
3993 warnings_list[i].string[0] = '\0';
3994 }
3995 for (i = 0; i < MAX_SOUND_FILES; i++)
3996 {
3997 sound_files[i].file_path[0] = '\0';
3998 sound_files[i].sample_num = -1;
3999 }
4000
4001 num_types = 0;
4002 num_samples = 0;
4003 sound_num_background_defaults = 0;
4004 sound_num_maps = 0;
4005 sound_num_effects = 0;
4006 sound_num_particles = 0;
4007 sound_num_items = 0;
4008 sound_num_tile_types = 0;
4009 num_sound_warnings = 0;
4010 num_sound_files = 0;
4011 }
4012
4013 /* done once at start up to create the sound list mutex */
4014 void initial_sound_init(void)
4015 {
4016 size_t i, j, k;
4017 sound_list_mutex = SDL_CreateMutex();
4018 if (!sound_list_mutex)
4019 {
4020 LOG_ERROR("Fatal error, unable to create sound list mutex: %s\n", SDL_GetError());
4021 SDL_Quit();
4022 exit(1);
4023 }
4024
4025 /* create arrays and do minimum initisation - memsetting to zero is not good enough.
4026 * These arrays were previous static and so valgrind could not determine if there were
4027 * memory access errors, this way we can work through them. How it worked before is
4028 * unknown. TO DO: Need to dedupe this code with clear_sound_data()....
4029 */
4030
4031 streams = (stream_data *)malloc(sizeof(stream_data) * MAX_STREAMS);
4032 for (i=0; i<MAX_STREAMS; i++)
4033 {
4034 streams[i].type = STREAM_TYPE_NONE;
4035 streams[i].sound = -1;
4036 streams[i].source = 0;
4037 streams[i].cookie = 0;
4038 memset(&streams[i].buffers, 0, sizeof(ALuint) * NUM_STREAM_BUFFERS);
4039 memset(&streams[i].stream, 0, sizeof(OggVorbis_File));
4040 streams[i].stream_opened = 0;
4041 streams[i].fade_length = 10;
4042 streams[i].boundary = NULL;
4043 streams[i].info = NULL;
4044 streams[i].fade = streams[i].processed = streams[i].playing = streams[i].variant = streams[i].is_default = 0;
4045 }
4046
4047 sounds_list = (sound_loaded *)malloc(sizeof(sound_loaded) * MAX_BUFFERS * 2);
4048 for (i=0; i<MAX_BUFFERS * 2; i++)
4049 {
4050 sounds_list[i].sound = sounds_list[i].variant = sounds_list[i].x = sounds_list[i].y = -1;
4051 sounds_list[i].loaded = sounds_list[i].playing = sounds_list[i].lifetime = 0;
4052 sounds_list[i].base_gain = sounds_list[i].cur_gain = 0.0f;
4053 sounds_list[i].cookie = 0;
4054 }
4055
4056 sound_source_data = (source_data*)malloc(sizeof(source_data) * ABS_MAX_SOURCES);
4057 for (i=0; i<ABS_MAX_SOURCES; i++)
4058 {
4059 source_data* p = &sound_source_data[i];
4060 p->source = 0;
4061 p->priority = p->play_duration = 0;
4062 p->current_stage = STAGE_UNUSED;
4063 p->loaded_sound = -1;
4064 p->cookie = 0;
4065 for (j=0; j<num_STAGES; j++)
4066 p->sample[j] = -1;
4067 }
4068
4069 sound_type_data = (sound_type*)malloc(sizeof(sound_type) * MAX_SOUNDS);
4070 for (i=0; i<MAX_SOUNDS; i++)
4071 {
4072 sound_type* p = &sound_type_data[i];
4073 p->name[0] = '\0';
4074 p->num_variants = p->stereo = p->fadeout_time = p->echo_delay = 0;
4075 p->echo_volume = 50;
4076 p->distance = 100.0f;
4077 p->time_of_the_day_flags = 0xffff;
4078 p->type = SOUNDS_NONE;
4079 p->positional = p->loops = 1;
4080 p->priority = p->loops = 50;
4081 for (j=0; j<MAX_SOUND_VARIANTS; j++)
4082 {
4083 for (k=0; k<num_STAGES; k++)
4084 p->variant[j].part[k] = NULL;
4085 p->variant[j].gain = 0.0f;
4086 }
4087 }
4088
4089 sound_sample_data = (sound_sample*)malloc(sizeof(sound_sample) * MAX_BUFFERS);
4090 for (i=0; i<MAX_BUFFERS; i++)
4091 {
4092 sound_sample* p = &sound_sample_data[i];
4093 p->sources = NULL;
4094 p->buffer = 0;
4095 p->format = 0;
4096 p->size = 0;
4097 p->freq = 0.0;
4098 p->channels = p->bits = 0;
4099 p->length = 0;
4100 }
4101
4102 // as clear_sound_data()
4103 sound_files = (sound_file*)malloc(sizeof(sound_file) * MAX_SOUND_FILES);
4104 for (i=0; i<MAX_SOUND_FILES; i++)
4105 {
4106 sound_files[i].file_path[0] = '\0';
4107 sound_files[i].sample_num = -1;
4108 }
4109
4110 sound_background_defaults = (background_default*)malloc(sizeof(background_default) * MAX_BACKGROUND_DEFAULTS);
4111 for (i=0; i<MAX_BACKGROUND_DEFAULTS; i++)
4112 {
4113 sound_background_defaults[i].time_of_day_flags = 0xffff;
4114 sound_background_defaults[i].map_type = 0;
4115 sound_background_defaults[i].sound = -1;
4116 }
4117
4118 sound_map_data = (map_sound_data*)malloc(sizeof(map_sound_data) * MAX_SOUND_MAPS);
4119 for (i=0; i<MAX_SOUND_MAPS; i++)
4120 {
4121 sound_map_data[i].num_boundaries = sound_map_data[i].num_defaults = sound_map_data[i].num_walk_boundaries = 0;
4122 sound_map_data[i].id = -1;
4123 sound_map_data[i].file_name[0] = '\0';
4124 }
4125
4126 // as clear_sound_data()
4127 sound_effect_data = (effect_sound_data*)malloc(sizeof(effect_sound_data) * MAX_SOUND_EFFECTS);
4128 for (i=0; i<MAX_SOUND_EFFECTS; i++)
4129 {
4130 sound_effect_data[i].id = 0;
4131 sound_effect_data[i].sound = -1;
4132 }
4133
4134 // as clear_sound_data()
4135 sound_particle_data = (particle_sound_data*)malloc(sizeof(particle_sound_data) * MAX_SOUND_PARTICLES);
4136 for (i=0; i<MAX_SOUND_PARTICLES; i++)
4137 {
4138 sound_particle_data[i].file[0] = '\0';
4139 sound_particle_data[i].sound = -1;
4140 }
4141
4142 // as clear_sound_data()
4143 sound_item_data = (item_sound_data*)malloc(sizeof(item_sound_data) * MAX_SOUND_ITEMS);
4144 for (i=0; i<MAX_SOUND_ITEMS; i++)
4145 {
4146 for (j = 0; j < MAX_ITEM_SOUND_IMAGE_IDS; j++)
4147 sound_item_data[i].image_id[j] = -1;
4148 sound_item_data[i].num_imageids = 0;
4149 sound_item_data[i].sound = -1;
4150 }
4151
4152 // as clear_sound_data()
4153 sound_tile_data = (tile_sound_data*)malloc(sizeof(tile_sound_data) * MAX_SOUND_TILE_TYPES);
4154 for (i=0; i<MAX_SOUND_TILE_TYPES; i++)
4155 {
4156 for (j = 0; j < MAX_SOUND_TILES; j++)
4157 {
4158 sound_tile_data[i].tile_type[j] = -1;
4159 }
4160 sound_tile_data[i].num_tile_types = 0;
4161 for (j = 0; j < MAX_SOUND_TILES_SOUNDS; j++)
4162 {
4163 sound_tile_data[i].sounds[j].actor_types[0] = '\0';
4164 sound_tile_data[i].sounds[j].sound = -1;
4165 }
4166 sound_tile_data[i].num_sounds = 0;
4167 sound_tile_data[i].default_sound = -1;
4168 }
4169
4170 // as clear_sound_data()
4171 server_sound = (int*)malloc(sizeof(int) * MAX_SERVER_SOUNDS);
4172 for (i=0; i<MAX_SERVER_SOUNDS; i++)
4173 server_sound[i] = -1;
4174
4175 // as clear_sound_data()
4176 sound_spell_data = (int*)malloc(sizeof(int) * NUM_ACTIVE_SPELLS);
4177 for (i=0; i<NUM_ACTIVE_SPELLS; i++)
4178 sound_spell_data[i] = -1;
4179
4180 // as clear_sound_data()
4181 warnings_list = (sound_warnings*)malloc(sizeof(sound_warnings) * MAX_SOUND_WARNINGS);
4182 for (i = 0; i < MAX_SOUND_WARNINGS; i++)
4183 {
4184 warnings_list[i].sound = -1;
4185 warnings_list[i].string[0] = '\0';
4186 }
4187
4188 // NOT as clear_sound_data()
4189 playlist = (playlist_entry*)malloc(sizeof(playlist_entry) * MAX_PLAYLIST_ENTRIES);
4190 clear_playlist();
4191
4192 // as clear_sound_data()
4193 num_types = 0;
4194 num_samples = 0;
4195 sound_num_background_defaults = 0;
4196 sound_num_maps = 0;
4197 sound_num_effects = 0;
4198 sound_num_particles = 0;
4199 sound_num_items = 0;
4200 sound_num_tile_types = 0;
4201 num_sound_warnings = 0;
4202 num_sound_files = 0;
4203
4204 return;
4205 }
4206
4207 static void clear_playlist(void)
4208 {
4209 size_t i;
4210 for (i=0; i<MAX_PLAYLIST_ENTRIES; i++)
4211 {
4212 playlist[i].file_name[0] = '\0';
4213 playlist[i].min_x = playlist[i].max_x = playlist[i].min_y = playlist[i].max_y = playlist[i].time = 0;
4214 }
4215 }
4216
4217 /* done once at exit to delete the sound list mutex */
4218 void final_sound_exit(void)
4219 {
4220 SDL_DestroyMutex(sound_list_mutex);
4221 sound_list_mutex = NULL;
4222 free(streams); streams = NULL;
4223 free(sounds_list); sounds_list = NULL;
4224 free(sound_source_data); sound_source_data = NULL;
4225 free(sound_type_data); sound_type_data = NULL;
4226 free(sound_sample_data); sound_sample_data = NULL;
4227 free(sound_files); sound_files = NULL;
4228 free(sound_background_defaults); sound_background_defaults = NULL;
4229 free(sound_map_data); sound_map_data = NULL;
4230 free(sound_effect_data); sound_effect_data = NULL;
4231 free(sound_particle_data); sound_particle_data = NULL;
4232 free(sound_item_data); sound_item_data = NULL;
4233 free(sound_tile_data); sound_tile_data = NULL;
4234 free(server_sound); server_sound = NULL;
4235 free(sound_spell_data); sound_spell_data = NULL;
4236 free(warnings_list); warnings_list = NULL;
4237 free(playlist); playlist = NULL;
4238 }
4239
4240 void init_sound()
4241 {
4242 ALCcontext *context;
4243 ALCdevice *device;
4244 ALfloat listenerPos[3] = {0.0f, 0.0f, 0.0f};
4245 ALfloat listenerVel[3] = {0.0f, 0.0f, 0.0f};
4246 ALfloat listenerOri[6] = {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
4247 ALCchar *device_list;
4248 int error;
4249 int i;
4250
4251 // If we don't have sound/music then bail so we don't grab the soundcard.
4252 if (inited || no_sound || (!sound_on && !music_on))
4253 return;
4254
4255 // Begin by setting all data to a known state
4256 if (have_sound)
4257 destroy_sound();
4258
4259 // Initialise OpenAL
4260
4261 // Get a list of the available devices (not used yet)
4262 if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") != AL_TRUE)
4263 {
4264 LOG_WARNING("ALC_ENUMERATION_EXT not found. Retrieving list of sound devices may fail.");
4265 }
4266 device_list = (char*) alcGetString(NULL, ALC_DEVICE_SPECIFIER);
4267 parse_snd_devices(device_list, sound_devices);
4268 LOG_INFO("Sound devices detected: %s\n", sound_devices);
4269
4270 // If you want to use a specific device, use, for example:
4271 // device = alcOpenDevice((ALCchar*) "DirectSound3D")
4272 // NULL makes it use the default device
4273 LOG_INFO("Soundcard device attempted: %s", sound_device);
4274 device = alcOpenDevice((ALCchar*) sound_device);
4275 if ((error = alcGetError(device)) != AL_NO_ERROR || !device)
4276 {
4277 if (strcmp(sound_device, "")) {
4278 // Try the default device
4279 device = alcOpenDevice(NULL);
4280 }
4281 if ((error = alcGetError(device)) != AL_NO_ERROR || !device)
4282 {
4283 char str[256];
4284 safe_snprintf(str, sizeof(str), "alcOpenDevice(): %s: %s\n", snd_init_error, alcGetString(device, error));
4285 LOG_TO_CONSOLE(c_red1, str);
4286 LOG_ERROR(str);
4287 have_sound = have_music = 0;
4288 return;
4289 } else {
4290 LOG_ERROR("Soundcard device specified (%s) failed. Using default device: %s", sound_device, alcGetString(device, ALC_DEVICE_SPECIFIER));
4291 }
4292 } else {
4293 LOG_INFO("Soundcard device in-use: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
4294 }
4295
4296 context = alcCreateContext( device, NULL );
4297 alcMakeContextCurrent( context );
4298 if ((error = alcGetError(device)) != AL_NO_ERROR || !context)
4299 {
4300 char str[256];
4301 safe_snprintf(str, sizeof(str), "context: %s: %s\n", snd_init_error, alcGetString(device, error));
4302 LOG_TO_CONSOLE(c_red1, str);
4303 LOG_ERROR(str);
4304 have_sound = have_music = 0;
4305 return;
4306 }
4307
4308 // Setup the listener
4309 alListenerfv(AL_POSITION, listenerPos);
4310 #ifdef _EXTRA_SOUND_DEBUG // Debugging for Florian
4311 if ((error = alGetError()) != AL_NO_ERROR)
4312 {
4313 LOG_DEBUG_VERBOSE("%s: Error setting up listener position - %s\n", snd_init_error, alGetString(error));
4314 }
4315 #endif // _EXTRA_SOUND_DEBUG
4316 alListenerfv(AL_VELOCITY, listenerVel);
4317 #ifdef _EXTRA_SOUND_DEBUG
4318 if ((error = alGetError()) != AL_NO_ERROR)
4319 {
4320 LOG_DEBUG_VERBOSE("%s: Error setting up listener velocity - %s\n", snd_init_error, alGetString(error));
4321 }
4322 #endif // _EXTRA_SOUND_DEBUG
4323 alListenerfv(AL_ORIENTATION, listenerOri);
4324 #ifdef _EXTRA_SOUND_DEBUG
4325 if ((error = alGetError()) != AL_NO_ERROR)
4326 {
4327 LOG_DEBUG_VERBOSE("%s: Error setting up listener orientation - %s\n", snd_init_error, alGetString(error));
4328 }
4329 #endif // _EXTRA_SOUND_DEBUG
4330
4331 if ((error = alGetError()) != AL_NO_ERROR)
4332 {
4333 char str[256];
4334 safe_snprintf(str, sizeof(str), "%s: Error setting up listener - %s\n", snd_init_error, alGetString(error));
4335 LOG_ERROR(str);
4336 }
4337
4338 // Start with our max and see how many sources we can allocate
4339 max_sources = ABS_MAX_SOURCES;
4340
4341 // Initialise sources
4342 LOCK_SOUND_LIST();
4343
4344 // Init source data
4345 for (i = 0; i < max_sources; i++)
4346 {
4347 clear_source(&sound_source_data[i]);
4348 }
4349
4350 // Generate our sources
4351 for (i = 0; i < max_sources; i++)
4352 {
4353 alGenSources(1, &sound_source_data[i].source);
4354 if ((error = alGetError()) != AL_NO_ERROR)
4355 {
4356 // Assume this is the limit of sources available
4357 max_sources = i;
4358 // Limit the available streams based on the number of sources (a stream takes twice the resources)
4359 if (max_sources <= 16)
4360 max_streams = 4; // This only allows a music stream, a crowd stream and 2 backgrounds...
4361 // but it takes effectively 8 sources of <= 16
4362 if (max_sources == 0)
4363 {
4364 // We don't have any sources so error and disable sound
4365 char str[256];
4366 safe_snprintf(str, sizeof(str), "alGenSources(): %s: %s - %s\n", snd_init_error, snd_source_error, alGetString(error));
4367 LOG_TO_CONSOLE(c_red1, str);
4368 LOG_ERROR(str);
4369 have_sound = have_music = 0;
4370 UNLOCK_SOUND_LIST();
4371 return;
4372 }
4373 break;
4374 }
4375 }
4376 UNLOCK_SOUND_LIST();
4377 #ifdef _EXTRA_SOUND_DEBUG
4378 LOG_DEBUG_VERBOSE("Generated and using %d sources\n", max_sources);
4379 #endif // _EXTRA_SOUND_DEBUG
4380
4381 have_sound = 1;
4382 have_music = 1;
4383
4384 // Initialise streams thread
4385 if (sound_streams_thread == NULL) {
4386 sound_streams_thread = SDL_CreateThread(update_streams, "SoundThread", 0);
4387 }
4388
4389 if (num_types == 0)
4390 {
4391 // We have no sounds defined so assume the config isn't loaded
4392 // As it isn't already loaded, assume the default config location
4393 load_sound_config_data(SOUND_CONFIG_PATH);
4394 }
4395
4396 inited = 1;
4397
4398 // Reset the error buffer
4399 if ((error = alGetError()) != AL_NO_ERROR)
4400 {
4401 LOG_DEBUG_VERBOSE("%s: %s", snd_init_error, alGetString(error));
4402 }
4403 }
4404
4405 void destroy_sound()
4406 {
4407 int i, error;
4408 ALCcontext *context;
4409 ALCdevice *device = NULL;
4410 if (!inited){
4411 return;
4412 }
4413 inited = have_sound = have_music = 0;
4414
4415 if (sound_streams_thread != NULL)
4416 {
4417 SDL_WaitThread(sound_streams_thread, NULL);
4418 sound_streams_thread = NULL;
4419 }
4420 LOCK_SOUND_LIST();
4421 for (i = 0; i < MAX_STREAMS; i++)
4422 {
4423 destroy_stream(&streams[i]);
4424 }
4425 // Remove physical elements (sources and buffers)
4426 for (i = 0; i < ABS_MAX_SOURCES; i++)
4427 {
4428 if (alIsSource(sound_source_data[i].source) == AL_TRUE)
4429 {
4430 alSourceStopv(1, &sound_source_data[i].source);
4431 alDeleteSources(1, &sound_source_data[i].source);
4432 }
4433 sound_source_data[i].source = 0;
4434 }
4435 used_sources = 0;
4436 for (i = 0; i < MAX_BUFFERS; i++)
4437 {
4438 unload_sample(i);
4439 }
4440 for (i = 0; i < MAX_BUFFERS * 2; i++)
4441 {
4442 if (no_sound) {
4443 unload_sound(i);
4444 } else {
4445 // Flag all sounds as unloaded, but don't remove them
4446 sounds_list[i].playing = 0;
4447 sounds_list[i].loaded = 0;
4448 }
4449 }
4450 UNLOCK_SOUND_LIST();
4451
4452 context = alcGetCurrentContext();
4453 if (context != NULL)
4454 {
4455 device = alcGetContextsDevice(context);
4456 #ifndef LINUX
4457 alcMakeContextCurrent(NULL);
4458 #endif // LINUX
4459 alcDestroyContext(context);
4460 if (device != NULL)
4461 {
4462 alcCloseDevice(device);
4463 device = NULL;
4464 }
4465 }
4466
4467 if (device != NULL && (error = alcGetError(device)) != AL_NO_ERROR)
4468 {
4469 char str[256];
4470 safe_snprintf(str, sizeof(str), "%s: %s\n", snd_init_error, alcGetString(device, error));
4471 LOG_TO_CONSOLE(c_red1, str);
4472 LOG_ERROR(str);
4473 }
4474 }
4475
4476
4477 // This function is to convert the \0 delimiter used by OpenAL into a comma so we can use
4478 // the device list as an everyday C "string" (original string terminated by \0\0).
4479 // For now the existance of a comma in a device name is irrelevent.
4480 void parse_snd_devices(ALCchar * in_array, char * sound_devs)
4481 {
4482 int i = 0;
4483 while (in_array[i] != '\0' || in_array[i+1] != '\0') {
4484 if (in_array[i] == '\0') {
4485 sound_devs[i] = ',';
4486 } else {
4487 sound_devs[i] = in_array[i];
4488 }
4489 i++;
4490 }
4491 sound_devs[i] = '\0';
4492 }
4493
4494 /********************
4495 * CONFIG FUNCTIONS *
4496 ********************/
4497
4498 // Returns -1 if the string is already in the list, 0 on error, 1 on success or -2 if there are no more list slots
4499 int add_to_sound_warnings_list(const char * text)
4500 {
4501 int i, snd;
4502 char left[256];
4503 char right[256];
4504 int t, tp;
4505
4506 if (text[0] == '\0' || text[0] == '#')
4507 return 1; // Nothing to do so return success
4508
4509 // Extract the sound name (left) and string (right) from the input text
4510 safe_strncpy (left, text, sizeof(left));
4511 for (t = 0; ; t++)
4512 {
4513 if (left[t] == '\0')
4514 {
4515 LOG_ERROR("Invalid sound warning declared: %s. Expected format 'sound = string'.", text);
4516 return 0;
4517 }
4518 if (left[t] == '=')
4519 {
4520 left[t] = '\0';
4521 for (tp = t - 1; tp >= 0 && isspace(left[tp]); tp--)
4522 {
4523 left[tp] = '\0';
4524 }
4525 for (tp = t + 1; left[tp] != '\0' && !(left[tp]&0x80) && isspace(left[tp]); tp++) ;
4526 safe_strncpy (right, &left[tp], sizeof(right));
4527 break;
4528 }
4529 }
4530
4531 // See if this string is already in the list
4532 for (i = 0; i < MAX_SOUND_WARNINGS; i++)
4533 {
4534 if (warnings_list[i].sound >= 0)
4535 {
4536 if (!strcasecmp(warnings_list[i].string, right))
4537 return -1; // Already in the list
4538 }
4539 }
4540
4541 snd = get_index_for_sound_type_name(left);
4542 if (snd > -1)
4543 {
4544 // We have a valid sound so find a free spot
4545 for (i = 0; i < MAX_SOUND_WARNINGS; i++)
4546 {
4547 if (warnings_list[i].sound < 0)
4548 {
4549 // Excellent, a free spot
4550 warnings_list[i].sound = snd;
4551 safe_strncpy(warnings_list[i].string, right, MAX_SND_WARNING_STRING);
4552 num_sound_warnings++;
4553 return 1;
4554 }
4555 }
4556 LOG_ERROR("Sound warning list is full. %d warnings loaded.", num_sound_warnings);
4557 return -2; // If we are here, it means the warnings list is full
4558 }
4559
4560 LOG_ERROR("Sound not found for sound warning: %s", text);
4561 return 0; // The sound wasn't found
4562 }
4563
4564 // Blatently stolen from the text filter code (filter.c)
4565 void load_sound_warnings_list(const char *filename)
4566 {
4567 int f_size;
4568 FILE * f = NULL;
4569 char * sound_warnings_list_mem;
4570 int istart, iend;
4571 char string[128];
4572
4573 f = open_file_config (filename, "rb");
4574 if (f == NULL) return;
4575
4576 // Ok, allocate memory for it and read it in
4577 fseek(f, 0, SEEK_END);
4578 f_size = ftell(f);
4579 if (f_size <= 0)
4580 {
4581 fclose(f);
4582 return;
4583 }
4584
4585 sound_warnings_list_mem = (char *) calloc (f_size, 1);
4586 fseek(f, 0, SEEK_SET);
4587 if (fread(sound_warnings_list_mem, 1, f_size, f) != f_size)
4588 {
4589 LOG_ERROR("%s() read failed for file [%s]\n", __FUNCTION__, filename);
4590 free(sound_warnings_list_mem);
4591 fclose(f);
4592 return;
4593 }
4594 fclose(f);
4595
4596 istart = 0;
4597 while (istart < f_size)
4598 {
4599 // Find end of the line
4600 for (iend = istart; iend < f_size; iend++)
4601 {
4602 if (sound_warnings_list_mem[iend] == '\n' || sound_warnings_list_mem[iend] == '\r')
4603 break;
4604 }
4605
4606 // Copy the line and process it
4607 if (iend > istart)
4608 {
4609 safe_strncpy2(string, sound_warnings_list_mem+istart, sizeof(string), iend - istart);
4610 if (add_to_sound_warnings_list(string) == -2) // -1 == already exists, -2 == list full
4611 {
4612 free(sound_warnings_list_mem);
4613 return; // Sound warnings list full
4614 }
4615 }
4616
4617 // Move to next line
4618 istart = iend + 1;
4619 }
4620
4621 free(sound_warnings_list_mem);
4622 }
4623
4624
4625
4626 void parse_server_sounds()
4627 {
4628 int i;
4629 // Parse the list of sounds according to client_serv.h and map them to our sound defs
4630 //
4631 // NOTE: This must be kept up-to-date with client_serv.h for it to be any use!!
4632 for (i = 0; i < MAX_SERVER_SOUNDS; i++)
4633 {
4634 switch(i)
4635 {
4636 case snd_rain:
4637 server_sound[snd_rain] = get_index_for_sound_type_name("Rain");
4638 break;
4639 case snd_tele_in:
4640 server_sound[snd_tele_in] = get_index_for_sound_type_name("Teleport_in");
4641 break;
4642 case snd_tele_out:
4643 server_sound[snd_tele_out] = get_index_for_sound_type_name("Teleport_out");
4644 break;
4645 case snd_teleprtr:
4646 server_sound[snd_teleprtr] = get_index_for_sound_type_name("Teleporter");
4647 break;
4648 case snd_thndr_1:
4649 server_sound[snd_thndr_1] = get_index_for_sound_type_name("Thunder1");
4650 break;
4651 case snd_thndr_2:
4652 server_sound[snd_thndr_2] = get_index_for_sound_type_name("Thunder2");
4653 break;
4654 case snd_thndr_3:
4655 server_sound[snd_thndr_3] = get_index_for_sound_type_name("Thunder3");
4656 break;
4657 case snd_thndr_4:
4658 server_sound[snd_thndr_4] = get_index_for_sound_type_name("Thunder4");
4659 break;
4660 case snd_thndr_5:
4661 server_sound[snd_thndr_5] = get_index_for_sound_type_name("Thunder5");
4662 break;
4663 case snd_fire:
4664 server_sound[snd_fire] = get_index_for_sound_type_name("FireBig");
4665 break;
4666 }
4667 }
4668 }
4669
4670 sound_file * init_sound_file(const char * content)
4671 {
4672 int i;
4673
4674 // Check if this file is already in our list of sound files
4675 for (i = 0; i < num_sound_files; i++)
4676 {
4677 if (!strcasecmp(sound_files[i].file_path, content)) {
4678 return &sound_files[i];
4679 }
4680 }
4681 // Not found so check we have space to add it to the list
4682 if (num_sound_files >= MAX_SOUND_FILES)
4683 {
4684 // Big problem! No more room to load sound files
4685 return NULL;
4686 }
4687 // Everything is ok so load it
4688 safe_strncpy(sound_files[i].file_path, content, MAX_FILENAME_LENGTH);
4689 num_sound_files++;
4690 return &sound_files[i];
4691 }
4692
4693 sound_file * load_sound_part(sound_file *pPart, SOUND_STAGE stage, const char * content)
4694 {
4695 char filename[200];
4696 char stage_name[6];
4697
4698 safe_strncpy(stage_name, (stage == STAGE_INTRO ? "Intro" : (stage == STAGE_MAIN ? "Main" : "Outro")), sizeof(stage_name));
4699
4700 if (!pPart || !strcasecmp(pPart->file_path, ""))
4701 {
4702 safe_strncpy(filename, datadir, sizeof(filename));
4703 safe_strcat(filename, content, sizeof(filename));
4704 if (file_exists(filename))
4705 {
4706 pPart = init_sound_file(content);
4707 if (pPart)
4708 {
4709 return pPart;
4710 }
4711 LOG_ERROR("%s: Too many sound files loaded!", snd_config_error);
4712 }
4713 else
4714 {
4715 LOG_ERROR("%s: %s stage file does not exist! %s", snd_config_error, stage_name, content);
4716 }
4717 }
4718 else
4719 {
4720 LOG_ERROR("%s: %s stage file already set!", snd_config_error, stage_name);
4721 return pPart;
4722 }
4723 return NULL;
4724 }
4725
4726 void parse_sound_variant(const xmlNode *inNode, sound_type *inType)
4727 {
4728 char content[50];
4729 float fVal = 0.0f;
4730 sound_variants * pData;
4731 const xmlNode *attributeNode;
4732
4733 if (inType->num_variants >= MAX_SOUND_VARIANTS)
4734 {
4735 LOG_ERROR("%s: Too many sound variants defined for this sound type: %s", snd_config_error, inType->name);
4736 return;
4737 }
4738
4739 pData = &inType->variant[inType->num_variants++];
4740 attributeNode = inNode->xmlChildrenNode;
4741 while (attributeNode != NULL)
4742 {
4743 if (attributeNode->type == XML_ELEMENT_NODE)
4744 {
4745 get_string_value(content, sizeof(content), attributeNode);
4746 if (!xmlStrcmp (attributeNode->name, (xmlChar*)"intro_sound"))
4747 {
4748 pData->part[STAGE_INTRO] = load_sound_part(pData->part[STAGE_INTRO], STAGE_INTRO, content);
4749 }
4750 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"main_sound"))
4751 {
4752 pData->part[STAGE_MAIN] = load_sound_part(pData->part[STAGE_MAIN], STAGE_MAIN, content);
4753 if (!pData->part[STAGE_MAIN])
4754 {
4755 // We don't have a main stage file, therefore this variant is invalid!
4756 LOG_ERROR("%s: We do not have a main stage file so this variant for sound type '%s' is disabled", snd_config_error, inType->name);
4757 clear_variant(pData);
4758 inType->num_variants--;
4759 return;
4760 }
4761 }
4762 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"outro_sound"))
4763 {
4764 pData->part[STAGE_OUTRO] = load_sound_part(pData->part[STAGE_OUTRO], STAGE_OUTRO, content);
4765 }
4766 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"gain"))
4767 {
4768 fVal = (float)atof((char *)content);
4769 if (fVal > 0.0f)
4770 pData->gain = fVal;
4771 else
4772 {
4773 LOG_ERROR("%s: Invalid gain = %s in '%s'", snd_config_error, content, inType->name);
4774 }
4775 }
4776 }
4777 else if (attributeNode->type == XML_ENTITY_REF_NODE)
4778 {
4779 LOG_ERROR("%s: Include not allowed in variant sound def", snd_config_error);
4780 }
4781 attributeNode = attributeNode->next;
4782 }
4783 // Check this variant has the required Main stage
4784 if (!pData->part[STAGE_MAIN])
4785 {
4786 LOG_ERROR("%s: Main stage not defined! A sound variant for this type is disabled: %s", snd_config_error, inType->name);
4787 clear_variant(pData);
4788 inType->num_variants--;
4789 }
4790 return;
4791 }
4792
4793 void parse_sound_object(const xmlNode *inNode)
4794 {
4795 const xmlNode *attributeNode = NULL;
4796
4797 char content[50];
4798 int iVal = 0;
4799 float fVal = 0.0f;
4800 xmlChar *sVal = NULL;
4801
4802 sound_type *pData = NULL;
4803
4804 if (num_types >= MAX_SOUNDS)
4805 {
4806 LOG_ERROR("%s: Maximum number of sounds (%d) reached!", snd_config_error, MAX_SOUNDS);
4807 return;
4808 }
4809
4810 pData = &sound_type_data[num_types++];
4811
4812 sVal = xmlGetProp((xmlNode *)inNode, (const xmlChar*)"name");
4813 if (!sVal)
4814 {
4815 LOG_ERROR("%s: sound has no name", snd_config_error);
4816 }
4817 else
4818 {
4819 safe_strncpy(pData->name, (const char*)sVal, sizeof(pData->name));
4820 xmlFree(sVal);
4821
4822 attributeNode = inNode->xmlChildrenNode;
4823 while (attributeNode != NULL)
4824 {
4825 if (attributeNode->type == XML_ELEMENT_NODE)
4826 {
4827 get_string_value(content, sizeof(content), attributeNode);
4828 if (!xmlStrcmp (attributeNode->name, (xmlChar*)"variant"))
4829 {
4830 parse_sound_variant(attributeNode, pData);
4831 }
4832 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"stereo"))
4833 {
4834 iVal = atoi((char *)content);
4835 if (iVal == 0 || iVal == 1)
4836 pData->stereo = iVal;
4837 else
4838 {
4839 LOG_ERROR("%s: stereo = %d in '%s'", snd_config_error, iVal, pData->name);
4840 }
4841 }
4842 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"distance"))
4843 {
4844 fVal = (float)atof((char *)content);
4845 if (fVal > 0.0f)
4846 pData->distance = fVal;
4847 else
4848 {
4849 LOG_ERROR("%s: distance = %f in '%s'", snd_config_error, fVal, pData->name);
4850 }
4851 }
4852 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"positional"))
4853 {
4854 iVal = atoi((char *)content);
4855 if (iVal == 0 || iVal == 1)
4856 pData->positional = iVal;
4857 else
4858 {
4859 LOG_ERROR("%s: positional = %d in '%s'", snd_config_error, iVal, pData->name);
4860 }
4861 }
4862 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"loops"))
4863 {
4864 iVal = atoi((char *)content);
4865 if (iVal >= 0)
4866 pData->loops = iVal;
4867 else
4868 {
4869 LOG_ERROR("%s: loops = %d in '%s'", snd_config_error, iVal, pData->name);
4870 }
4871 }
4872 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"fadeout_time"))
4873 {
4874 iVal = atoi((char *)content);
4875 if (iVal >= 0)
4876 pData->fadeout_time = iVal;
4877 else
4878 {
4879 LOG_ERROR("%s: fadeout_time = %d in '%s'", snd_config_error, iVal, pData->name);
4880 }
4881 }
4882 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"echo_delay"))
4883 {
4884 iVal = atoi((char *)content);
4885 if (iVal >= 0)
4886 pData->echo_delay = iVal;
4887 else
4888 {
4889 LOG_ERROR("%s: echo_delay = %d in '%s'", snd_config_error, iVal, pData->name);
4890 }
4891 }
4892 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"echo_volume"))
4893 {
4894 iVal = atoi((char *)content);
4895 if (iVal >= 0)
4896 pData->echo_volume = iVal;
4897 else
4898 {
4899 LOG_ERROR("%s: echo_volume = %d in '%s'", snd_config_error, iVal, pData->name);
4900 }
4901 }
4902 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"time_of_day_flags"))
4903 {
4904 sscanf((char *)content, "%x", &iVal);
4905 if (iVal >= 0 && iVal <= 0xffff)
4906 pData->time_of_the_day_flags = iVal;
4907 else
4908 {
4909 LOG_ERROR("%s: time_of_the_day_flags = 0x%x in '%s'", snd_config_error, iVal, pData->name);
4910 }
4911 }
4912 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"priority"))
4913 {
4914 iVal = atoi((char *)content);
4915 if (iVal >= 0)
4916 pData->priority = iVal;
4917 else
4918 {
4919 LOG_ERROR("%s: priority = %d in '%s'", snd_config_error, iVal, pData->name);
4920 }
4921 }
4922 else if (!xmlStrcmp (attributeNode->name, (xmlChar*)"type"))
4923 {
4924 iVal = SOUNDS_NONE;
4925 if (!strcasecmp((char *)content, "environmental")) {
4926 iVal = SOUNDS_ENVIRO;
4927 } else if (!strcasecmp((char *)content, "actor")) {
4928 iVal = SOUNDS_ACTOR;
4929 } else if (!strcasecmp((char *)content, "walking")) {
4930 iVal = SOUNDS_WALKING;
4931 } else if (!strcasecmp((char *)content, "map")) {
4932 iVal = SOUNDS_MAP;
4933 } else if (!strcasecmp((char *)content, "crowd")) {
4934 iVal = SOUNDS_CROWD;
4935 } else if (!strcasecmp((char *)content, "client")) {
4936 iVal = SOUNDS_CLIENT;
4937 } else if (!strcasecmp((char *)content, "gamewin")) {
4938 iVal = SOUNDS_GAMEWIN;
4939 } else if (!strcasecmp((char *)content, "warnings")) {
4940 iVal = SOUNDS_WARNINGS;
4941 } else {
4942 LOG_ERROR("%s: Unknown type '%s' for sound '%s'", snd_config_error, content, pData->name);
4943 }
4944 if (iVal != SOUNDS_NONE)
4945 pData->type = iVal;
4946 }
4947 else
4948 {
4949 LOG_ERROR("%s: Unknown attribute '%s' for sound '%s'", snd_config_error, attributeNode->name, pData->name);
4950 }
4951 }
4952 else if (attributeNode->type == XML_ENTITY_REF_NODE)
4953 {
4954 LOG_ERROR("%s: Include not allowed in sound def", snd_config_error);
4955 }
4956 attributeNode = attributeNode->next;
4957 }
4958 }
4959 // Check this type has at least one variant
4960 if (pData->num_variants < 1)
4961 {
4962 LOG_ERROR("%s: No sound variants defined! This sound type is disabled: %s", snd_config_error, pData->name);
4963 clear_sound_type(num_types);
4964 num_types--;
4965 }
4966 }
4967
4968 void store_boundary_coords(char *coordinates, int * x, int * y)
4969 {
4970 int i = 0, j = 0, element = 0;
4971 char tmp[5] = "";
4972
4973 while (i != strlen(coordinates))
4974 {
4975 if (coordinates[i] != ',' && j < 5 && i != strlen(coordinates))
4976 {
4977 tmp[j] = coordinates[i];
4978 j++;
4979 }
4980 else
4981 {
4982 if (element == 0)
4983 {
4984 *x = atoi(tmp);
4985 for (j = 0; j < 5; j++)
4986 {
4987 tmp[j] = '\0';
4988 }
4989 j = 0;
4990 element++;
4991 }
4992 else break;
4993 }
4994 i++;
4995 }
4996 if (element == 1)
4997 {
4998 *y = atoi(tmp);
4999 }
5000 else
5001 {
5002 LOG_ERROR("%s: Error parsing coordinates", snd_config_error);
5003 }
5004 return;
5005 }
5006
5007 int validate_boundary(map_sound_boundary_def * bounds, char * map_name)
5008 {
5009 int i;
5010 double a;
5011
5012 // Check if this is a default
5013 if (bounds->is_default)
5014 {
5015 // Check if we have any points
5016 if (bounds->p[0].x != -1 || bounds->p[0].y != -1 || bounds->p[1].x != -1 || bounds->p[1].y != -1
5017 || bounds->p[2].x != -1 || bounds->p[2].y != -1 || bounds->p[3].x != -1 || bounds->p[3].y != -1)
5018 {
5019 LOG_ERROR("Warning: Points defined for default boundary. Points will be ignored.\n");
5020 }
5021 return 1; // Points are ignored for defaults
5022 }
5023
5024 // Check we have details for at least 2 points
5025 if (bounds->p[0].x == -1 || bounds->p[0].y == -1 || bounds->p[1].x == -1 || bounds->p[1].y == -1)
5026 {
5027 LOG_ERROR("%s: Point missing for boundary in map '%s'. Non-default boundaries must contain 2 or 4 points.", snd_config_error, map_name);
5028 return 0;
5029 }
5030
5031 // Calculate the outer box
5032 bounds->o[0].x = bounds->p[0].x;
5033 bounds->o[0].y = bounds->p[0].y;
5034 bounds->o[1].x = bounds->p[0].x;
5035 bounds->o[1].y = bounds->p[0].y;
5036 for (i = 0; i < 4; i++)
5037 {
5038 if (bounds->p[i].x > -1 && bounds->p[i].y > -1)
5039 {
5040 // Check if this point's x or y is greater than the current max or less than the current min and update
5041 if (bounds->p[i].x < bounds->o[0].x)
5042 bounds->o[0].x = bounds->p[i].x;
5043 if (bounds->p[i].y < bounds->o[0].y)
5044 bounds->o[0].y = bounds->p[i].y;
5045 if (bounds->p[i].x > bounds->o[1].x)
5046 bounds->o[1].x = bounds->p[i].x;
5047 if (bounds->p[i].y > bounds->o[1].y)
5048 bounds->o[1].y = bounds->p[i].y;
5049 }
5050 }
5051
5052 // We have the outer box now so if we have only 2 points then we can bail
5053 if (bounds->p[2].x == -1 && bounds->p[2].y == -1 && bounds->p[3].x == -1 && bounds->p[3].y == -1)
5054 {
5055 return 1;
5056 }
5057 else if (bounds->p[2].x == -1 || bounds->p[2].y == -1 || bounds->p[3].x == -1 || bounds->p[3].y == -1)
5058 {
5059 LOG_ERROR("%s: Point missing for boundary in map '%s'. Non-default boundaries must contain 2 or 4 points.", snd_config_error, map_name);
5060 return 0;
5061 }
5062
5063 // Check if our 4 points are actually equal to the bounding box rectangle
5064 if (bounds->p[0].x == bounds->o[0].x && bounds->p[0].y == bounds->o[0].y &&
5065 bounds->p[1].x == bounds->o[0].x && bounds->p[1].y == bounds->o[1].y &&
5066 bounds->p[2].x == bounds->o[1].x && bounds->p[2].y == bounds->o[1].y &&
5067 bounds->p[3].x == bounds->o[1].x && bounds->p[3].y == bounds->o[0].y)
5068 {
5069 // This is the bounding box so remove points 1 and 2 as the corners and blank the others
5070 // to symbolise using the bounding box check only
5071 bounds->p[1].x = bounds->p[2].x;
5072 bounds->p[1].y = bounds->p[2].y;
5073 bounds->p[2].x = -1;
5074 bounds->p[2].y = -1;
5075 bounds->p[3].x = -1;
5076 bounds->p[3].y = -1;
5077 // Nothing left to do
5078 return 1;
5079 }
5080
5081 // Find the angle of the line from the top left corner to the top right (point1 -> point2)
5082 bounds->p[0].a = calculate_bounds_angle(bounds->p[1].x, bounds->p[1].y, 0, bounds);
5083
5084 // Find the angle of the line from the top right corner to the bottom right (point2 -> point3)
5085 bounds->p[1].a = calculate_bounds_angle(bounds->p[2].x, bounds->p[2].y, 1, bounds);
5086
5087 // Find the angle of the line from the bottom right corner to the bottom left (point3 -> point4)
5088 bounds->p[2].a = calculate_bounds_angle(bounds->p[3].x, bounds->p[3].y, 2, bounds);
5089
5090 // Find the angle of the line from the bottom left corner to the top left (point4 -> point1)
5091 bounds->p[3].a = calculate_bounds_angle(bounds->p[0].x, bounds->p[0].y, 3, bounds);
5092
5093
5094 // Check the angle of the line from the bottom left corner to the top right (point4 -> point2)
5095 a = calculate_bounds_angle(bounds->p[1].x, bounds->p[1].y, 3, bounds);
5096 if (bounds->p[3].a < a) bounds->int_point = 0;
5097
5098 // Check the angle of the line from the top left corner to the bottom right (point1 -> point3)
5099 a = calculate_bounds_angle(bounds->p[2].x, bounds->p[2].y, 0, bounds);
5100 if (bounds->p[0].a < a) bounds->int_point = 1;
5101
5102 // Check the angle of the line from the top right corner to the bottom left (point2 -> point4)
5103 a = calculate_bounds_angle(bounds->p[3].x, bounds->p[3].y, 1, bounds);
5104 if (bounds->p[1].a < a) bounds->int_point = 2;
5105
5106 // Check the angle of the line from the bottom right corner to the top left (point3 -> point1)
5107 a = calculate_bounds_angle(bounds->p[0].x, bounds->p[0].y, 2, bounds);
5108 if (bounds->p[2].a < a) bounds->int_point = 3;
5109
5110 return 1;
5111 }
5112
5113 void parse_map_sound(const xmlNode *inNode)
5114 {
5115 const xmlNode *boundaryNode = NULL;
5116 const xmlNode *attributeNode = NULL;
5117
5118 xmlChar *sVal = NULL;
5119 char content[50];
5120
5121 int iVal;
5122
5123 map_sound_data *pMap = NULL;
5124 map_sound_boundary_def *pMapBoundary = NULL;
5125
5126 if (sound_num_maps >= MAX_SOUND_MAPS)
5127 {
5128 LOG_ERROR("%s: Maximum number of maps reached!", snd_config_error);
5129 return;
5130 }
5131 pMap = &sound_map_data[sound_num_maps++];
5132
5133 sVal = xmlGetProp((xmlNode*)inNode,(const xmlChar*)"file_name");
5134 if (!sVal)
5135 {
5136 pMap->file_name[0] = '\0';
5137 }
5138 else
5139 {
5140 safe_strncpy(pMap->file_name, (const char*)sVal, sizeof(pMap->file_name));
5141 xmlFree(sVal);
5142 }
5143
5144 sVal = xmlGetProp((xmlNode*)inNode,(const xmlChar*)"id");
5145 if (!sVal)
5146 {
5147 pMap->id = -1;
5148 }
5149 else
5150 {
5151 pMap->id = atoi((const char*)sVal);
5152 xmlFree(sVal);
5153 }
5154
5155 if (pMap->file_name[0] == '\0' && pMap->id == -1)
5156 {
5157 LOG_ERROR("%s: map has no file_name or id", snd_config_error);
5158 }
5159 else
5160 {
5161 sVal = xmlGetProp((xmlNode*)inNode, (const xmlChar*)"name");
5162 if (sVal)
5163 {
5164 safe_strncpy(pMap->name, (const char*)sVal, sizeof(pMap->name));
5165 xmlFree(sVal);
5166 }
5167
5168 for (boundaryNode = inNode->children; boundaryNode; boundaryNode = boundaryNode->next)
5169 {
5170 if (boundaryNode->type == XML_ELEMENT_NODE)
5171 {
5172 if(!xmlStrcasecmp(boundaryNode->name, (xmlChar*)"boundary_def"))
5173 {
5174 // Process this set of boundaries
5175 if (pMap->num_boundaries++ < MAX_SOUND_MAP_BOUNDARIES)
5176 {
5177 pMapBoundary = &pMap->boundaries[pMap->num_boundaries - 1];
5178
5179 for (attributeNode = boundaryNode->children; attributeNode; attributeNode = attributeNode->next)
5180 {
5181 get_string_value(content, sizeof(content), attributeNode);
5182 if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"background"))
5183 {
5184 // Find the type of background sound for this set of boundaries
5185 pMapBoundary->bg_sound = get_index_for_sound_type_name(content);
5186 if (pMapBoundary->bg_sound == -1)
5187 {
5188 LOG_ERROR("%s: background sound not found for map boundary type '%s' in map '%s'", snd_config_error,content, pMap->name);
5189 }
5190 }
5191 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"crowd"))
5192 {
5193 // Find the type of crowd sound for this set of boundaries
5194 pMapBoundary->crowd_sound = get_index_for_sound_type_name(content);
5195 if (pMapBoundary->crowd_sound == -1)
5196 {
5197 LOG_ERROR("%s: crowd sound not found for map boundary type '%s' in map '%s'", snd_config_error, content, pMap->name);
5198 }
5199 }
5200 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"time_of_day_flags"))
5201 {
5202 // Find the type of crowd sound for this set of boundaries
5203 sscanf((char *)content, "%x", &iVal);
5204 if (iVal >= 0 && iVal <= 0xffff)
5205 pMapBoundary->time_of_day_flags = iVal;
5206 else
5207 {
5208 LOG_ERROR("%s: time_of_day flags (%s) invalid for map boundary in map '%s'", snd_config_error, content, pMap->name);
5209 }
5210 }
5211 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"is_default"))
5212 {
5213 // Find the type of crowd sound for this set of boundaries
5214 iVal = atoi(content);
5215 if (iVal == 0 || iVal == 1)
5216 {
5217 pMapBoundary->is_default = iVal;
5218 if (pMap->num_defaults < MAX_MAP_BACKGROUND_DEFAULTS)
5219 {
5220 pMap->num_defaults++;
5221 pMap->defaults[pMap->num_defaults] = pMap->num_boundaries;
5222 }
5223 else
5224 {
5225 LOG_ERROR("%s: Maximum defaults reached for map '%s'", snd_config_error, pMap->name);
5226 }
5227 }
5228 else
5229 {
5230 LOG_ERROR("%s: is_default setting (%s) invalid for map boundary in map '%s'", snd_config_error, content, pMap->name);
5231 }
5232 }
5233 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point1"))
5234 {
5235 // Parse the coordinates
5236 store_boundary_coords(content, &pMapBoundary->p[0].x, &pMapBoundary->p[0].y);
5237 }
5238 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point2"))
5239 {
5240 // Parse the coordinates
5241 store_boundary_coords(content, &pMapBoundary->p[1].x, &pMapBoundary->p[1].y);
5242 }
5243 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point3"))
5244 {
5245 // Parse the coordinates
5246 store_boundary_coords(content, &pMapBoundary->p[2].x, &pMapBoundary->p[2].y);
5247 }
5248 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point4"))
5249 {
5250 // Parse the coordinates
5251 store_boundary_coords(content, &pMapBoundary->p[3].x, &pMapBoundary->p[3].y);
5252 }
5253 }
5254 // Validate the boundary
5255 if (!validate_boundary(pMapBoundary, pMap->name))
5256 {
5257 // This one is invalid so remove it (we have already errored)
5258 clear_boundary_data(pMapBoundary);
5259 pMap->num_boundaries--;
5260 }
5261 }
5262 else
5263 {
5264 LOG_ERROR("%s: reached max boundaries for map '%s'", snd_config_error, pMap->name);
5265 }
5266 }
5267 // This block is a temporary fix for detecting 2d and 3d objects. It can be removed once the other functionality is coded.
5268 else if(!xmlStrcasecmp(boundaryNode->name, (xmlChar*)"walk_boundary_def"))
5269 {
5270 // Process this set of boundaries
5271 if (pMap->num_walk_boundaries++ < MAX_SOUND_WALK_BOUNDARIES)
5272 {
5273 pMapBoundary = &pMap->walk_boundaries[pMap->num_walk_boundaries - 1];
5274
5275 for (attributeNode = boundaryNode->children; attributeNode; attributeNode = attributeNode->next)
5276 {
5277 get_string_value(content, sizeof(content), attributeNode);
5278 if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"sound"))
5279 {
5280 // Find the sound for this set of boundaries
5281 pMapBoundary->bg_sound = get_index_for_sound_type_name(content);
5282 if (pMapBoundary->bg_sound == -1)
5283 {
5284 LOG_ERROR("%s: sound not found for walk boundary type '%s' in map '%s'", snd_config_error, content, pMap->name);
5285 }
5286 }
5287 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"time_of_day_flags"))
5288 {
5289 // Find the type of time of day flags for this set of boundaries
5290 sscanf((char *)content, "%x", &iVal);
5291 if (iVal >= 0 && iVal <= 0xffff)
5292 pMapBoundary->time_of_day_flags = iVal;
5293 else
5294 {
5295 LOG_ERROR("%s: time_of_day flags (%s) invalid for walk boundary in map '%s'", snd_config_error, content, pMap->name);
5296 }
5297 }
5298 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point1"))
5299 {
5300 // Parse the coordinates
5301 store_boundary_coords(content, &pMapBoundary->p[0].x, &pMapBoundary->p[0].y);
5302 }
5303 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point2"))
5304 {
5305 // Parse the coordinates
5306 store_boundary_coords(content, &pMapBoundary->p[1].x, &pMapBoundary->p[1].y);
5307 }
5308 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point3"))
5309 {
5310 // Parse the coordinates
5311 store_boundary_coords(content, &pMapBoundary->p[2].x, &pMapBoundary->p[2].y);
5312 }
5313 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"point4"))
5314 {
5315 // Parse the coordinates
5316 store_boundary_coords(content, &pMapBoundary->p[3].x, &pMapBoundary->p[3].y);
5317 }
5318 }
5319 // Validate the boundary
5320 if (!validate_boundary(pMapBoundary, pMap->name))
5321 {
5322 // This one is invalid so remove it (we have already errored)
5323 clear_boundary_data(pMapBoundary);
5324 pMap->num_walk_boundaries--;
5325 }
5326 }
5327 else
5328 {
5329 LOG_ERROR("%s: reached max walk boundaries for map '%s'", snd_config_error, pMap->name);
5330 }
5331 }
5332 // This block ^^ is a temporary fix for detecting 2d and 3d objects. It can be removed once the other functionality is coded.
5333 else
5334 {
5335 LOG_ERROR("%s: Boundary definition expected. Found: %s", snd_config_error, boundaryNode->name);
5336 }
5337 }
5338 else if (boundaryNode->type == XML_ENTITY_REF_NODE)
5339 {
5340 LOG_ERROR("%s: Include not allowed in map sound def", snd_config_error);
5341 }
5342 }
5343 }
5344 }
5345
5346 void parse_effect_sound(const xmlNode *inNode)
5347 {
5348 const xmlNode *attributeNode = NULL;
5349 effect_sound_data *pEffect = NULL;
5350 char sound[MAX_SOUND_NAME_LENGTH] = "";
5351
5352 if (inNode->type == XML_ELEMENT_NODE)
5353 {
5354 if (sound_num_effects >= MAX_SOUND_EFFECTS)
5355 {
5356 LOG_ERROR("%s: Maximum number of effects reached!", snd_config_error);
5357 return;
5358 }
5359 pEffect = &sound_effect_data[sound_num_effects++];
5360
5361 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5362 {
5363 if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"id"))
5364 {
5365 pEffect->id = get_float_value(attributeNode);
5366 }
5367 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"sound"))
5368 {
5369 get_string_value(sound, sizeof(sound), attributeNode);
5370 pEffect->sound = get_index_for_sound_type_name(sound);
5371 if (pEffect->sound == -1)
5372 {
5373 LOG_ERROR("%s: Unknown sound %s for effect %d", snd_config_error, sound, pEffect->id);
5374 }
5375 }
5376 }
5377 }
5378 else if (inNode->type == XML_ENTITY_REF_NODE)
5379 {
5380 LOG_ERROR("%s: Include not allowed in effect sound def", snd_config_error);
5381 }
5382 }
5383
5384 void parse_particle_sound(const xmlNode *inNode)
5385 {
5386 const xmlNode *attributeNode = NULL;
5387 particle_sound_data *pParticle = NULL;
5388 char sound[MAX_SOUND_NAME_LENGTH] = "";
5389
5390 if (inNode->type == XML_ELEMENT_NODE)
5391 {
5392 if (sound_num_particles >= MAX_SOUND_PARTICLES)
5393 {
5394 LOG_ERROR("%s: Maximum number of particles reached!", snd_config_error);
5395 return;
5396 }
5397 pParticle = &sound_particle_data[sound_num_particles++];
5398
5399 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5400 {
5401 if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"file"))
5402 {
5403 get_string_value(pParticle->file, sizeof(pParticle->file), attributeNode);
5404 }
5405 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"sound"))
5406 {
5407 get_string_value(sound, sizeof(sound), attributeNode);
5408 pParticle->sound = get_index_for_sound_type_name(sound);
5409 if (pParticle->sound == -1)
5410 {
5411 LOG_ERROR("%s: Unknown sound %s for particle %s", snd_config_error, sound, pParticle->file);
5412 }
5413 }
5414 }
5415 }
5416 else if (inNode->type == XML_ENTITY_REF_NODE)
5417 {
5418 LOG_ERROR("%s: Include not allowed in particle sound def", snd_config_error);
5419 }
5420 }
5421
5422 int check_for_valid_background_details(background_default * test)
5423 {
5424 int err, i;
5425 err = 0;
5426 // Check this has a valid sound
5427 if (test->sound < 0) return -1;
5428 // Check this time_of_day_flag and map_type don't conflict with an existing default background
5429 for (i = 0; i < sound_num_background_defaults - 1; i++)
5430 {
5431 if ((sound_background_defaults[i].time_of_day_flags & test->time_of_day_flags) > 0 &&
5432 sound_background_defaults[i].map_type == test->map_type)
5433 {
5434 // Conflict
5435 err = -1;
5436 break;
5437 }
5438 }
5439 return err;
5440 }
5441
5442 void parse_background_defaults(const xmlNode *inNode)
5443 {
5444 const xmlNode *attributeNode = NULL;
5445 background_default *pBackgroundDefault = NULL;
5446 char content[MAX_SOUND_NAME_LENGTH] = "";
5447
5448 int iVal = 0;
5449
5450 if (inNode->type == XML_ELEMENT_NODE)
5451 {
5452 if (sound_num_background_defaults >= MAX_BACKGROUND_DEFAULTS)
5453 {
5454 LOG_ERROR("%s: Maximum number of background defaults reached!", snd_config_error);
5455 return;
5456 }
5457 pBackgroundDefault = &sound_background_defaults[sound_num_background_defaults++];
5458
5459 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5460 {
5461 get_string_value(content, sizeof(content), attributeNode);
5462 if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"time_of_day_flags"))
5463 {
5464 sscanf((char *)content, "%x", &iVal);
5465 if (iVal >= 0 && iVal <= 0xffff)
5466 pBackgroundDefault->time_of_day_flags = iVal;
5467 else
5468 {
5469 LOG_ERROR("%s: time_of_the_day_flags = 0x%x in background default", snd_config_error, iVal);
5470 }
5471 }
5472 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"map_type"))
5473 {
5474 iVal = atoi((char *)content);
5475 if(iVal >= 0)
5476 pBackgroundDefault->map_type = iVal;
5477 else
5478 {
5479 LOG_ERROR("%s: Unknown map_type %s in background default", snd_config_error, content);
5480 }
5481 }
5482 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"sound"))
5483 {
5484 pBackgroundDefault->sound = get_index_for_sound_type_name(content);
5485 if (pBackgroundDefault->sound == -1)
5486 {
5487 LOG_ERROR("%s: Unknown sound %s in background default", snd_config_error, content);
5488 }
5489 }
5490 }
5491 if (check_for_valid_background_details(pBackgroundDefault))
5492 {
5493 LOG_ERROR("%s: invalid/conflicting background defaults found!", snd_config_error);
5494 // This background is invalid so reset it to the defaults (and reuse it if there are any others)
5495 pBackgroundDefault->time_of_day_flags = 0xffff;
5496 pBackgroundDefault->map_type = 0;
5497 pBackgroundDefault->sound = -1;
5498 sound_num_background_defaults--;
5499 }
5500 }
5501 else if (inNode->type == XML_ENTITY_REF_NODE)
5502 {
5503 LOG_ERROR("%s: Include not allowed in defaults sound def", snd_config_error);
5504 }
5505 }
5506
5507 void parse_sound_defaults(const xmlNode *inNode)
5508 {
5509 const xmlNode *attributeNode = NULL;
5510 char sound[MAX_SOUND_NAME_LENGTH] = "";
5511
5512 if (inNode->type == XML_ELEMENT_NODE)
5513 {
5514 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5515 {
5516 if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"background"))
5517 {
5518 parse_background_defaults(attributeNode);
5519 }
5520 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"crowd"))
5521 {
5522 get_string_value(sound, sizeof(sound), attributeNode);
5523 crowd_default = get_index_for_sound_type_name(sound);
5524 if (crowd_default == -1)
5525 {
5526 LOG_ERROR("%s: Unknown sound %s for crowd default", snd_config_error, sound);
5527 }
5528 }
5529 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"walking"))
5530 {
5531 get_string_value(sound, sizeof(sound), attributeNode);
5532 walking_default = get_index_for_sound_type_name(sound);
5533 if (walking_default == -1)
5534 {
5535 LOG_ERROR("%s: Unknown sound %s for crowd default", snd_config_error, sound);
5536 }
5537 }
5538 }
5539 }
5540 else if (inNode->type == XML_ENTITY_REF_NODE)
5541 {
5542 LOG_ERROR("%s: Include not allowed in defaults sound def", snd_config_error);
5543 }
5544 }
5545
5546 void parse_item_image_ids(char * content, item_sound_data * pItem)
5547 {
5548 int i, j;
5549 char temp[5] = "";
5550
5551 i = 0;
5552 j = -1;
5553 while (i < strlen(content))
5554 {
5555 if (content[i] == ',')
5556 {
5557 if (pItem->num_imageids < MAX_ITEM_SOUND_IMAGE_IDS)
5558 {
5559 pItem->image_id[pItem->num_imageids++] = atoi(temp);
5560 j = -1;
5561 }
5562 else
5563 {
5564 LOG_ERROR("%s: Too many image ids defined for item sound: %s", snd_config_error, content);
5565 return; // Avoid any more errors
5566 }
5567 }
5568 else
5569 {
5570 j++;
5571 if (j < 5)
5572 temp[j] = content[i];
5573 else
5574 {
5575 LOG_ERROR("%s: Invalid image id defined for item sound: %s...", snd_config_error, temp);
5576 j = -1;
5577 }
5578 }
5579 i++;
5580 }
5581 // Add anything remaining as a last image id
5582 if (pItem->num_imageids < MAX_ITEM_SOUND_IMAGE_IDS)
5583 {
5584 pItem->image_id[pItem->num_imageids++] = atoi(temp);
5585 }
5586 else
5587 {
5588 LOG_ERROR("%s: Too many image ids defined for item sound: %s", snd_config_error, content);
5589 }
5590 return;
5591 }
5592
5593 void parse_item_sound(const xmlNode *inNode)
5594 {
5595 const xmlNode *attributeNode = NULL;
5596 char content[100] = "";
5597 item_sound_data * pItem;
5598
5599 if (inNode->type == XML_ELEMENT_NODE)
5600 {
5601 if (sound_num_items < MAX_SOUND_ITEMS)
5602 {
5603 pItem = &sound_item_data[sound_num_items++];
5604
5605 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5606 {
5607 get_string_value(content, sizeof(content), attributeNode);
5608 if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"image_ids"))
5609 {
5610 parse_item_image_ids(content, pItem);
5611 }
5612 else if(!xmlStrcasecmp(attributeNode->name, (xmlChar*)"sound"))
5613 {
5614 pItem->sound = get_index_for_sound_type_name(content);
5615 if (pItem->sound == -1)
5616 {
5617 LOG_ERROR("%s: Unknown sound %s for item sound", snd_config_error, content);
5618 }
5619 }
5620 }
5621 }
5622 else
5623 {
5624 LOG_ERROR("%s: Too many item sounds defined.", snd_config_error);
5625 }
5626 }
5627 else if (inNode->type == XML_ENTITY_REF_NODE)
5628 {
5629 LOG_ERROR("%s: Include not allowed in item sound def", snd_config_error);
5630 }
5631 }
5632
5633 void parse_tile_types(char * content, tile_sound_data * pTileType)
5634 {
5635 int i, j;
5636 char temp[5] = "";
5637
5638 i = 0;
5639 j = -1;
5640 while (i < strlen(content))
5641 {
5642 if (content[i] == ',')
5643 {
5644 if (pTileType->num_tile_types < MAX_SOUND_TILES)
5645 {
5646 pTileType->tile_type[pTileType->num_tile_types++] = atoi(temp);
5647 j = -1;
5648 }
5649 else
5650 {
5651 LOG_ERROR("%s: Too many tile types defined for tile type sound: %s, max: %d", snd_config_error, content, MAX_SOUND_TILES);
5652 return; // Avoid any more errors
5653 }
5654 }
5655 else
5656 {
5657 j++;
5658 if (j < 5)
5659 temp[j] = content[i];
5660 else
5661 {
5662 LOG_ERROR("%s: Invalid tile type defined for tile type sound: %s...", snd_config_error, temp);
5663 j = -1;
5664 }
5665 }
5666 i++;
5667 }
5668 // Add anything remaining as a last tile type
5669 if (pTileType->num_tile_types < MAX_SOUND_TILES)
5670 {
5671 pTileType->tile_type[pTileType->num_tile_types++] = atoi(temp);
5672 }
5673 else
5674 {
5675 LOG_ERROR("%s: Too many tile types defined for tile type sound: %s, max: %d", snd_config_error, content, MAX_SOUND_TILES);
5676 }
5677 return;
5678 }
5679
5680 void parse_tile_type_sound(const xmlNode *inNode)
5681 {
5682 const xmlNode *attributeNode = NULL;
5683 char content[1024] = "";
5684 tile_sound_data * pTileType;
5685
5686 if (inNode->type == XML_ELEMENT_NODE)
5687 {
5688 if (sound_num_tile_types < MAX_SOUND_TILE_TYPES)
5689 {
5690 pTileType = &sound_tile_data[sound_num_tile_types++];
5691
5692 for (attributeNode = inNode->children; attributeNode; attributeNode = attributeNode->next)
5693 {
5694 get_string_value(content, sizeof(content), attributeNode);
5695 if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"tiles"))
5696 {
5697 parse_tile_types(content, pTileType);
5698 }
5699 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"actor_types"))
5700 {
5701 safe_strncpy(pTileType->sounds[pTileType->num_sounds].actor_types, content, sizeof(pTileType->sounds[pTileType->num_sounds].actor_types));
5702 safe_strncpy(content, get_string_property(attributeNode, "sound"), sizeof(content));
5703 pTileType->sounds[pTileType->num_sounds].sound = get_index_for_sound_type_name(content);
5704 if (pTileType->sounds[pTileType->num_sounds].sound == -1)
5705 {
5706 LOG_ERROR("%s: Unknown sound %s for tile type sound", snd_config_error, content);
5707 }
5708 // Increment the actor_types count
5709 pTileType->num_sounds++;
5710 }
5711 else if (!xmlStrcasecmp(attributeNode->name, (xmlChar*)"default"))
5712 {
5713 pTileType->default_sound = get_index_for_sound_type_name(content);
5714 if (pTileType->default_sound == -1)
5715 {
5716 LOG_ERROR("%s: Unknown default sound %s for tile type sound", snd_config_error, content);
5717 }
5718 }
5719 }
5720 }
5721 else
5722 {
5723 LOG_ERROR("%s: Too many tile type sounds defined.", snd_config_error);
5724 }
5725 }
5726 else if (inNode->type == XML_ENTITY_REF_NODE)
5727 {
5728 LOG_ERROR("%s: Include not allowed in tile type sound def", snd_config_error);
5729 }
5730 }
5731
5732 void parse_spell_sound(const xmlNode *inNode)
5733 {
5734 char content[100] = "";
5735 int i = -1;
5736
5737 if (inNode->type == XML_ELEMENT_NODE)
5738 {
5739 get_string_value(content, sizeof(content), inNode);
5740 if (!xmlStrcasecmp(inNode->name, (xmlChar*)"spell_effect"))
5741 {
5742 i = get_int_property(inNode, "id");
5743 if (i >= 0 && i < NUM_ACTIVE_SPELLS)
5744 {
5745 sound_spell_data[i] = get_index_for_sound_type_name(content);
5746 if (sound_spell_data[i] == -1)
5747 {
5748 LOG_ERROR("%s: Unknown sound %s for spell effect sound", snd_config_error, content);
5749 }
5750 }
5751 else
5752 {
5753 LOG_ERROR("%s: Unknown spell effect ID %d for spell effect sound", snd_config_error, i);
5754 }
5755 }
5756 }
5757 else if (inNode->type == XML_ENTITY_REF_NODE)
5758 {
5759 LOG_ERROR("%s: Include not allowed in spell effect sound def", snd_config_error);
5760 }
5761 }
5762
5763 int parse_sound_defs(const xmlNode *node)
5764 {
5765 const xmlNode *def;
5766 int ok = 1;
5767
5768 for (def = node->children; def; def = def->next)
5769 {
5770 if (def->type == XML_ELEMENT_NODE)
5771 {
5772 if (xmlStrcasecmp (def->name, (xmlChar*)"sound") == 0)
5773 {
5774 parse_sound_object(def);
5775 }
5776 else if (xmlStrcasecmp (def->name, (xmlChar*)"defaults") == 0)
5777 {
5778 parse_sound_defaults(def);
5779 }
5780 else if (xmlStrcasecmp (def->name, (xmlChar*)"map") == 0)
5781 {
5782 parse_map_sound(def);
5783 }
5784 else if (xmlStrcasecmp (def->name, (xmlChar*)"effect") == 0)
5785 {
5786 parse_effect_sound(def);
5787 }
5788 else if (xmlStrcasecmp (def->name, (xmlChar*)"particle") == 0)
5789 {
5790 parse_particle_sound(def);
5791 }
5792 else if (xmlStrcasecmp (def->name, (xmlChar*)"item") == 0)
5793 {
5794 parse_item_sound(def);
5795 }
5796 else if (xmlStrcasecmp (def->name, (xmlChar*)"tile_type") == 0)
5797 {
5798 parse_tile_type_sound(def);
5799 }
5800 else if (xmlStrcasecmp (def->name, (xmlChar*)"spell_effect") == 0)
5801 {
5802 parse_spell_sound(def);
5803 }
5804 else
5805 {
5806 LOG_ERROR("%s: Unknown element found: %s", snd_config_error, def->name);
5807 ok = 0;
5808 }
5809 }
5810 else if (def->type == XML_ENTITY_REF_NODE)
5811 {
5812 ok &= parse_sound_defs (def->children);
5813 }
5814 }
5815
5816 return ok;
5817 }
5818
5819 void load_sound_config_data (const char *file)
5820 {
5821 xmlDoc *doc;
5822 const xmlNode *root = NULL;
5823
5824 if (no_sound)
5825 return;
5826
5827 if (!el_file_exists(file))
5828 return;
5829
5830 if ((doc = xmlReadFile(file, NULL, XML_PARSE_NOENT)) == NULL)
5831 {
5832 char str[200];
5833 safe_snprintf(str, sizeof(str), snd_config_open_err_str, file);
5834 LOG_ERROR(str);
5835 LOG_TO_CONSOLE(c_red1,str);
5836 }
5837 // Can we find a root element
5838 else if ((root = xmlDocGetRootElement(doc))==NULL)
5839 {
5840 LOG_ERROR("%s: No XML root element found in '%s'", snd_config_error, file);
5841 }
5842 // Is the root the right type?
5843 else if ( xmlStrcmp( root->name, (xmlChar*)"sound_config" ) )
5844 {
5845 LOG_ERROR("%s: Invalid root element '%s' in '%s'", snd_config_error, root->name, file);
5846 }
5847 // We've found our expected root, now parse the children
5848 else
5849 {
5850 have_sound_config = 1;
5851 clear_sound_data();
5852 parse_sound_defs(root);
5853 parse_server_sounds();
5854 load_sound_warnings_list(SOUND_WARNINGS_PATH);
5855 }
5856
5857 xmlFreeDoc(doc);
5858 #ifdef DEBUG
5859 print_sound_types();
5860 #endif // DEBUG
5861
5862 }
5863
5864 /***********************
5865 * DEBUGGING FUNCTIONS *
5866 ***********************/
5867
5868 #ifdef DEBUG
5869 void print_sound_types()
5870 {
5871 int i, j;
5872 sound_type *pData = NULL;
5873 map_sound_data *pMap = NULL;
5874 map_sound_boundary_def *pMapBoundary = NULL;
5875 effect_sound_data *pEffect = NULL;
5876 particle_sound_data *pParticle = NULL;
5877 item_sound_data *pItem = NULL;
5878 tile_sound_data *pTileType = NULL;
5879
5880 printf("\nSOUND TYPE DATA\n===============\n");
5881 printf("There are %d sound types (max %d):\n", num_types, MAX_SOUNDS);
5882 for (i = 0; i < num_types; ++i)
5883 {
5884 pData = &sound_type_data[i];
5885 printf("Sound type '%s' #%d:\n" , pData->name, i);
5886 for (j = 0; j < pData->num_variants; ++j)
5887 {
5888 printf("\tVariant %d/%d:\n" , j, pData->num_variants);
5889 printf("\t\tIntro sample = '%s'\n" , (pData->variant[j].part[STAGE_INTRO] ? pData->variant[j].part[STAGE_INTRO]->file_path : "(none)"));
5890 printf("\t\tMain sample = '%s'\n" , (pData->variant[j].part[STAGE_MAIN] ? pData->variant[j].part[STAGE_MAIN]->file_path : "(none)"));
5891 printf("\t\tOutro sample = '%s'\n" , (pData->variant[j].part[STAGE_OUTRO] ? pData->variant[j].part[STAGE_OUTRO]->file_path : "(none)"));
5892 printf("\t\tGain = %f\n" , pData->variant[j].gain);
5893 }
5894 printf("\tStereo = %d\n" , pData->stereo);
5895 printf("\tDistance = %f\n" , pData->distance);
5896 printf("\tPositional = %d\n" , pData->positional);
5897 printf("\tLoops = %d\n" , pData->loops);
5898 printf("\tFadeout time = %dms\n" , pData->fadeout_time);
5899 printf("\tEcho delay = %dms\n" , pData->echo_delay);
5900 printf("\tEcho volume = %d%%\n" , pData->echo_volume);
5901 printf("\tTime of day flags = 0x%x\n" , pData->time_of_the_day_flags);
5902 printf("\tPriority = %d\n" , pData->priority);
5903 printf("\tType = %d\n\n" , pData->type);
5904 }
5905
5906 printf("\nMAP SOUND DATA\n===============\n");
5907 printf("There are %d map sounds:\n" , sound_num_maps);
5908 for (i = 0; i < sound_num_maps; ++i)
5909 {
5910 pMap = &sound_map_data[i];
5911 printf("Map id: %d\n" , pMap->id);
5912 printf("Map name: %s\n" , pMap->name);
5913 printf("Num boundaries: %d\n" , pMap->num_boundaries);
5914 for (j = 0; j < pMap->num_boundaries; ++j)
5915 {
5916 pMapBoundary = &pMap->boundaries[j];
5917 printf("Boundary num: %d\n" , j);
5918 printf("\tBackground sound: %d\n" , pMapBoundary->bg_sound);
5919 printf("\tCrowd sound: %d\n" , pMapBoundary->crowd_sound);
5920 printf("\tTime of day flags: 0x%x\n", pMapBoundary->time_of_day_flags);
5921 printf("\tDefault: %s\n" , pMapBoundary->is_default == 0 ? "No" : "Yes");
5922 printf("\tX1, Y1, A1: (%d, %d, %f), X2, Y2, A2: (%d, %d, %f), X3, Y3, A3: (%d, %d, %f), X4, Y4, A4: (%d, %d, %f)\n",
5923 pMapBoundary->p[0].x, pMapBoundary->p[0].y, pMapBoundary->p[0].a,
5924 pMapBoundary->p[1].x, pMapBoundary->p[1].y, pMapBoundary->p[1].a,
5925 pMapBoundary->p[2].x, pMapBoundary->p[2].y, pMapBoundary->p[2].a,
5926 pMapBoundary->p[3].x, pMapBoundary->p[3].y, pMapBoundary->p[3].a);
5927 printf("\tOuter box - X1, Y1, A1: (%d, %d, %f); X2, Y2, A1: (%d, %d, %f)\n",
5928 pMapBoundary->o[0].x, pMapBoundary->o[0].y, pMapBoundary->o[0].a,
5929 pMapBoundary->o[1].x, pMapBoundary->o[1].y, pMapBoundary->o[1].a);
5930 printf("\tInternal point: %d\n" , pMapBoundary->int_point);
5931 }
5932 printf("\n");
5933 printf("Num walk boundaries: %d\n" , pMap->num_walk_boundaries);
5934 for (j = 0; j < pMap->num_walk_boundaries; ++j)
5935 {
5936 pMapBoundary = &pMap->walk_boundaries[j];
5937 printf("Walk boundary num: %d\n" , j);
5938 printf("\tWalk sound: %d\n" , pMapBoundary->bg_sound);
5939 printf("\tTime of day flags: 0x%x\n", pMapBoundary->time_of_day_flags);
5940 printf("\tX1, Y1, A1: (%d, %d, %f), X2, Y2, A2: (%d, %d, %f), X3, Y3, A3: (%d, %d, %f), X4, Y4, A4: (%d, %d, %f)\n",
5941 pMapBoundary->p[0].x, pMapBoundary->p[0].y, pMapBoundary->p[0].a,
5942 pMapBoundary->p[1].x, pMapBoundary->p[1].y, pMapBoundary->p[1].a,
5943 pMapBoundary->p[2].x, pMapBoundary->p[2].y, pMapBoundary->p[2].a,
5944 pMapBoundary->p[3].x, pMapBoundary->p[3].y, pMapBoundary->p[3].a);
5945 printf("\tOuter box - X1, Y1, A1: (%d, %d, %f); X2, Y2, A1: (%d, %d, %f)\n",
5946 pMapBoundary->o[0].x, pMapBoundary->o[0].y, pMapBoundary->o[0].a,
5947 pMapBoundary->o[1].x, pMapBoundary->o[1].y, pMapBoundary->o[1].a);
5948 printf("\tInternal point: %d\n" , pMapBoundary->int_point);
5949 }
5950 printf("\n");
5951 }
5952
5953 printf("\nEFFECT SOUND DATA\n===============\n");
5954 printf("There are %d effect sounds:\n", sound_num_effects);
5955 for (i = 0; i < sound_num_effects; ++i)
5956 {
5957 pEffect = &sound_effect_data[i];
5958 printf("Effect ID: %d\n" , pEffect->id);
5959 printf("Sound: %d\n" , pEffect->sound);
5960 }
5961
5962 printf("\nPARTICLE SOUND DATA\n===============\n");
5963 printf("There are %d particle sounds:\n", sound_num_particles);
5964 for (i = 0; i < sound_num_particles; ++i)
5965 {
5966 pParticle = &sound_particle_data[i];
5967 printf("Particle file: %s\n" , pParticle->file);
5968 printf("Sound: %d\n" , pParticle->sound);
5969 }
5970
5971 printf("\nITEM SOUND DATA\n===============\n");
5972 printf("There are %d item sounds:\n", sound_num_items);
5973 for (i = 0; i < sound_num_items; ++i)
5974 {
5975 pItem = &sound_item_data[i];
5976 printf("Sound: %d\n" , pItem->sound);
5977 printf("Image ID's (%d total):\n" , pItem->num_imageids);
5978 for (j = 0; j < pItem->num_imageids; ++j)
5979 {
5980 printf("%d, " , pItem->image_id[j]);
5981 }
5982 printf("\n");
5983 }
5984
5985 printf("\nTILE (WALKING) SOUND DATA\n===============\n");
5986 printf("There are %d tile type sounds:\n", sound_num_tile_types);
5987 for (i = 0; i < sound_num_tile_types; ++i)
5988 {
5989 pTileType = &sound_tile_data[i];
5990 printf("Tile: %d\n" , i);
5991 printf("\tDefault sound: %d\n" , pTileType->default_sound);
5992 printf("\tTile types (%d total):\n\t\t" , pTileType->num_tile_types);
5993 for (j = 0; j < pTileType->num_tile_types; ++j)
5994 {
5995 printf("%d, " , pTileType->tile_type[j]);
5996 }
5997 printf("\n\tNum sounds: %d\n" , pTileType->num_sounds);
5998 for (j = 0; j < pTileType->num_sounds; ++j)
5999 {
6000 printf("\t\tSound: %d\n" , pTileType->sounds[j].sound);
6001 printf("\t\tActor types: %s\n" , pTileType->sounds[j].actor_types);
6002 }
6003 }
6004
6005 printf("\nSPELL EFFECT SOUND DATA\n===============\n");
6006 printf("There are %d spell effects:\n", NUM_ACTIVE_SPELLS);
6007 for (i = 0; i <NUM_ACTIVE_SPELLS; ++i)
6008 {
6009 printf("Spell Effect Sound: %d = %d\n", i, sound_spell_data[i]);
6010 }
6011
6012 printf("\nSERVER SOUNDS\n===============\n");
6013 printf("There are %d server sounds:\n", MAX_SERVER_SOUNDS);
6014 for (i = 0; i <MAX_SERVER_SOUNDS; ++i)
6015 {
6016 printf("Server Sound: %d = %d\n", i, server_sound[i]);
6017 }
6018
6019 printf("\nTEXT WARNING SOUNDS\n===============\n");
6020 printf("There are %d/%d text warning sounds:\n", num_sound_warnings, MAX_SOUND_WARNINGS);
6021 for (i = 0; i < num_sound_warnings; ++i)
6022 {
6023 printf("Text Warning: %d\n", i);
6024 printf("\tText: %s\n", warnings_list[i].string);
6025 printf("\tSound: %d\n", warnings_list[i].sound);
6026 }
6027 }
6028
6029 void print_sound_samples()
6030 {
6031 int i;
6032 sound_sample *pData=NULL;
6033 printf("\nSOUND SAMPLE DATA\n===============\n");
6034 printf("There are %d sound samples loaded (max %d):\n", num_samples, MAX_BUFFERS);
6035 printf("(skipped sample numbers are buffers that have been used and released)\n");
6036
6037 for (i = 0; i < MAX_BUFFERS; ++i)
6038 {
6039 pData = &sound_sample_data[i];
6040 if (alIsBuffer(pData->buffer))
6041 {
6042 printf("Sample %d:\n" , i);
6043 printf("\tBuffer ID = %d\n" , pData->buffer);
6044 printf("\tSize = %d\n" , pData->size);
6045 printf("\tFrequency = %f\n" , pData->freq);
6046 printf("\tChannels = %d\n" , pData->channels);
6047 printf("\tBits = %d\n" , pData->bits);
6048 printf("\tLength = %dms\n\n" , pData->length);
6049 }
6050 }
6051 }
6052
6053 void print_sounds_list()
6054 {
6055 int i;
6056 sound_loaded *pData = NULL;
6057 printf("\nLOADED SOUND DATA\n===============\n");
6058 printf("There are %d loaded sounds (max %d):\n", num_sounds, MAX_BUFFERS * 2);
6059
6060 for (i = 0; i < num_sounds; ++i)
6061 {
6062 pData = &sounds_list[i];
6063 printf("Loaded sound #%d:\n" , i);
6064 printf("\tSound type %d : '%s'\n" , pData->sound, sound_type_data[pData->sound].name);
6065 printf("\tX = %d\n" , pData->x);
6066 printf("\tY = %d\n" , pData->y);
6067 printf("\tPlaying = %s\n" , pData->playing == 0 ? "No" : "Yes");
6068 printf("\tBase gain = %f\n" , pData->base_gain);
6069 printf("\tCurrent (final) gain = %f\n" , pData->cur_gain);
6070 printf("\tSamples are loaded: %s\n" , pData->loaded == 0 ? "No" : "Yes");
6071 }
6072 }
6073
6074 void print_sound_sources()
6075 {
6076 int i;
6077 source_data *pData = NULL;
6078 printf("\nSOUND SOURCE DATA\n===============\n");
6079 printf("There are %d sound sources (max %d):\n", used_sources, max_sources);
6080
6081 for (i = 0; i < used_sources; ++i)
6082 {
6083 pData = &sound_source_data[i];
6084 printf("Source #%d:\n" , i);
6085 printf("\tLoaded sound num = %d\n" , pData->loaded_sound);
6086 printf("\tSound type = %d : '%s'\n" , sounds_list[pData->loaded_sound].sound
6087 , sound_type_data[sounds_list[pData->loaded_sound].sound].name);
6088 printf("\tPlay duration = %dms\n" , pData->play_duration);
6089 printf("\tSource ID = %d\n" , pData->source);
6090 }
6091 }
6092
6093 void print_sound_streams()
6094 {
6095 int i;
6096 stream_data *pData = NULL;
6097 printf("\nSOUND STREAM DATA\n===============\n");
6098 printf("There are %d sound streams:\n", max_streams);
6099
6100 for (i = 0; i < max_streams; ++i)
6101 {
6102 pData = &streams[i];
6103 printf("Stream #%d:\n" , i);
6104 printf("\tType = %s\n" , get_stream_type(pData->type));
6105 printf("\tSound = %d : '%s'\n" , pData->sound
6106 , pData->type != STREAM_TYPE_MUSIC ? sound_type_data[pData->sound].name : playlist[pData->sound].file_name);
6107 printf("\tSource ID = %d\n" , pData->source);
6108 printf("\tCookie = %u\n" , pData->cookie);
6109 printf("\tPlaying = %s\n" , pData->playing == 1 ? "Yes" : "No");
6110 printf("\tDefault = %s\n" , pData->is_default == 1 ? "Yes" : "No");
6111 printf("\tCurrent fade = %d\n" , pData->fade);
6112 printf("\tFade length = %d\n" , pData->fade_length);
6113 printf("\tProcessed = %d\n" , pData->processed);
6114 }
6115 }
6116
6117 #endif //_DEBUG
6118 #endif // !NEW_SOUND
6119