1 /*
2  * File: snd-sdl.c
3  * Purpose: SDL sound support
4  *
5  * Copyright (c) 2004-2007 Brendon Oliver, Andrew Sidwell.
6  * A large chunk of this file was taken and modified from main-ros.
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  */
19 
20 /* modified for TomeNET to support our custom sound structure and also
21    background music and weather - C. Blue */
22 
23 #include "angband.h"
24 
25 
26 #ifdef SOUND_SDL
27 
28 /* Smooth dynamic weather volume change depending on amount of particles,
29    instead of just on/off depending on particle count window? */
30 //#define WEATHER_VOL_PARTICLES  -- not yet that cool
31 
32 /* Maybe this will be cool: Dynamic weather volume calculated from distances to registered clouds */
33 #define WEATHER_VOL_CLOUDS
34 
35 /*
36 #include <SDL/SDL.h>
37 #include <SDL/SDL_mixer.h>
38 #include <SDL/SDL_thread.h>
39 */
40 
41 /* This is the way recommended by the SDL web page */
42 #include "SDL.h"
43 #include "SDL_mixer.h"
44 #include "SDL_thread.h"
45 
46 /* completely turn off mixing of disabled audio features (music, sound, weather, all)
47    as opposed to just muting their volume? */
48 //#define DISABLE_MUTED_AUDIO
49 
50 /* load sounds on the fly if the loader thread has not loaded them yet */
51 /* disabled because this can cause delays up to a few seconds */
52 bool on_demand_loading = FALSE;
53 
54 /* output various status messages about initializing audio */
55 //#define DEBUG_SOUND
56 
57 /* Path to sound files */
58 static const char *ANGBAND_DIR_XTRA_SOUND;
59 static const char *ANGBAND_DIR_XTRA_MUSIC;
60 
61 
62 /* for threaded caching of audio files */
63 SDL_Thread *load_audio_thread;
64 SDL_mutex *load_sample_mutex_entrance, *load_song_mutex_entrance;
65 SDL_mutex *load_sample_mutex, *load_song_mutex;
66 
67 
68 /* declare */
69 static void fadein_next_music(void);
70 static void clear_channel(int c);
71 static bool my_fexists(const char *fname);
72 
73 static int thread_load_audio(void *dummy);
74 static Mix_Chunk* load_sample(int idx, int subidx);
75 static Mix_Music* load_song(int idx, int subidx);
76 
77 
78 /* Arbitrary limit of mixer channels */
79 #define MAX_CHANNELS	32
80 
81 /* Arbitary limit on number of samples per event */
82 #define MAX_SAMPLES	8
83 
84 /* Arbitary limit on number of music songs per situation */
85 #define MAX_SONGS	3
86 
87 /* Exponential volume level table
88  * evlt[i] = round(0.09921 * exp(2.31 * i / 100))
89  */
90 
91 static s16b evlt[101] = { 12,
92   13,  13,  14,  14,  14,  15,  15,  15,  16,  16,
93   16,  17,  17,  18,  18,  18,  19,  19,  20,  20,
94   21,  21,  22,  22,  23,  23,  24,  24,  25,  25,
95   26,  27,  27,  28,  29,  29,  30,  31,  31,  32,
96   33,  34,  34,  35,  36,  37,  38,  38,  39,  40,
97   41,  42,  43,  44,  45,  46,  47,  48,  50,  51,
98   52,  53,  54,  56,  57,  58,  60,  61,  63,  64,
99   65,  67,  69,  70,  72,  73,  75,  77,  79,  81,
100   82,  84,  86,  88,  90,  93,  95,  97,  99, 102,
101  104, 106, 109, 111, 114, 117, 119, 122, 125, 128
102 };
103 
104 #if 1 /* Exponential volume scale - mikaelh */
105  #define CALC_MIX_VOLUME(T, V)	(cfg_audio_master * T * evlt[V] * evlt[cfg_audio_master_volume] / MIX_MAX_VOLUME)
106 #endif
107 #if 0 /* use linear volume scale -- poly+50 would be best, but already causes mixer outtages if total volume becomes too small (ie < 1).. =_= */
108  #define CALC_MIX_VOLUME(T, V)  ((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? (V) : 0) : 0) * cfg_audio_master_volume) / 10000)
109 #endif
110 #if 0 /* use polynomial volume scale -- '+50' seems best, although some low-low combos already won't produce sound at all due to low mixer resolution. maybe just use linear scale, simply? */
111  #define CALC_MIX_VOLUME(T, V)	((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? (((V) + 50) * ((V) + 50)) / 100 - 25 : 0) : 0) * (((cfg_audio_master_volume + 50) * (cfg_audio_master_volume + 50)) / 100 - 25)) / 40000)
112 // #define CALC_MIX_VOLUME(T, V)	((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? (((V) + 30) * ((V) + 30)) / 100 - 9 : 0) : 0) * (((cfg_audio_master_volume + 30) * (cfg_audio_master_volume + 30)) / 100 - 9)) / 25600)
113 // #define CALC_MIX_VOLUME(T, V)	((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? (((V) + 10) * ((V) + 10)) / 100 - 1 : 0) : 0) * (((cfg_audio_master_volume + 10) * (cfg_audio_master_volume + 10)) / 100 - 1)) / 14400)
114 #endif
115 #if 0 /* use exponential volume scale (whoa) - but let's use a lookup table for efficiency ^^ EDIT: too extreme */
116  static int vol[11] = { 0, 1, 2, 4, 6, 10, 16, 26, 42, 68, 100 }; /* this is similar to rounded down 1.6^(0..10) */
117  #define CALC_MIX_VOLUME(T, V)	((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? vol[(V) / 10] : 0) : 0) * vol[cfg_audio_master_volume / 10]) / 10000)
118 #endif
119 #if 0 /* also too extreme, even more so */
120  static int vol[11] = { 0, 1, 2, 3, 5, 8, 14, 25, 42, 68, 100 }; /* this is similar to rounded down 1.6^(0..10) */
121  #define CALC_MIX_VOLUME(T, V)	((MIX_MAX_VOLUME * (cfg_audio_master ? ((T) ? vol[(V) / 10] : 0) : 0) * vol[cfg_audio_master_volume / 10]) / 10000)
122 #endif
123 
124 /* Struct representing all data about an event sample */
125 typedef struct {
126 	int num;                        /* Number of samples for this event */
127 	Mix_Chunk *wavs[MAX_SAMPLES];   /* Sample array */
128 	const char *paths[MAX_SAMPLES]; /* Relative pathnames for samples */
129 	int current_channel;		/* Channel it's currently being played on, -1 if none; to avoid
130 					   stacking of the same sound multiple (read: too many) times - ...
131 					   note that with 4.4.5.4+ this is deprecated - C. Blue */
132 	int started_timer_tick;		/* global timer tick on which this sample was started (for efficiency) */
133 	bool disabled;
134 	bool config;
135 } sample_list;
136 
137 /* background music */
138 typedef struct {
139 	int num;
140 	Mix_Music *wavs[MAX_SONGS];
141 	const char *paths[MAX_SONGS];
142 	bool disabled;
143 	bool config;
144 } song_list;
145 
146 /* Just need an array of SampInfos */
147 static sample_list samples[SOUND_MAX_2010];
148 
149 /* Array of potential channels, for managing that only one
150    sound of a kind is played simultaneously, for efficiency - C. Blue */
151 static int channel_sample[MAX_CHANNELS];
152 static int channel_type[MAX_CHANNELS];
153 static int channel_volume[MAX_CHANNELS];
154 static s32b channel_player_id[MAX_CHANNELS];
155 
156 /* Music Array */
157 static song_list songs[MUSIC_MAX];
158 
159 
160 /*
161  * Shut down the sound system and free resources.
162  */
close_audio(void)163 static void close_audio(void) {
164 	size_t i;
165 	int j;
166 
167 	/* Kill the loading thread if it's still running */
168 	if (load_audio_thread) SDL_KillThread(load_audio_thread);
169 
170 	Mix_HaltMusic();
171 
172 	/* Free all the sample data*/
173 	for (i = 0; i < SOUND_MAX_2010; i++) {
174 		sample_list *smp = &samples[i];
175 
176 		/* Nuke all samples */
177 		for (j = 0; j < smp->num; j++) {
178 			Mix_FreeChunk(smp->wavs[j]);
179 			string_free(smp->paths[j]);
180 		}
181 	}
182 
183 	/* Free all the music data*/
184 	for (i = 0; i < MUSIC_MAX; i++) {
185 		song_list *mus = &songs[i];
186 
187 		/* Nuke all samples */
188 		for (j = 0; j < mus->num; j++) {
189 			Mix_FreeMusic(mus->wavs[j]);
190 			string_free(mus->paths[j]);
191 		}
192 	}
193 
194 	string_free(ANGBAND_DIR_XTRA_SOUND);
195 	string_free(ANGBAND_DIR_XTRA_MUSIC);
196 
197 	/* Close the audio */
198 	Mix_CloseAudio();
199 
200 	SDL_DestroyMutex(load_sample_mutex_entrance);
201 	SDL_DestroyMutex(load_song_mutex_entrance);
202 	SDL_DestroyMutex(load_sample_mutex);
203 	SDL_DestroyMutex(load_song_mutex);
204 
205 	/* XXX This may conflict with the SDL port */
206 	SDL_Quit();
207 }
208 
209 
210 /*
211  * Initialise SDL and open the mixer
212  */
open_audio(void)213 static bool open_audio(void) {
214 	int audio_rate;
215 	Uint16 audio_format;
216 	int audio_channels;
217 
218 	/* Initialize variables */
219 	if (cfg_audio_rate < 4000) cfg_audio_rate = 4000;
220 	if (cfg_audio_rate > 48000) cfg_audio_rate = 48000;
221 	audio_rate = cfg_audio_rate;
222 	audio_format = AUDIO_S16SYS;
223 	audio_channels = 2;
224 
225 	/* Initialize the SDL library */
226 	if (SDL_Init(SDL_INIT_AUDIO) < 0) {
227 //#ifdef DEBUG_SOUND
228 		plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
229 //		puts(format("Couldn't initialize SDL: %s", SDL_GetError()));
230 //#endif
231 		return FALSE;
232 	}
233 
234 	/* Try to open the audio */
235 	if (cfg_audio_buffer < 128) cfg_audio_buffer = 128;
236 	if (cfg_audio_buffer > 8192) cfg_audio_buffer = 8192;
237 	if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, cfg_audio_buffer) < 0) {
238 //#ifdef DEBUG_SOUND
239 		plog_fmt("Couldn't open mixer: %s", SDL_GetError());
240 //		puts(format("Couldn't open mixer: %s", SDL_GetError()));
241 //#endif
242 		return FALSE;
243 	}
244 
245 	if (cfg_max_channels > MAX_CHANNELS) cfg_max_channels = MAX_CHANNELS;
246 	if (cfg_max_channels < 4) cfg_max_channels = 4;
247 	Mix_AllocateChannels(cfg_max_channels);
248 	/* set hook for clearing faded-out weather and for managing sound-fx playback */
249 	Mix_ChannelFinished(clear_channel);
250 	/* set hook for fading over to next song */
251 	Mix_HookMusicFinished(fadein_next_music);
252 
253 	/* Success */
254 	return TRUE;
255 }
256 
257 
258 
259 /*
260  * Read sound.cfg and map events to sounds; then load all the sounds into
261  * memory to avoid I/O latency later.
262  */
sound_sdl_init(bool no_cache)263 static bool sound_sdl_init(bool no_cache) {
264 	char path[2048];
265 	char buffer0[2048], *buffer = buffer0;
266 	FILE *fff;
267 	int i;
268 	char out_val[160];
269 	bool disabled;
270 
271 	bool events_loaded_semaphore;
272 
273 	load_sample_mutex_entrance = SDL_CreateMutex();
274 	load_song_mutex_entrance = SDL_CreateMutex();
275 	load_sample_mutex = SDL_CreateMutex();
276 	load_song_mutex = SDL_CreateMutex();
277 
278 	/* Initialise the mixer  */
279 	if (!open_audio()) return FALSE;
280 
281 #ifdef DEBUG_SOUND
282 	puts(format("sound_sdl_init() opened at %d Hz.", cfg_audio_rate));
283 #endif
284 
285 	/* Initialize sound-fx channel management */
286 	for (i = 0; i < cfg_max_channels; i++) channel_sample[i] = -1;
287 
288 
289 	/* ------------------------------- Init Sounds */
290 
291 	/* Build the "sound" path */
292 	path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
293 	ANGBAND_DIR_XTRA_SOUND = string_make(path);
294 
295 	/* Find and open the config file */
296 	path_build(path, sizeof(path), ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
297 	fff = my_fopen(path, "r");
298 
299 	/* Handle errors */
300 	if (!fff) {
301 #if 0
302 		plog_fmt("Failed to open sound config (%s):\n    %s", path, strerror(errno));
303 		return FALSE;
304 #else /* try to use simple default file */
305 		FILE *fff2;
306 		char path2[2048];
307 
308 		path_build(path, sizeof(path), ANGBAND_DIR_XTRA_SOUND, "sound.cfg.default");
309 		fff = my_fopen(path, "r");
310 		if (!fff) {
311 			plog_fmt("Failed to open default sound config (%s):\n    %s", path, strerror(errno));
312 			return FALSE;
313 		}
314 
315 		path_build(path2, sizeof(path2), ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
316 		fff2 = my_fopen(path2, "w");
317 		if (!fff2) {
318 			plog_fmt("Failed to write sound config (%s):\n    %s", path2, strerror(errno));
319 			return FALSE;
320 		}
321 
322 		while (my_fgets(fff, buffer, sizeof(buffer)) == 0)
323 			fprintf(fff2, "%s\n", buffer);
324 
325 		my_fclose(fff2);
326 		my_fclose(fff);
327 
328 		/* Try again */
329 		path_build(path, sizeof(path), ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
330 		fff = my_fopen(path, "r");
331 		if (!fff) {
332 			plog_fmt("Failed to open sound config (%s):\n    %s", path, strerror(errno));
333 			return FALSE;
334 		}
335 #endif
336 	}
337 
338 #ifdef DEBUG_SOUND
339 	puts("sound_sdl_init() reading sound.cfg:");
340 #endif
341 
342 	/* Parse the file */
343 	/* Lines are always of the form "name = sample [sample ...]" */
344 	while (my_fgets(fff, buffer0, sizeof(buffer0)) == 0) {
345 		char *cfg_name;
346 		cptr lua_name;
347 		char *sample_list;
348 		char *search;
349 		char *cur_token;
350 		char *next_token;
351 		int event;
352 
353 		/* Lines starting on ';' count as 'provided event' but actually
354 		   remain silent, as a way of disabling effects/songs without
355 		   letting the server know. */
356 		buffer = buffer0;
357 		if (buffer0[0] == ';') {
358 			buffer++;
359 			disabled = TRUE;
360 		} else disabled = FALSE;
361 
362 		/* Skip anything not beginning with an alphabetic character */
363 		if (!buffer[0] || !isalpha((unsigned char)buffer[0])) continue;
364 
365 		/* Split the line into two: message name, and the rest */
366 		search = strchr(buffer, ' ');
367 		sample_list = strchr(search + 1, ' ');
368 		/* no event name given? */
369 		if (!search) continue;
370 		/* no audio filenames listed? */
371 		if (!sample_list) continue;
372 
373 		/* Set the message name, and terminate at first space */
374 		cfg_name = buffer;
375 		search[0] = '\0';
376 
377 		/* Make sure this is a valid event name */
378 		for (event = SOUND_MAX_2010 - 1; event >= 0; event--) {
379 			sprintf(out_val, "return get_sound_name(%d)", event);
380 			lua_name = string_exec_lua(0, out_val);
381 			if (!strlen(lua_name)) continue;
382 			if (strcmp(cfg_name, lua_name) == 0) break;
383 		}
384 		if (event < 0) {
385 			fprintf(stderr, "Sample '%s' not in audio.lua\n", cfg_name);
386 			continue;
387 		}
388 
389 		/* Advance the sample list pointer so it's at the beginning of text */
390 		sample_list++;
391 		if (!sample_list[0]) continue;
392 
393 		/* Terminate the current token */
394 		cur_token = sample_list;
395 		search = strchr(cur_token, ' ');
396 		if (search) {
397 			search[0] = '\0';
398 			next_token = search + 1;
399 		} else {
400 			next_token = NULL;
401 		}
402 
403 		/*
404 		 * Now we find all the sample names and add them one by one
405 		*/
406 		events_loaded_semaphore = FALSE;
407 		while (cur_token) {
408 			int num = samples[event].num;
409 
410 			/* Don't allow too many samples */
411 			if (num >= MAX_SAMPLES) break;
412 
413 			/* Build the path to the sample */
414 			path_build(path, sizeof(path), ANGBAND_DIR_XTRA_SOUND, cur_token);
415 			if (!my_fexists(path)) {
416 				fprintf(stderr, "Can't find sample '%s'\n", cur_token);
417 				goto next_token_snd;
418 			}
419 
420 			/* Don't load now if we're not caching */
421 			if (no_cache) {
422 				/* Just save the path for later */
423 				samples[event].paths[num] = string_make(path);
424 			} else {
425 				/* Load the file now */
426 				samples[event].wavs[num] = Mix_LoadWAV(path);
427 				if (!samples[event].wavs[num]) {
428 					plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
429 					puts(format("%s: %s (%s)", SDL_GetError(), strerror(errno), path));//DEBUG USE_SOUND_2010
430 					goto next_token_snd;
431 				}
432 			}
433 			/* Initialize as 'not being played' */
434 			samples[event].current_channel = -1;
435 
436 			//puts(format("loaded sample %s (ev %d, #%d).", samples[event].paths[num], event, num));//debug
437 
438 			/* Imcrement the sample count */
439 			samples[event].num++;
440 			if (!events_loaded_semaphore) {
441 				events_loaded_semaphore = TRUE;
442 				audio_sfx++;
443 				/* for do_cmd_options_...(): remember that this sample was mentioned in our config file */
444 				samples[event].config = TRUE;
445 			}
446 
447 			next_token_snd:
448 
449 			/* Figure out next token */
450 			cur_token = next_token;
451 			if (next_token) {
452 				/* Try to find a space */
453 				search = strchr(cur_token, ' ');
454 
455 				/* If we can find one, terminate, and set new "next" */
456 				if (search) {
457 					search[0] = '\0';
458 					next_token = search + 1;
459 				} else {
460 					/* Otherwise prevent infinite looping */
461 					next_token = NULL;
462 				}
463 			}
464 		}
465 
466 		/* disable this sfx? */
467 		if (disabled) samples[event].disabled = TRUE;
468 	}
469 
470 	/* Close the file */
471 	my_fclose(fff);
472 
473 
474 	/* ------------------------------- Init Music */
475 
476 	buffer = buffer0;
477 
478 	/* Build the "music" path */
479 	path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "music");
480 	ANGBAND_DIR_XTRA_MUSIC = string_make(path);
481 
482 	/* Find and open the config file */
483 	path_build(path, sizeof(path), ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
484 	fff = my_fopen(path, "r");
485 
486 	/* Handle errors */
487 	if (!fff) {
488 #if 0
489 		plog_fmt("Failed to open music config (%s):\n    %s", path, strerror(errno));
490 		return FALSE;
491 #else /* try to use simple default file */
492 		FILE *fff2;
493 		char path2[2048];
494 
495 		path_build(path, sizeof(path), ANGBAND_DIR_XTRA_MUSIC, "music.cfg.default");
496 		fff = my_fopen(path, "r");
497 		if (!fff) {
498 			plog_fmt("Failed to open default music config (%s):\n    %s", path, strerror(errno));
499 			return FALSE;
500 		}
501 
502 		path_build(path2, sizeof(path2), ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
503 		fff2 = my_fopen(path2, "w");
504 		if (!fff2) {
505 			plog_fmt("Failed to write music config (%s):\n    %s", path2, strerror(errno));
506 			return FALSE;
507 		}
508 
509 		while (my_fgets(fff, buffer, sizeof(buffer)) == 0)
510 			fprintf(fff2, "%s\n", buffer);
511 
512 		my_fclose(fff2);
513 		my_fclose(fff);
514 
515 		/* Try again */
516 		path_build(path, sizeof(path), ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
517 		fff = my_fopen(path, "r");
518 		if (!fff) {
519 			plog_fmt("Failed to open music config (%s):\n    %s", path, strerror(errno));
520 			return FALSE;
521 		}
522 #endif
523 	}
524 
525 #ifdef DEBUG_SOUND
526 	puts("sound_sdl_init() reading music.cfg:");
527 #endif
528 
529 	/* Parse the file */
530 	/* Lines are always of the form "name = music [music ...]" */
531 	while (my_fgets(fff, buffer0, sizeof(buffer0)) == 0) {
532 		char *cfg_name;
533 		cptr lua_name;
534 		char *song_list;
535 		char *search;
536 		char *cur_token;
537 		char *next_token;
538 		int event;
539 
540 		/* Lines starting on ';' count as 'provided event' but actually
541 		   remain silent, as a way of disabling effects/songs without
542 		   letting the server know. */
543 		buffer = buffer0;
544 		if (buffer0[0] == ';') {
545 			buffer++;
546 			disabled = TRUE;
547 		} else disabled = FALSE;
548 
549 		/* Skip anything not beginning with an alphabetic character */
550 		if (!buffer[0] || !isalpha((unsigned char)buffer[0])) continue;
551 
552 		/* Split the line into two: message name, and the rest */
553 		search = strchr(buffer, ' ');
554 		song_list = strchr(search + 1, ' ');
555 		/* no event name given? */
556 		if (!search) continue;
557 		/* no audio filenames listed? */
558 		if (!song_list) continue;
559 
560 		/* Set the message name, and terminate at first space */
561 		cfg_name = buffer;
562 		search[0] = '\0';
563 
564 		/* Make sure this is a valid event name */
565 		for (event = MUSIC_MAX - 1; event >= 0; event--) {
566 			sprintf(out_val, "return get_music_name(%d)", event);
567 			lua_name = string_exec_lua(0, out_val);
568 			if (!strlen(lua_name)) continue;
569 			if (strcmp(cfg_name, lua_name) == 0) break;
570 		}
571 		if (event < 0) {
572 			fprintf(stderr, "Song '%s' not in audio.lua\n", cfg_name);
573 			continue;
574 		}
575 
576 		/* Advance the sample list pointer so it's at the beginning of text */
577 		song_list++;
578 		if (!song_list[0]) continue;
579 
580 		/* Terminate the current token */
581 		cur_token = song_list;
582 		if (cur_token[0] == '\"') {
583 			cur_token++;
584 			search = strchr(cur_token, '\"');
585 			if (search) {
586 				search[0] = '\0';
587 				search = strchr(search + 1, ' ');
588 			}
589 		} else {
590 			search = strchr(cur_token, ' ');
591 		}
592 		if (search) {
593 			search[0] = '\0';
594 			next_token = search + 1;
595 		} else {
596 			next_token = NULL;
597 		}
598 
599 		/*
600 		 * Now we find all the sample names and add them one by one
601 		*/
602 		events_loaded_semaphore = FALSE;
603 		while (cur_token) {
604 			int num = songs[event].num;
605 
606 			/* Don't allow too many songs */
607 			if (num >= MAX_SONGS) break;
608 
609 			/* Build the path to the sample */
610 			path_build(path, sizeof(path), ANGBAND_DIR_XTRA_MUSIC, cur_token);
611 			if (!my_fexists(path)) {
612 				fprintf(stderr, "Can't find song '%s'\n", cur_token);
613 				goto next_token_mus;
614 			}
615 
616 			/* Don't load now if we're not caching */
617 			if (no_cache) {
618 				/* Just save the path for later */
619 				songs[event].paths[num] = string_make(path);
620 			} else {
621 				/* Load the file now */
622 				songs[event].wavs[num] = Mix_LoadMUS(path);
623 				if (!songs[event].wavs[num]) {
624 //					puts(format("PRBPATH: lua_name %s, ev %d, num %d, path %s", lua_name, event, num, path));
625 					plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
626 //					puts(format("%s: %s", SDL_GetError(), strerror(errno)));//DEBUG USE_SOUND_2010
627 					goto next_token_mus;
628 				}
629 			}
630 
631 			//puts(format("loaded song %s (ev %d, #%d).", songs[event].paths[num], event, num));//debug
632 			/* Imcrement the sample count */
633 			songs[event].num++;
634 			if (!events_loaded_semaphore) {
635 				events_loaded_semaphore = TRUE;
636 				audio_music++;
637 				/* for do_cmd_options_...(): remember that this sample was mentioned in our config file */
638 				songs[event].config = TRUE;
639 			}
640 
641 			next_token_mus:
642 
643 			/* Figure out next token */
644 			cur_token = next_token;
645 			if (next_token) {
646 				/* Try to find a space */
647 				if (cur_token[0] == '\"') {
648 					cur_token++;
649 					search = strchr(cur_token, '\"');
650 					if (search) {
651 						search[0] = '\0';
652 						search = strchr(search + 1, ' ');
653 					}
654 				} else {
655 					search = strchr(cur_token, ' ');
656 				}
657 				/* If we can find one, terminate, and set new "next" */
658 				if (search) {
659 					search[0] = '\0';
660 					next_token = search + 1;
661 				} else {
662 					/* Otherwise prevent infinite looping */
663 					next_token = NULL;
664 				}
665 			}
666 		}
667 
668 		/* disable this song? */
669 		if (disabled) songs[event].disabled = TRUE;
670 	}
671 
672 	/* Close the file */
673 	my_fclose(fff);
674 
675 #ifdef DEBUG_SOUND
676 	puts("sound_sdl_init() done.");
677 #endif
678 
679 	/* Success */
680 	return TRUE;
681 }
682 
683 /*
684  * Play a sound of type "event". Returns FALSE if sound couldn't be played.
685  */
play_sound(int event,int type,int vol,s32b player_id)686 static bool play_sound(int event, int type, int vol, s32b player_id) {
687 	Mix_Chunk *wave = NULL;
688 	int s;
689 	bool test = FALSE;
690 
691 #ifdef DISABLE_MUTED_AUDIO
692 	if (!cfg_audio_master || !cfg_audio_sound) return TRUE; /* claim that it 'succeeded' */
693 #endif
694 	if (samples[event].disabled) return TRUE; /* claim that it 'succeeded' */
695 
696 	/* Paranoia */
697 	if (event < 0 || event >= SOUND_MAX_2010) return FALSE;
698 
699 	/* Check there are samples for this event */
700 	if (!samples[event].num) return FALSE;
701 
702 	/* already playing? allow to prevent multiple sounds of the same kind
703 	   from being mixed simultaneously, for preventing silliness */
704 	switch (type) {
705 	case SFX_TYPE_ATTACK: if (c_cfg.ovl_sfx_attack) break; else test = TRUE;
706 		break;
707 	case SFX_TYPE_COMMAND: if (c_cfg.ovl_sfx_command) break; else test = TRUE;
708 		break;
709 	case SFX_TYPE_MISC: if (c_cfg.ovl_sfx_misc) break; else test = TRUE;
710 		break;
711 	case SFX_TYPE_MON_ATTACK: if (c_cfg.ovl_sfx_mon_attack) break; else test = TRUE;
712 		break;
713 	case SFX_TYPE_MON_SPELL: if (c_cfg.ovl_sfx_mon_spell) break; else test = TRUE;
714 		break;
715 	case SFX_TYPE_MON_MISC: if (c_cfg.ovl_sfx_mon_misc) break; else test = TRUE;
716 		break;
717 	case SFX_TYPE_NO_OVERLAP: /* never overlap! (eg tunnelling) */
718 		test = TRUE;
719 		break;
720 	case SFX_TYPE_WEATHER:
721 	case SFX_TYPE_AMBIENT:
722 		/* always allow overlapping, since these should be sent by the
723 		   server in a completely sensibly timed manner anyway. */
724 		break;
725 	default:
726 		test = TRUE;
727 	}
728 	if (test) {
729 #if 0 /* old method before sounds could've come from other players nearby us, too */
730 		if (samples[event].current_channel != -1) return TRUE;
731 #else /* so now we need to allow multiple samples, IF they stem from different sources aka players */
732 		for (s = 0; s < cfg_max_channels; s++) {
733 			if (channel_sample[s] == event && channel_player_id[s] == player_id) return TRUE;
734 		}
735 #endif
736 	}
737 
738 	/* prevent playing duplicate sfx that were initiated very closely
739 	   together in time, after one each other? (efficiency) */
740 	if (c_cfg.no_ovl_close_sfx && ticks == samples[event].started_timer_tick) return TRUE;
741 
742 
743 	/* Choose a random event */
744 	s = rand_int(samples[event].num);
745 	wave = samples[event].wavs[s];
746 
747 	/* Try loading it, if it's not cached */
748 	if (!wave) {
749 		if (on_demand_loading || no_cache_audio) {
750 			if (!(wave = load_sample(event, s))) {
751 				/* we really failed to load it */
752 				plog(format("SDL sound load failed (%d, %d).", event, s));
753 				return FALSE;
754 			}
755 		} else {
756 			/* Fail silently */
757 			return TRUE;
758 		}
759 	}
760 
761 	/* Actually play the thing */
762 	/* remember, for efficiency management */
763 	s = Mix_PlayChannel(-1, wave, 0);
764 	if (s != -1) {
765 		channel_sample[s] = event;
766 		channel_type[s] = type;
767 		channel_volume[s] = vol;
768 		channel_player_id[s] = player_id;
769 
770 		/* HACK - use weather volume for thunder sfx */
771 		if (type == SFX_TYPE_WEATHER)
772 			Mix_Volume(s, (CALC_MIX_VOLUME(cfg_audio_weather, (cfg_audio_weather_volume * vol) / 100) * grid_weather_volume) / 100);
773 		else
774 		if (type == SFX_TYPE_AMBIENT)
775 			Mix_Volume(s, (CALC_MIX_VOLUME(cfg_audio_sound, (cfg_audio_sound_volume * vol) / 100) * grid_ambient_volume) / 100);
776 		else
777 		/* Note: Linear scaling is used here to allow more precise control at the server end */
778 			Mix_Volume(s, CALC_MIX_VOLUME(cfg_audio_sound, (cfg_audio_sound_volume * vol) / 100));
779 
780 //puts(format("playing sample %d at vol %d.\n", event, (cfg_audio_sound_volume * vol) / 100));
781 	}
782 	samples[event].current_channel = s;
783 	samples[event].started_timer_tick = ticks;
784 
785 	return TRUE;
786 }
787 /* play the 'bell' sound */
788 #define BELL_REDUCTION 3 /* reduce volume of bell() sounds by this factor */
sound_bell(void)789 extern bool sound_bell(void) {
790 	Mix_Chunk *wave = NULL;
791 	int s;
792 
793 	if (bell_sound_idx == -1) return FALSE;
794 	if (samples[bell_sound_idx].disabled) return TRUE; /* claim that it 'succeeded' */
795 	if (!samples[bell_sound_idx].num) return FALSE;
796 
797 	/* already playing? prevent multiple sounds of the same kind from being mixed simultaneously, for preventing silliness */
798 	if (samples[bell_sound_idx].current_channel != -1) return TRUE;
799 
800 	/* Choose a random event */
801 	s = rand_int(samples[bell_sound_idx].num);
802 	wave = samples[bell_sound_idx].wavs[s];
803 
804 	/* Try loading it, if it's not cached */
805 	if (!wave) {
806 		if (on_demand_loading || no_cache_audio) {
807 			if (!(wave = load_sample(bell_sound_idx, s))) {
808 				/* we really failed to load it */
809 				plog(format("SDL sound load failed (%d, %d).", bell_sound_idx, s));
810 				return FALSE;
811 			}
812 		} else {
813 			/* Fail silently */
814 			return TRUE;
815 		}
816 	}
817 
818 	/* Actually play the thing */
819 	/* remember, for efficiency management */
820 	s = Mix_PlayChannel(-1, wave, 0);
821 	if (s != -1) {
822 		channel_sample[s] = bell_sound_idx;
823 		channel_type[s] = SFX_TYPE_AMBIENT; /* whatever (just so overlapping is possible) */
824 		if (c_cfg.paging_max_volume) {
825 			Mix_Volume(s, MIX_MAX_VOLUME / BELL_REDUCTION);
826 		} else if (c_cfg.paging_master_volume) {
827 			Mix_Volume(s, CALC_MIX_VOLUME(1, 100 / BELL_REDUCTION));
828 		}
829 	}
830 	samples[bell_sound_idx].current_channel = s;
831 
832 	return TRUE;
833 }
834 /* play the 'page' sound */
sound_page(void)835 extern bool sound_page(void) {
836 	Mix_Chunk *wave = NULL;
837 	int s;
838 
839 	if (page_sound_idx == -1) return FALSE;
840 	if (samples[page_sound_idx].disabled) return TRUE; /* claim that it 'succeeded' */
841 	if (!samples[page_sound_idx].num) return FALSE;
842 
843 	/* already playing? prevent multiple sounds of the same kind from being mixed simultaneously, for preventing silliness */
844 	if (samples[page_sound_idx].current_channel != -1) return TRUE;
845 
846 	/* Choose a random event */
847 	s = rand_int(samples[page_sound_idx].num);
848 	wave = samples[page_sound_idx].wavs[s];
849 
850 	/* Try loading it, if it's not cached */
851 	if (!wave) {
852 		if (on_demand_loading || no_cache_audio) {
853 			if (!(wave = load_sample(page_sound_idx, s))) {
854 				/* we really failed to load it */
855 				plog(format("SDL sound load failed (%d, %d).", page_sound_idx, s));
856 				return FALSE;
857 			}
858 		} else {
859 			/* Fail silently */
860 			return TRUE;
861 		}
862 	}
863 
864 	/* Actually play the thing */
865 	/* remember, for efficiency management */
866 	s = Mix_PlayChannel(-1, wave, 0);
867 	if (s != -1) {
868 		channel_sample[s] = page_sound_idx;
869 		channel_type[s] = SFX_TYPE_AMBIENT; /* whatever (just so overlapping is possible) */
870 		if (c_cfg.paging_max_volume) {
871 			Mix_Volume(s, MIX_MAX_VOLUME);
872 		} else if (c_cfg.paging_master_volume) {
873 			Mix_Volume(s, CALC_MIX_VOLUME(1, 100));
874 		}
875 	}
876 	samples[page_sound_idx].current_channel = s;
877 
878 	return TRUE;
879 }
880 /* play the 'warning' sound */
sound_warning(void)881 extern bool sound_warning(void) {
882 	Mix_Chunk *wave = NULL;
883 	int s;
884 
885 	if (warning_sound_idx == -1) return FALSE;
886 	if (samples[warning_sound_idx].disabled) return TRUE; /* claim that it 'succeeded' */
887 	if (!samples[warning_sound_idx].num) return FALSE;
888 
889 	/* already playing? prevent multiple sounds of the same kind from being mixed simultaneously, for preventing silliness */
890 	if (samples[warning_sound_idx].current_channel != -1) return TRUE;
891 
892 	/* Choose a random event */
893 	s = rand_int(samples[warning_sound_idx].num);
894 	wave = samples[warning_sound_idx].wavs[s];
895 
896 	/* Try loading it, if it's not cached */
897 	if (!wave) {
898 		if (on_demand_loading || no_cache_audio) {
899 			if (!(wave = load_sample(warning_sound_idx, s))) {
900 				/* we really failed to load it */
901 				plog(format("SDL sound load failed (%d, %d).", warning_sound_idx, s));
902 				return FALSE;
903 			}
904 		} else {
905 			/* Fail silently */
906 			return TRUE;
907 		}
908 	}
909 
910 	/* Actually play the thing */
911 	/* remember, for efficiency management */
912 	s = Mix_PlayChannel(-1, wave, 0);
913 	if (s != -1) {
914 		channel_sample[s] = warning_sound_idx;
915 		channel_type[s] = SFX_TYPE_AMBIENT; /* whatever (just so overlapping is possible) */
916 		/* use 'page' sound volume settings for warning too */
917 		if (c_cfg.paging_max_volume) {
918 			Mix_Volume(s, MIX_MAX_VOLUME);
919 		} else if (c_cfg.paging_master_volume) {
920 			Mix_Volume(s, CALC_MIX_VOLUME(1, 100));
921 		}
922 	}
923 	samples[warning_sound_idx].current_channel = s;
924 
925 	return TRUE;
926 }
927 
928 
929 /* Release weather channel after fading out has been completed */
clear_channel(int c)930 static void clear_channel(int c) {
931 	/* weather has faded out, mark it as gone */
932 	if (c == weather_channel) {
933 		weather_channel = -1;
934 		return;
935 	}
936 
937 	if (c == ambient_channel) {
938 		ambient_channel = -1;
939 		return;
940 	}
941 
942 	/* a sample has finished playing, so allow this kind to be played again */
943 	/* hack: if the sample was the 'paging' sound, reset the channel's volume to be on the safe side */
944 	if (channel_sample[c] == page_sound_idx || channel_sample[c] == warning_sound_idx)
945 		Mix_Volume(c, CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume));
946 
947 	/* HACK - if the sample was a weather sample, which would be thunder, reset the vol too, paranoia */
948 	if (channel_type[c] == SFX_TYPE_WEATHER)
949 		Mix_Volume(c, CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume));
950 
951 	samples[channel_sample[c]].current_channel = -1;
952 	channel_sample[c] = -1;
953 }
954 
955 /* Overlay a weather noise -- not WEATHER_VOL_PARTICLES or WEATHER_VOL_CLOUDS */
play_sound_weather(int event)956 static void play_sound_weather(int event) {
957 	Mix_Chunk *wave = NULL;
958 	int s, new_wc;
959 
960 	/* allow halting a muted yet playing sound, before checking for DISABLE_MUTED_AUDIO */
961 	if (event == -2 && weather_channel != -1) {
962 #ifdef DEBUG_SOUND
963 		puts(format("w-2: wco %d, ev %d", weather_channel, event));
964 #endif
965 		Mix_HaltChannel(weather_channel);
966 		return;
967 	}
968 
969 	if (event == -1 && weather_channel != -1) {
970 #ifdef DEBUG_SOUND
971 		puts(format("w-1: wco %d, ev %d", weather_channel, event));
972 #endif
973 
974 		/* if channel is muted anyway, no need to fade out, just halt it instead.
975 		   HACK: The reason for this is actually to fix this bug:
976 		   There was a bug where ambient channel wasn't faded out if it was actually
977 		   muted at the same time, and so it'd continue being active when unmuted
978 		   again, instead of having been terminated by the fade-out.  */
979 		if (!cfg_audio_master || !cfg_audio_weather || !cfg_audio_weather_volume) {
980 			Mix_HaltChannel(weather_channel);
981 			return;
982 		}
983 
984 		if (Mix_FadingChannel(weather_channel) != MIX_FADING_OUT) {
985 			if (!weather_channel_volume) Mix_HaltChannel(weather_channel); else //hack: workaround SDL bug that doesn't terminate a sample playing at 0 volume after a FadeOut
986 			Mix_FadeOutChannel(weather_channel, 2000);
987 		}
988 		return;
989 	}
990 
991 #ifdef DISABLE_MUTED_AUDIO
992 	if (!cfg_audio_master || !cfg_audio_weather) return;
993 #endif
994 
995 	/* we're already in this weather? */
996 	if (weather_channel != -1 && weather_current == event &&
997 	    Mix_FadingChannel(weather_channel) != MIX_FADING_OUT)
998 		return;
999 
1000 	/* Paranoia */
1001 	if (event < 0 || event >= SOUND_MAX_2010) return;
1002 
1003 	if (samples[event].disabled) return;
1004 
1005 	/* Check there are samples for this event */
1006 	if (!samples[event].num) {
1007 		/* stop previous weather sound */
1008 #if 0 /* stop apruptly */
1009 		if (weather_channel != -1) Mix_HaltChannel(weather_channel);
1010 #else /* fade out */
1011 		if (weather_channel != -1 &&
1012 		    Mix_FadingChannel(weather_channel) != MIX_FADING_OUT) {
1013 			if (!weather_channel_volume) Mix_HaltChannel(weather_channel); else //hack: workaround SDL bug that doesn't terminate a sample playing at 0 volume after a FadeOut
1014 			Mix_FadeOutChannel(weather_channel, 2000);
1015 		}
1016 #endif
1017 		return;
1018 	}
1019 
1020 	/* Choose a random event */
1021 	s = rand_int(samples[event].num);
1022 	wave = samples[event].wavs[s];
1023 
1024 	/* Try loading it, if it's not cached */
1025 	if (!wave) {
1026 		if (on_demand_loading || no_cache_audio) {
1027 			if (!(wave = load_sample(event, s))) {
1028 				/* we really failed to load it */
1029 				plog(format("SDL sound load failed (%d, %d).", event, s));
1030 				return;
1031 			}
1032 		} else {
1033 			/* Fail silently */
1034 			return;
1035 		}
1036 	}
1037 
1038 	/* Actually play the thing */
1039 #if 1 /* volume glitch paranoia (first fade-in seems to move volume to 100% instead of designated cfg_audio_... */
1040 	new_wc = Mix_PlayChannel(weather_channel, wave, -1);
1041 	if (new_wc != -1) {
1042 		Mix_Volume(new_wc, (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100);
1043 
1044 		/* weird bug (see above) apparently STILL occurs for some people (Dj_wolf) - hack it moar: */
1045 		if (cfg_audio_weather)
1046 
1047 		if (!weather_resume) new_wc = Mix_FadeInChannel(new_wc, wave, -1, 500);
1048 	}
1049 #else
1050 	if (!weather_resume) new_wc = Mix_FadeInChannel(weather_channel, wave, -1, 500);
1051 #endif
1052 
1053 	if (!weather_resume) weather_fading = 1;
1054 	else weather_resume = FALSE;
1055 
1056 #ifdef DEBUG_SOUND
1057 	puts(format("old: %d, new: %d, ev: %d", weather_channel, new_wc, event));
1058 #endif
1059 
1060 #if 1
1061 	/* added this <if> after weather seemed to glitch sometimes,
1062 	   with its channel becoming unmutable */
1063 	//we didn't play weather so far?
1064 	if (weather_channel == -1) {
1065 		//failed to start playing?
1066 		if (new_wc == -1) return;
1067 
1068 		//successfully started playing the first weather
1069 		weather_channel = new_wc;
1070 		weather_current = event;
1071 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100);
1072 	} else {
1073 		//failed to start playing?
1074 		if (new_wc == -1) {
1075 			Mix_HaltChannel(weather_channel);
1076 			return;
1077 		//successfully started playing a follow-up weather
1078 		} else {
1079 			//same channel?
1080 			if (new_wc == weather_channel) {
1081 				weather_current = event;
1082 			//different channel?
1083 			} else {
1084 				Mix_HaltChannel(weather_channel);
1085 				weather_channel = new_wc;
1086 				weather_current = event;
1087 				Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100);
1088 			}
1089 		}
1090 	}
1091 #endif
1092 #if 0
1093 	/* added this <if> after weather seemed to glitch sometimes,
1094 	   with its channel becoming unmutable */
1095 	if (new_wc != weather_channel) {
1096 		if (weather_channel != -1) Mix_HaltChannel(weather_channel);
1097 		weather_channel = new_wc;
1098 	}
1099 	if (weather_channel != -1) { //paranoia? should always be != -1 at this point
1100 		weather_current = event;
1101 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100);
1102 	}
1103 #endif
1104 
1105 #ifdef DEBUG_SOUND
1106 	puts(format("now: %d, oev: %d, ev: %d", weather_channel, event, weather_current));
1107 #endif
1108 }
1109 
1110 
1111 /* Overlay a weather noise, with a certain volume -- WEATHER_VOL_PARTICLES */
play_sound_weather_vol(int event,int vol)1112 static void play_sound_weather_vol(int event, int vol) {
1113 	Mix_Chunk *wave = NULL;
1114 	int s, new_wc;
1115 
1116 	/* allow halting a muted yet playing sound, before checking for DISABLE_MUTED_AUDIO */
1117 	if (event == -2 && weather_channel != -1) {
1118 #ifdef DEBUG_SOUND
1119 		puts(format("w-2: wco %d, ev %d", weather_channel, event));
1120 #endif
1121 		Mix_HaltChannel(weather_channel);
1122 		return;
1123 	}
1124 
1125 	if (event == -1 && weather_channel != -1) {
1126 #ifdef DEBUG_SOUND
1127 		puts(format("w-1: wco %d, ev %d", weather_channel, event));
1128 #endif
1129 
1130 		/* if channel is muted anyway, no need to fade out, just halt it instead.
1131 		   HACK: The reason for this is actually to fix this bug:
1132 		   There was a bug where ambient channel wasn't faded out if it was actually
1133 		   muted at the same time, and so it'd continue being active when unmuted
1134 		   again, instead of having been terminated by the fade-out.  */
1135 		if (!cfg_audio_master || !cfg_audio_weather || !cfg_audio_weather_volume) {
1136 			Mix_HaltChannel(weather_channel);
1137 			return;
1138 		}
1139 
1140 		if (Mix_FadingChannel(weather_channel) != MIX_FADING_OUT) {
1141 			if (!weather_channel_volume) Mix_HaltChannel(weather_channel); else //hack: workaround SDL bug that doesn't terminate a sample playing at 0 volume after a FadeOut
1142 			Mix_FadeOutChannel(weather_channel, 2000);
1143 		}
1144 		return;
1145 	}
1146 
1147 #ifdef DISABLE_MUTED_AUDIO
1148 	if (!cfg_audio_master || !cfg_audio_weather) return;
1149 #endif
1150 
1151 	/* we're already in this weather? */
1152 	if (weather_channel != -1 && weather_current == event &&
1153 	    Mix_FadingChannel(weather_channel) != MIX_FADING_OUT) {
1154 		int v = (cfg_audio_weather_volume * vol) / 100, n, va = 0;
1155 
1156 		/* shift array and calculate average over the last n volume values */
1157 		for (n = 20 - 1; n > 0; n--) {
1158 			va += weather_smooth_avg[n];
1159 			/* and shift array to make room for new value */
1160 			weather_smooth_avg[n] = weather_smooth_avg[n - 1];
1161 		}
1162 		va += weather_smooth_avg[0];//add the last element
1163 		va /= 20;//calculate average
1164 		/* queue new value */
1165 		weather_smooth_avg[0] = v;
1166 
1167 		/* change volume though? */
1168 //c_message_add(format("vol %d, v %d", vol, v));
1169 		if (weather_vol_smooth < va - 20) {
1170 			weather_vol_smooth_anti_oscill = va;
1171 //c_message_add(format("smooth++ %d (vol %d)", weather_vol_smooth, vol));
1172 		}
1173 		else if (weather_vol_smooth > va + 20) {
1174 			weather_vol_smooth_anti_oscill = va;
1175 //c_message_add(format("smooth-- %d (vol %d)", weather_vol_smooth, vol));
1176 		}
1177 
1178 		if (weather_vol_smooth < weather_vol_smooth_anti_oscill)
1179 			weather_vol_smooth++;
1180 		else if (weather_vol_smooth > weather_vol_smooth_anti_oscill)
1181 				weather_vol_smooth--;
1182 
1183 //c_message_add(format("smooth %d", weather_vol_smooth));
1184 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, weather_vol_smooth) * grid_weather_volume) / 100);
1185 
1186 		/* Done */
1187 		return;
1188 	}
1189 
1190 	/* Paranoia */
1191 	if (event < 0 || event >= SOUND_MAX_2010) return;
1192 
1193 	if (samples[event].disabled) return;
1194 
1195 	/* Check there are samples for this event */
1196 	if (!samples[event].num) return;
1197 
1198 	/* Choose a random event */
1199 	s = rand_int(samples[event].num);
1200 	wave = samples[event].wavs[s];
1201 
1202 	/* Try loading it, if it's not cached */
1203 	if (!wave) {
1204 		if (on_demand_loading || no_cache_audio) {
1205 			if (!(wave = load_sample(event, s))) {
1206 				/* we really failed to load it */
1207 				plog(format("SDL sound load failed (%d, %d).", event, s));
1208 				return;
1209 			}
1210 		} else {
1211 			/* Fail silently */
1212 			return;
1213 		}
1214 	}
1215 
1216 	/* Actually play the thing */
1217 #if 1 /* volume glitch paranoia (first fade-in seems to move volume to 100% instead of designated cfg_audio_... */
1218 	new_wc = Mix_PlayChannel(weather_channel, wave, -1);
1219 	if (new_wc != -1) {
1220 		weather_vol_smooth = (cfg_audio_weather_volume * vol) / 100; /* set initially, instantly */
1221 		Mix_Volume(new_wc, (CALC_MIX_VOLUME(cfg_audio_weather, weather_vol_smooth) * grid_weather_volume) / 100);
1222 
1223 		/* weird bug (see above) apparently might STILL occur for some people - hack it moar: */
1224 		if (cfg_audio_weather)
1225 
1226 		if (!weather_resume) new_wc = Mix_FadeInChannel(new_wc, wave, -1, 500);
1227 	}
1228 #else
1229 	if (!weather_resume) new_wc = Mix_FadeInChannel(weather_channel, wave, -1, 500);
1230 #endif
1231 
1232 	if (!weather_resume) weather_fading = 1;
1233 	else weather_resume = FALSE;
1234 
1235 #ifdef DEBUG_SOUND
1236 	puts(format("old: %d, new: %d, ev: %d", weather_channel, new_wc, event));
1237 #endif
1238 
1239 #if 1
1240 	/* added this <if> after weather seemed to glitch sometimes,
1241 	   with its channel becoming unmutable */
1242 	//we didn't play weather so far?
1243 	if (weather_channel == -1) {
1244 		//failed to start playing?
1245 		if (new_wc == -1) return;
1246 
1247 		//successfully started playing the first weather
1248 		weather_channel = new_wc;
1249 		weather_current = event;
1250 
1251 		weather_vol_smooth = (cfg_audio_weather_volume * vol) / 100; /* set initially, instantly */
1252 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, weather_vol_smooth) * grid_weather_volume) / 100);
1253 	} else {
1254 		//failed to start playing?
1255 		if (new_wc == -1) {
1256 			Mix_HaltChannel(weather_channel);
1257 			return;
1258 		//successfully started playing a follow-up weather
1259 		} else {
1260 			//same channel?
1261 			if (new_wc == weather_channel) {
1262 				weather_current = event;
1263 			//different channel?
1264 			} else {
1265 				Mix_HaltChannel(weather_channel);
1266 				weather_channel = new_wc;
1267 				weather_current = event;
1268 				weather_vol_smooth = (cfg_audio_weather_volume * vol) / 100; /* set initially, instantly */
1269 				Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, weather_vol_smooth) * grid_weather_volume) / 100);
1270 			}
1271 		}
1272 	}
1273 #endif
1274 #if 0
1275 	/* added this <if> after weather seemed to glitch sometimes,
1276 	   with its channel becoming unmutable */
1277 	if (new_wc != weather_channel) {
1278 		if (weather_channel != -1) Mix_HaltChannel(weather_channel);
1279 		weather_channel = new_wc;
1280 	}
1281 	if (weather_channel != -1) { //paranoia? should always be != -1 at this point
1282 		weather_current = event;
1283 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, (cfg_audio_weather_volume * vol) / 100) * grid_weather_volume) / 100);
1284 	}
1285 #endif
1286 
1287 #ifdef DEBUG_SOUND
1288 	puts(format("now: %d, oev: %d, ev: %d", weather_channel, event, weather_current));
1289 #endif
1290 }
1291 
1292 /* make sure volume is set correct after fading-in has been completed (might be just paranoia) */
weather_handle_fading(void)1293 void weather_handle_fading(void) {
1294 	if (weather_channel == -1) { //paranoia
1295 		weather_fading = 0;
1296 		return;
1297 	}
1298 
1299 	if (Mix_FadingChannel(weather_channel) == MIX_NO_FADING) {
1300 #ifndef WEATHER_VOL_PARTICLES
1301 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100);
1302 #else
1303 		Mix_Volume(weather_channel, (CALC_MIX_VOLUME(cfg_audio_weather, weather_vol_smooth) * grid_weather_volume) / 100);
1304 #endif
1305 		weather_fading = 0;
1306 		return;
1307 	}
1308 }
1309 
1310 /* Overlay an ambient sound effect */
play_sound_ambient(int event)1311 static void play_sound_ambient(int event) {
1312 	Mix_Chunk *wave = NULL;
1313 	int s, new_ac;
1314 
1315 #ifdef DEBUG_SOUND
1316 	puts(format("psa: ch %d, ev %d", ambient_channel, event));
1317 #endif
1318 
1319 	/* allow halting a muted yet playing sound, before checking for DISABLE_MUTED_AUDIO */
1320 	if (event == -2 && ambient_channel != -1) {
1321 #ifdef DEBUG_SOUND
1322 		puts(format("w-2: wco %d, ev %d", ambient_channel, event));
1323 #endif
1324 		Mix_HaltChannel(ambient_channel);
1325 		return;
1326 	}
1327 
1328 	if (event == -1 && ambient_channel != -1) {
1329 #ifdef DEBUG_SOUND
1330 		puts(format("w-1: wco %d, ev %d", ambient_channel, event));
1331 #endif
1332 
1333 		/* if channel is muted anyway, no need to fade out, just halt it instead.
1334 		   HACK: The reason for this is actually to fix this bug:
1335 		   There was a bug where ambient channel wasn't faded out if it was actually
1336 		   muted at the same time, and so it'd continue being active when unmuted
1337 		   again, instead of having been terminated by the fade-out.  */
1338 		if (!cfg_audio_master || !cfg_audio_sound || !cfg_audio_sound_volume) {
1339 			Mix_HaltChannel(ambient_channel);
1340 			return;
1341 		}
1342 
1343 		if (Mix_FadingChannel(ambient_channel) != MIX_FADING_OUT) {
1344 			if (!ambient_channel_volume) Mix_HaltChannel(ambient_channel); else //hack: workaround SDL bug that doesn't terminate a sample playing at 0 volume after a FadeOut
1345 			Mix_FadeOutChannel(ambient_channel, 2000);
1346 		}
1347 		return;
1348 	}
1349 
1350 #ifdef DISABLE_MUTED_AUDIO
1351 	if (!cfg_audio_master || !cfg_audio_sound) return;
1352 #endif
1353 
1354 	/* we're already in this ambient? */
1355 	if (ambient_channel != -1 && ambient_current == event &&
1356 	    Mix_FadingChannel(ambient_channel) != MIX_FADING_OUT)
1357 		return;
1358 
1359 	/* Paranoia */
1360 	if (event < 0 || event >= SOUND_MAX_2010) return;
1361 
1362 	if (samples[event].disabled) return;
1363 
1364 	/* Check there are samples for this event */
1365 	if (!samples[event].num) {
1366 		/* stop previous ambient sound */
1367 #if 0 /* stop apruptly */
1368 		if (ambient_channel != -1) Mix_HaltChannel(ambient_channel);
1369 #else /* fade out */
1370 		if (ambient_channel != -1 &&
1371 		    Mix_FadingChannel(ambient_channel) != MIX_FADING_OUT) {
1372 			if (!ambient_channel_volume) Mix_HaltChannel(ambient_channel); else //hack: workaround SDL bug that doesn't terminate a sample playing at 0 volume after a FadeOut
1373 			Mix_FadeOutChannel(ambient_channel, 2000);
1374 		}
1375 #endif
1376 		return;
1377 	}
1378 
1379 	/* Choose a random event */
1380 	s = rand_int(samples[event].num);
1381 	wave = samples[event].wavs[s];
1382 
1383 	/* Try loading it, if it's not cached */
1384 	if (!wave) {
1385 #if 0 /* for ambient sounds. we don't drop them as we'd do for "normal " sfx, \
1386 	 because they ought to be looped, so we'd completely lose them. - C. Blue */
1387 		if (on_demand_loading || no_cache_audio) {
1388 #endif
1389 			if (!(wave = load_sample(event, s))) {
1390 				/* we really failed to load it */
1391 				plog(format("SDL sound load failed (%d, %d).", event, s));
1392 				return;
1393 			}
1394 #if 0 /* see above */
1395 		} else {
1396 #ifdef DEBUG_SOUND
1397 			puts(format("on_demand_loading %d, no_cache_audio %d", on_demand_loading, no_cache_audio));
1398 #endif
1399 			/* Fail silently */
1400 			return;
1401 		}
1402 #endif
1403 	}
1404 
1405 	/* Actually play the thing */
1406 #if 1 /* volume glitch paranoia (first fade-in seems to move volume to 100% instead of designated cfg_audio_... */
1407 	new_ac = Mix_PlayChannel(ambient_channel, wave, -1);
1408 	if (new_ac != -1) {
1409 		Mix_Volume(new_ac, (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100);
1410 
1411 		/* weird bug (see above) apparently might STILL occur for some people - hack it moar: */
1412 		if (cfg_audio_sound)
1413 
1414 		if (!ambient_resume) new_ac = Mix_FadeInChannel(new_ac, wave, -1, 500);
1415 	}
1416 #else
1417 	if (!ambient_resume) new_ac = Mix_FadeInChannel(ambient_channel, wave, -1, 500);
1418 #endif
1419 
1420 	if (!ambient_resume) ambient_fading = 1;
1421 	else ambient_resume = FALSE;
1422 
1423 #ifdef DEBUG_SOUND
1424 	puts(format("old: %d, new: %d, ev: %d", ambient_channel, new_ac, event));
1425 #endif
1426 
1427 #if 1
1428 	/* added this <if> after ambient seemed to glitch sometimes,
1429 	   with its channel becoming unmutable */
1430 	//we didn't play ambient so far?
1431 	if (ambient_channel == -1) {
1432 		//failed to start playing?
1433 		if (new_ac == -1) return;
1434 
1435 		//successfully started playing the first ambient
1436 		ambient_channel = new_ac;
1437 		ambient_current = event;
1438 		Mix_Volume(ambient_channel, (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100);
1439 	} else {
1440 		//failed to start playing?
1441 		if (new_ac == -1) {
1442 			Mix_HaltChannel(ambient_channel);
1443 			return;
1444 		//successfully started playing a follow-up ambient
1445 		} else {
1446 			//same channel?
1447 			if (new_ac == ambient_channel) {
1448 				ambient_current = event;
1449 			//different channel?
1450 			} else {
1451 				Mix_HaltChannel(ambient_channel);
1452 				ambient_channel = new_ac;
1453 				ambient_current = event;
1454 				Mix_Volume(ambient_channel, (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100);
1455 			}
1456 		}
1457 
1458 	}
1459 #endif
1460 #if 0
1461 	/* added this <if> after ambient seemed to glitch sometimes,
1462 	   with its channel becoming unmutable */
1463 	if (new_ac != ambient_channel) {
1464 		if (ambient_channel != -1) Mix_HaltChannel(ambient_channel);
1465 		ambient_channel = new_ac;
1466 	}
1467 	if (ambient_channel != -1) { //paranoia? should always be != -1 at this point
1468 		ambient_current = event;
1469 		Mix_Volume(ambient_channel, (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100);
1470 	}
1471 #endif
1472 
1473 #ifdef DEBUG_SOUND
1474 	puts(format("now: %d, oev: %d, ev: %d", ambient_channel, event, ambient_current));
1475 #endif
1476 }
1477 
1478 /* make sure volume is set correct after fading-in has been completed (might be just paranoia) */
ambient_handle_fading(void)1479 void ambient_handle_fading(void) {
1480 	if (ambient_channel == -1) { //paranoia
1481 		ambient_fading = 0;
1482 		return;
1483 	}
1484 
1485 	if (Mix_FadingChannel(ambient_channel) == MIX_NO_FADING) {
1486 		Mix_Volume(ambient_channel, (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100);
1487 		ambient_fading = 0;
1488 		return;
1489 	}
1490 }
1491 
1492 
1493 /*
1494  * Play a music of type "event".
1495  */
play_music(int event)1496 static bool play_music(int event) {
1497 	/* Paranoia */
1498 	if (event < 0 || event >= MUSIC_MAX) return FALSE;
1499 
1500 	if (songs[event].disabled) {
1501 		/* Stop currently playing music though, before returning */
1502 		if (Mix_PlayingMusic() && Mix_FadingMusic() != MIX_FADING_OUT)
1503 			Mix_FadeOutMusic(500);
1504 
1505 		return TRUE; /* claim that it 'succeeded' */
1506 	}
1507 
1508 	/* Check there are samples for this event */
1509 	if (!songs[event].num) {
1510 		/* Stop currently playing music though, before returning */
1511 		if (Mix_PlayingMusic() && Mix_FadingMusic() != MIX_FADING_OUT)
1512 			Mix_FadeOutMusic(500);
1513 
1514 		return FALSE;
1515 	}
1516 
1517 
1518 	music_next = event;
1519 
1520 	/* check if music is already running, if so, fade it out first! */
1521 	if (Mix_PlayingMusic()) {
1522 		if (Mix_FadingMusic() != MIX_FADING_OUT)
1523 			Mix_FadeOutMusic(500);
1524 	} else {
1525 		//play immediately
1526 		fadein_next_music();
1527 	}
1528 	return TRUE;
1529 }
1530 
fadein_next_music(void)1531 static void fadein_next_music(void) {
1532 	Mix_Music *wave = NULL;
1533 	int s;
1534 
1535 #ifdef DISABLE_MUTED_AUDIO
1536 	if (!cfg_audio_master || !cfg_audio_music) return;
1537 #endif
1538 
1539 	/* Paranoia */
1540 	if (music_next < 0 || music_next >= MUSIC_MAX) return;
1541 
1542 	if (songs[music_next].disabled) return;
1543 
1544 	/* Check there are samples for this event */
1545 	if (!songs[music_next].num) return;
1546 
1547 	/* Choose a random event */
1548 	s = rand_int(songs[music_next].num);
1549 	wave = songs[music_next].wavs[s];
1550 
1551 	/* Try loading it, if it's not cached */
1552 	if (!wave && !(wave = load_song(music_next, s))) {
1553 		/* we really failed to load it */
1554 		plog(format("SDL music load failed (%d, %d).", music_next, s));
1555 		puts(format("SDL music load failed (%d, %d).", music_next, s));
1556 		return;
1557 	}
1558 
1559 	/* Actually play the thing */
1560 #ifdef DISABLE_MUTED_AUDIO
1561 	music_cur = music_next;
1562 	music_cur_song = s;
1563 #endif
1564 	music_next = -1;
1565 //	Mix_PlayMusic(wave, -1);//-1 infinite, 0 once, or n times
1566 	Mix_FadeInMusic(wave, -1, 1000);
1567 }
1568 
1569 #ifdef DISABLE_MUTED_AUDIO
1570 /* start playing current music again if we reenabled it in the mixer UI after having had it disabled */
reenable_music(void)1571 static void reenable_music(void) {
1572 	Mix_Music *wave = NULL;
1573 
1574 	/* music has changed meanwhile, just play the new one the normal way */
1575 	if (music_next != -1 && music_next != music_cur) {
1576 		fadein_next_music();
1577 		return;
1578 	}
1579 
1580 	/* music initialization not yet completed? (at the start of the game) */
1581 	if (music_cur == -1 || music_cur_song == -1) return;
1582 
1583 	wave = songs[music_cur].wavs[music_cur_song];
1584 
1585 	/* If audio is still being loaded/cached, we might just have to exit here for now */
1586 	if (!wave) return;
1587 
1588 	/* Take up playing again immediately, no fading in */
1589 	Mix_PlayMusic(wave, -1);
1590 }
1591 #endif
1592 
1593 /*
1594  * Set mixing levels in the SDL module.
1595  */
set_mixing_sdl(void)1596 static void set_mixing_sdl(void) {
1597 //	puts(format("mixer set to %d, %d, %d.", cfg_audio_music_volume, cfg_audio_sound_volume, cfg_audio_weather_volume));
1598 #if 0 /* don't use relative sound-effect specific volumes, transmitted from the server? */
1599 	Mix_Volume(-1, CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume));
1600 #else /* use relative volumes (4.4.5b+) */
1601 	int n;
1602 	for (n = 0; n < cfg_max_channels; n++) {
1603 		if (n == weather_channel) continue;
1604 		if (n == ambient_channel) continue;
1605 
1606 		/* HACK - use weather volume for thunder sfx */
1607 		if (channel_sample[n] != -1 && channel_type[n] == SFX_TYPE_WEATHER)
1608 			Mix_Volume(n, (CALC_MIX_VOLUME(cfg_audio_weather, (cfg_audio_weather_volume * channel_volume[n]) / 100) * grid_weather_volume) / 100);
1609 		else
1610 		/* grid_ambient_volume influences non-looped ambient sfx clips */
1611 		if (channel_sample[n] != -1 && channel_type[n] == SFX_TYPE_AMBIENT)
1612 			Mix_Volume(n, (CALC_MIX_VOLUME(cfg_audio_sound, (cfg_audio_sound_volume * channel_volume[n]) / 100) * grid_ambient_volume) / 100);
1613 		else
1614 		/* Note: Linear scaling is used here to allow more precise control at the server end */
1615 			Mix_Volume(n, CALC_MIX_VOLUME(cfg_audio_sound, (cfg_audio_sound_volume * channel_volume[n]) / 100));
1616 
1617  #ifdef DISABLE_MUTED_AUDIO
1618 		if ((!cfg_audio_master || !cfg_audio_sound) && Mix_Playing(n))
1619 			Mix_HaltChannel(n);
1620  #endif
1621 	}
1622 #endif
1623 	Mix_VolumeMusic(CALC_MIX_VOLUME(cfg_audio_music, cfg_audio_music_volume));
1624 #ifdef DISABLE_MUTED_AUDIO
1625 	if (!cfg_audio_master || !cfg_audio_music) {
1626 		if (Mix_PlayingMusic()) Mix_HaltMusic();
1627 	} else if (!Mix_PlayingMusic()) reenable_music();
1628 #endif
1629 
1630 	if (weather_channel != -1 && Mix_FadingChannel(weather_channel) != MIX_FADING_OUT) {
1631 #ifndef WEATHER_VOL_PARTICLES
1632 		weather_channel_volume = (CALC_MIX_VOLUME(cfg_audio_weather, cfg_audio_weather_volume) * grid_weather_volume) / 100;
1633 		Mix_Volume(weather_channel, weather_channel_volume);
1634 #else
1635 		Mix_Volume(weather_channel, weather_channel_volume);
1636 #endif
1637 	}
1638 
1639 	if (ambient_channel != -1 && Mix_FadingChannel(ambient_channel) != MIX_FADING_OUT) {
1640 		ambient_channel_volume = (CALC_MIX_VOLUME(cfg_audio_sound, cfg_audio_sound_volume) * grid_ambient_volume) / 100;
1641 		Mix_Volume(ambient_channel, ambient_channel_volume);
1642 	}
1643 
1644 #ifdef DISABLE_MUTED_AUDIO
1645 	if (!cfg_audio_master || !cfg_audio_weather) {
1646 		weather_resume = TRUE;
1647 		if (weather_channel != -1 && Mix_Playing(weather_channel))
1648 			Mix_HaltChannel(weather_channel);
1649 
1650 		/* HACK - use weather volume for thunder sfx */
1651 		for (n = 0; n < cfg_max_channels; n++)
1652 			if (channel_type[n] == SFX_TYPE_WEATHER)
1653 				Mix_HaltChannel(n);
1654 	}
1655 
1656 	if (!cfg_audio_master || !cfg_audio_sound) {
1657 		ambient_resume = TRUE;
1658 		if (ambient_channel != -1 && Mix_Playing(ambient_channel))
1659 			Mix_HaltChannel(ambient_channel);
1660 	}
1661 #endif
1662 }
1663 
1664 /*
1665  * Init the SDL sound "module".
1666  */
init_sound_sdl(int argc,char ** argv)1667 errr init_sound_sdl(int argc, char **argv) {
1668 	int i;
1669 
1670 	/* Parse args */
1671 	for (i = 1; i < argc; i++) {
1672 		if (prefix(argv[i], "-a")) {
1673 			no_cache_audio = TRUE;
1674 			plog("Audio cache disabled.");
1675 			continue;
1676 		}
1677 	}
1678 
1679 #ifdef DEBUG_SOUND
1680 	puts(format("init_sound_sdl() init%s", no_cache_audio == FALSE ? " (cached)" : " (not cached)"));
1681 #endif
1682 
1683 	/* Load sound preferences if requested */
1684 #if 0
1685 	if (!sound_sdl_init(no_cache_audio)) {
1686 #else /* never cache audio right at program start, because it creates an annoying delay! */
1687 	if (!sound_sdl_init(TRUE)) {
1688 #endif
1689 		plog("Failed to initialise audio.");
1690 
1691 		/* Failure */
1692 		return (1);
1693 	}
1694 
1695 	/* Set the mixing hook */
1696 	mixing_hook = set_mixing_sdl;
1697 
1698 	/* Enable sound */
1699 	sound_hook = play_sound;
1700 
1701 	/* Enable music */
1702 	music_hook = play_music;
1703 
1704 	/* Enable weather noise overlay */
1705 	sound_weather_hook = play_sound_weather;
1706 	sound_weather_hook_vol = play_sound_weather_vol;
1707 
1708 	/* Enable ambient sfx overlay */
1709 	sound_ambient_hook = play_sound_ambient;
1710 
1711 	/* clean-up hook */
1712 	atexit(close_audio);
1713 
1714 	/* start caching audio in a separate thread to eliminate startup loading time */
1715 	if (!no_cache_audio) {
1716 #ifdef DEBUG_SOUND
1717 		puts("Audio cache: Creating thread..");
1718 #endif
1719 		load_audio_thread = SDL_CreateThread(thread_load_audio, NULL);
1720 		if (load_audio_thread == NULL) {
1721 #ifdef DEBUG_SOUND
1722 			puts("Audio cache: Thread creation failed.");
1723 #endif
1724 			plog(format("Audio cache: Unable to create thread: %s\n", SDL_GetError()));
1725 
1726 			/* load manually instead, with annoying delay ;-p */
1727 			thread_load_audio(NULL);
1728 		}
1729 #ifdef DEBUG_SOUND
1730 		else puts("Audio cache: Thread creation succeeded.");
1731 #endif
1732 	}
1733 
1734 #ifdef DEBUG_SOUND
1735 	puts("init_sound_sdl() completed.");
1736 #endif
1737 
1738 	/* Success */
1739 	return (0);
1740 }
1741 
1742 /* on game termination */
1743 void mixer_fadeall(void) {
1744 	Mix_FadeOutMusic(1500);
1745 	Mix_FadeOutChannel(-1, 1500);
1746 }
1747 
1748 //extra code I moved here for USE_SOUND_2010, for porting
1749 //this stuff from angband into here. it's part of angband's z-files.c..- C. Blue
1750 
1751 //z-files.c:
1752 static bool my_fexists(const char *fname) {
1753 	FILE *fd;
1754 	/* Try to open it */
1755 	fd = fopen(fname, "rb");
1756 	/* It worked */
1757 	if (fd != NULL) {
1758 		fclose(fd);
1759 		return TRUE;
1760 	} else return FALSE;
1761 }
1762 
1763 /* if audioCached is TRUE, load those audio files in a separate
1764    thread, to avoid startup delay of client - C. Blue */
1765 static int thread_load_audio(void *dummy) {
1766 	int idx, subidx;
1767 
1768 	/* process all sound fx */
1769 	for (idx = 0; idx < SOUND_MAX_2010; idx++) {
1770 		/* process all files for each sound event */
1771 		for (subidx = 0; subidx < samples[idx].num; subidx++) {
1772 			load_sample(idx, subidx);
1773 		}
1774 	}
1775 
1776 	/* process all music */
1777 	for (idx = 0; idx < MUSIC_MAX; idx++) {
1778 		/* process all files for each sound event */
1779 		for (subidx = 0; subidx < songs[idx].num; subidx++) {
1780 			load_song(idx, subidx);
1781 		}
1782 	}
1783 
1784 	return(0);
1785 }
1786 
1787 /* thread-safe loading of audio files - C. Blue */
1788 static Mix_Chunk* load_sample(int idx, int subidx) {
1789 	const char *filename = samples[idx].paths[subidx];
1790 	Mix_Chunk *wave = NULL;
1791 
1792 	SDL_LockMutex(load_sample_mutex_entrance);
1793 
1794 	SDL_LockMutex(load_sample_mutex);
1795 
1796 	SDL_UnlockMutex(load_sample_mutex_entrance);
1797 
1798 	/* paranoia: check if it's already loaded (but how could it..) */
1799 	if (samples[idx].wavs[subidx]) {
1800 #ifdef DEBUG_SOUND
1801 		puts(format("sample already loaded %d, %d: %s.", idx, subidx, filename));
1802 #endif
1803 		SDL_UnlockMutex(load_sample_mutex);
1804 		return (samples[idx].wavs[subidx]);
1805 	}
1806 
1807 	/* Try loading it, if it's not yet cached */
1808 
1809 	/* Verify it exists */
1810 	if (!my_fexists(filename)) {
1811 #ifdef DEBUG_SOUND
1812 		puts(format("file doesn't exist %d, %d: %s.", idx, subidx, filename));
1813 #endif
1814 		SDL_UnlockMutex(load_sample_mutex);
1815 		return (NULL);
1816 	}
1817 
1818 	/* Load */
1819 	wave = Mix_LoadWAV(filename);
1820 
1821 	/* Did we get it now? */
1822 	if (wave) {
1823 		samples[idx].wavs[subidx] = wave;
1824 #ifdef DEBUG_SOUND
1825 		puts(format("loaded sample %d, %d: %s.", idx, subidx, filename));
1826 #endif
1827 	} else {
1828 #ifdef DEBUG_SOUND
1829 		puts(format("failed to load sample %d, %d: %s.", idx, subidx, filename));
1830 #endif
1831 		SDL_UnlockMutex(load_sample_mutex);
1832 		return (NULL);
1833 	}
1834 
1835 	SDL_UnlockMutex(load_sample_mutex);
1836 	return (wave);
1837 }
1838 static Mix_Music* load_song(int idx, int subidx) {
1839 	const char *filename = songs[idx].paths[subidx];
1840 	Mix_Music *waveMUS = NULL;
1841 
1842 	SDL_LockMutex(load_song_mutex_entrance);
1843 
1844 	SDL_LockMutex(load_song_mutex);
1845 
1846 	SDL_UnlockMutex(load_song_mutex_entrance);
1847 
1848 	/* check if it's already loaded */
1849 	if (songs[idx].wavs[subidx]) {
1850 #ifdef DEBUG_SOUND
1851 		puts(format("song already loaded %d, %d: %s.", idx, subidx, filename));
1852 #endif
1853 		SDL_UnlockMutex(load_song_mutex);
1854 		return (songs[idx].wavs[subidx]);
1855 	}
1856 
1857 	/* Try loading it, if it's not yet cached */
1858 
1859 	/* Verify it exists */
1860 	if (!my_fexists(filename)) {
1861 #ifdef DEBUG_SOUND
1862 		puts(format("file doesn't exist %d, %d: %s.", idx, subidx, filename));
1863 #endif
1864 		SDL_UnlockMutex(load_song_mutex);
1865 		return (NULL);
1866 	}
1867 
1868 	/* Load */
1869 	waveMUS = Mix_LoadMUS(filename);
1870 
1871 	/* Did we get it now? */
1872 	if (waveMUS) {
1873 		songs[idx].wavs[subidx] = waveMUS;
1874 #ifdef DEBUG_SOUND
1875 		puts(format("loaded song %d, %d: %s.", idx, subidx, filename));
1876 #endif
1877 	} else {
1878 #ifdef DEBUG_SOUND
1879 		puts(format("failed to load song %d, %d: %s.", idx, subidx, filename));
1880 #endif
1881 		SDL_UnlockMutex(load_song_mutex);
1882 		return (NULL);
1883 	}
1884 
1885 	SDL_UnlockMutex(load_song_mutex);
1886 	return (waveMUS);
1887 }
1888 
1889 /* Display options page UI that allows to comment out sounds easily */
1890 void do_cmd_options_sfx_sdl(void) {
1891 	int i, i2, j, d, vertikal_offset = 3, horiz_offset = 5;
1892 	int y = 0;
1893 	char ch;
1894 	byte a, a2;
1895 	cptr lua_name;
1896 	bool go = TRUE;
1897 	char buf[1024], buf2[1024], out_val[2048], out_val2[2048], *p, evname[2048];
1898 	FILE *fff, *fff2;
1899 
1900 	//ANGBAND_DIR_XTRA_SOUND/MUSIC are NULL in quiet_mode!
1901 	if (quiet_mode) {
1902 		c_msg_print("Client is running in quiet mode, sounds are not available.");
1903 		return;
1904 	}
1905 
1906 	/* Build the filename */
1907 	path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
1908 
1909 	/* Check if the file exists */
1910 	fff = my_fopen(buf, "r");
1911 	if (!fff) {
1912 		c_msg_print("Error: File 'sound.cfg' not found.");
1913 		return;
1914 	}
1915 	fclose(fff);
1916 
1917 	/* Clear screen */
1918 	Term_clear();
1919 
1920 	/* Interact */
1921 	while (go) {
1922 		Term_putstr(0, 0, -1, TERM_WHITE, "  (<\377ydir\377w/\377y#\377w>, \377yt\377w (toggle), \377yy\377w/\377yn\377w (enable/disable), \377yESC\377w)");
1923 		Term_putstr(0, 1, -1, TERM_WHITE, "  (\377wAll changes made here will auto-save as soon as you leave this page)");
1924 
1925 		/* Display the events */
1926 		for (i = y - 10 ; i <= y + 10 ; i++) {
1927 			if (i < 0 || i >= audio_sfx) {
1928 				Term_putstr(horiz_offset + 7, vertikal_offset + i + 10 - y, -1, TERM_WHITE, "                                        ");
1929 				continue;
1930 			}
1931 
1932 			/* Map events we've listed in our local config file onto audio.lua indices */
1933 			i2 = -1;
1934 			for (j = 0; j < SOUND_MAX_2010; j++) {
1935 				if (!samples[j].config) continue;
1936 				i2++;
1937 				if (i2 == i) break;
1938 			}
1939 			if (j != SOUND_MAX_2010) { //paranoia, should always be false
1940 				/* get event name */
1941 				sprintf(out_val, "return get_sound_name(%d)", j);
1942 				lua_name = string_exec_lua(0, out_val);
1943 			} else lua_name = "<nothing>";
1944 
1945 			/* set colour depending on enabled/disabled state */
1946 			//todo - c_cfg.use_color D: yadayada
1947 			if (samples[i].disabled) {
1948 				a = TERM_L_DARK;
1949 				a2 = TERM_UMBER;
1950 			} else {
1951 				a = TERM_WHITE;
1952 				a2 = TERM_YELLOW;
1953 			}
1954 
1955 			Term_putstr(horiz_offset + 7, vertikal_offset + i + 10 - y, -1, a2, format("%3d", i + 1));
1956 			Term_putstr(horiz_offset + 12, vertikal_offset + i + 10 - y, -1, a, "                              ");
1957 			Term_putstr(horiz_offset + 12, vertikal_offset + i + 10 - y, -1, a, (char*)lua_name);
1958 		}
1959 
1960 		/* display static selector */
1961 		Term_putstr(horiz_offset + 1, vertikal_offset + 10, -1, TERM_ORANGE, ">>>");
1962 		Term_putstr(horiz_offset + 1 + 12 + 40 + 1, vertikal_offset + 10, -1, TERM_ORANGE, "<<<");
1963 
1964 		/* Place Cursor */
1965 		//Term_gotoxy(20, vertikal_offset + y);
1966 		/* hack: hide cursor */
1967 		Term->scr->cx = Term->wid;
1968 		Term->scr->cu = 1;
1969 
1970 		/* Get key */
1971 		ch = inkey();
1972 
1973 		/* Analyze */
1974 		switch (ch) {
1975 		case ESCAPE:
1976 			/* auto-save */
1977 			path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
1978 			path_build(buf2, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.$$$");
1979 			fff = my_fopen(buf, "r");
1980 			fff2 = my_fopen(buf2, "w");
1981 			if (!fff) {
1982 				c_msg_print("Error: File 'sound.cfg' not found.");
1983 				return;
1984 			}
1985 			while (!feof(fff)) {
1986 				fgets(out_val, 2048, fff);
1987 				if (feof(fff)) continue;
1988 
1989 				p = out_val;
1990 				/* remove comment-character */
1991 				if (*p == ';') p++;
1992 
1993 				/* ignores lines that don't start on a letter */
1994 				if (tolower(*p) < 'a' || tolower(*p) > 'z') {
1995 					fputs(out_val, fff2);
1996 					continue;
1997 				}
1998 
1999 				/* extract event name */
2000 				strcpy(evname, p);
2001 				*(strchr(evname, ' ')) = 0;
2002 
2003 				/* find out event state (disabled/enabled) */
2004 				j = exec_lua(0, format("return get_sound_index(\"%s\")", evname));
2005 				if (j == -1 || !samples[j].config) {
2006 					/* 'empty' event (no filenames specified), just copy it over same as misc lines */
2007 					fputs(out_val, fff2);
2008 					continue;
2009 				}
2010 
2011 				/* apply new state */
2012 				if (samples[j].disabled) {
2013 					strcpy(out_val2, ";");
2014 					strcat(out_val2, p);
2015 				} else {
2016 					strcpy(out_val2, p);
2017 				}
2018 
2019 				fputs(out_val2, fff2);
2020 			}
2021 			fclose(fff);
2022 			fclose(fff2);
2023 			rename(buf, format("%s.bak", buf));
2024 			rename(buf2, buf);
2025 
2026 			go = FALSE;
2027 			break;
2028 
2029 		case KTRL('T'):
2030 			/* Take a screenshot */
2031 			xhtml_screenshot("screenshot????");
2032 			break;
2033 		case ':':
2034 			/* specialty: allow chatting from within here */
2035 			cmd_message();
2036 			break;
2037 
2038 		case 't':
2039 			samples[y].disabled = !samples[y].disabled;
2040 			break;
2041 		case 'y':
2042 			samples[y].disabled = FALSE;
2043 			break;
2044 		case 'n':
2045 			samples[y].disabled = TRUE;
2046 			break;
2047 
2048 		case '#':
2049 			y = c_get_quantity("Enter index number: ", audio_sfx) - 1;
2050 			if (y < 0) y = 0;
2051 			if (y >= audio_sfx) y = audio_sfx - 1;
2052 			break;
2053 		case '9':
2054 			y = (y - 10 + audio_sfx) % audio_sfx;
2055 			break;
2056 		case '3':
2057 			y = (y + 10 + audio_sfx) % audio_sfx;
2058 			break;
2059 		case '1':
2060 			y = audio_sfx - 1;
2061 			break;
2062 		case '7':
2063 			y = 0;
2064 			break;
2065 		case '8':
2066 		case '2':
2067 			d = keymap_dirs[ch & 0x7F];
2068 			y = (y + ddy[d] + audio_sfx) % audio_sfx;
2069 			break;
2070 		default:
2071 			bell();
2072 		}
2073 	}
2074 }
2075 
2076 /* Display options page UI that allows to comment out music easily */
2077 void do_cmd_options_mus_sdl(void) {
2078 	int i, i2, j, d, vertikal_offset = 3, horiz_offset = 5;
2079 	int y = 0;//, max_events = 0;
2080 	char ch;
2081 	byte a, a2;
2082 	cptr lua_name;
2083 	bool go = TRUE;
2084 	char buf[1024], buf2[1024], out_val[2048], out_val2[2048], *p, evname[2048];
2085 	FILE *fff, *fff2;
2086 
2087 	//ANGBAND_DIR_XTRA_SOUND/MUSIC are NULL in quiet_mode!
2088 	if (quiet_mode) {
2089 		c_msg_print("Client is running in quiet mode, music is not available.");
2090 		return;
2091 	}
2092 
2093 	/* Build the filename */
2094 	path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
2095 
2096 	/* Check if the file exists */
2097 	fff = my_fopen(buf, "r");
2098 	if (!fff) {
2099 		c_msg_print("Error: File 'music.cfg' not found.");
2100 		return;
2101 	}
2102 	fclose(fff);
2103 
2104 	/* Clear screen */
2105 	Term_clear();
2106 
2107 	/* Interact */
2108 	while (go) {
2109 		Term_putstr(0, 0, -1, TERM_WHITE, "  (<\377ydir\377w/\377y#\377w>, \377yt\377w (toggle), \377yy\377w/\377yn\377w (enable/disable), \377yESC\377w)");
2110 		Term_putstr(0, 1, -1, TERM_WHITE, "  (\377wAll changes made here will auto-save as soon as you leave this page)");
2111 
2112 		/* Display the events */
2113 		for (i = y - 10 ; i <= y + 10 ; i++) {
2114 			if (i < 0 || i >= audio_music) {
2115 				Term_putstr(horiz_offset + 7, vertikal_offset + i + 10 - y, -1, TERM_WHITE, "                                        ");
2116 				continue;
2117 			}
2118 
2119 			/* Map events we've listed in our local config file onto audio.lua indices */
2120 			i2 = -1;
2121 			for (j = 0; j < MUSIC_MAX; j++) {
2122 				if (!songs[j].config) continue;
2123 				i2++;
2124 				if (i2 == i) break;
2125 			}
2126 			if (j != MUSIC_MAX) { //paranoia, should always be false
2127 				/* get event name */
2128 				sprintf(out_val, "return get_music_name(%d)", j);
2129 				lua_name = string_exec_lua(0, out_val);
2130 			} else lua_name = "<nothing>";
2131 
2132 			/* set colour depending on enabled/disabled state */
2133 			//todo - c_cfg.use_color D: yadayada
2134 			if (songs[i].disabled) {
2135 				a = TERM_L_DARK;
2136 				a2 = TERM_UMBER;
2137 			} else {
2138 				a = TERM_WHITE;
2139 				a2 = TERM_YELLOW;
2140 			}
2141 
2142 			Term_putstr(horiz_offset + 7, vertikal_offset + i + 10 - y, -1, a2, format("%3d", i + 1));
2143 			Term_putstr(horiz_offset + 12, vertikal_offset + i + 10 - y, -1, a, "                              ");
2144 			Term_putstr(horiz_offset + 12, vertikal_offset + i + 10 - y, -1, a, (char*)lua_name);
2145 		}
2146 
2147 		/* display static selector */
2148 		Term_putstr(horiz_offset + 1, vertikal_offset + 10, -1, TERM_ORANGE, ">>>");
2149 		Term_putstr(horiz_offset + 1 + 12 + 40 + 1, vertikal_offset + 10, -1, TERM_ORANGE, "<<<");
2150 
2151 		/* Place Cursor */
2152 		//Term_gotoxy(20, vertikal_offset + y);
2153 		/* hack: hide cursor */
2154 		Term->scr->cx = Term->wid;
2155 		Term->scr->cu = 1;
2156 
2157 		/* Get key */
2158 		ch = inkey();
2159 
2160 		/* Analyze */
2161 		switch (ch) {
2162 		case ESCAPE:
2163 			/* auto-save */
2164 			path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
2165 			path_build(buf2, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.$$$");
2166 			fff = my_fopen(buf, "r");
2167 			fff2 = my_fopen(buf2, "w");
2168 			if (!fff) {
2169 				c_msg_print("Error: File 'music.cfg' not found.");
2170 				return;
2171 			}
2172 			while (!feof(fff)) {
2173 				fgets(out_val, 2048, fff);
2174 				if (feof(fff)) continue;
2175 
2176 				p = out_val;
2177 				/* remove comment-character */
2178 				if (*p == ';') p++;
2179 
2180 				/* ignores lines that don't start on a letter */
2181 				if (tolower(*p) < 'a' || tolower(*p) > 'z') {
2182 					fputs(out_val, fff2);
2183 					continue;
2184 				}
2185 
2186 				/* extract event name */
2187 				strcpy(evname, p);
2188 				*(strchr(evname, ' ')) = 0;
2189 
2190 				/* find out event state (disabled/enabled) */
2191 				j = exec_lua(0, format("return get_music_index(\"%s\")", evname));
2192 				if (j == -1 || !songs[j].config) {
2193 					/* 'empty' event (no filenames specified), just copy it over same as misc lines */
2194 					fputs(out_val, fff2);
2195 					continue;
2196 				}
2197 
2198 				/* apply new state */
2199 				if (songs[j].disabled) {
2200 					strcpy(out_val2, ";");
2201 					strcat(out_val2, p);
2202 				} else {
2203 					strcpy(out_val2, p);
2204 				}
2205 
2206 				fputs(out_val2, fff2);
2207 			}
2208 			fclose(fff);
2209 			fclose(fff2);
2210 			rename(buf, format("%s.bak", buf));
2211 			rename(buf2, buf);
2212 
2213 			go = FALSE;
2214 			break;
2215 
2216 		case KTRL('T'):
2217 			/* Take a screenshot */
2218 			xhtml_screenshot("screenshot????");
2219 			break;
2220 		case ':':
2221 			/* specialty: allow chatting from within here */
2222 			cmd_message();
2223 			break;
2224 
2225 		case 't':
2226 			songs[y].disabled = !songs[y].disabled;
2227 			play_music(y);
2228 			break;
2229 		case 'y':
2230 			songs[y].disabled = FALSE;
2231 			play_music(y);
2232 			break;
2233 		case 'n':
2234 			songs[y].disabled = TRUE;
2235 			play_music(y);
2236 			break;
2237 
2238 		case '#':
2239 			y = c_get_quantity("Enter index number: ", audio_music) - 1;
2240 			if (y < 0) y = 0;
2241 			if (y >= audio_music) y = audio_music - 1;
2242 			break;
2243 		case '9':
2244 			y = (y - 10 + audio_music) % audio_music;
2245 			break;
2246 		case '3':
2247 			y = (y + 10 + audio_music) % audio_music;
2248 			break;
2249 		case '1':
2250 			y = audio_music - 1;
2251 			break;
2252 		case '7':
2253 			y = 0;
2254 			break;
2255 		case '8':
2256 		case '2':
2257 			d = keymap_dirs[ch & 0x7F];
2258 			y = (y + ddy[d] + audio_music) % audio_music;
2259 			break;
2260 		default:
2261 			bell();
2262 		}
2263 	}
2264 }
2265 
2266 #endif /* SOUND_SDL */
2267