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