3 * Purpose: SDL sound support
5 * Copyright (c) 2004-2007 Brendon Oliver, Andrew Sidwell.
6 * A large chunk of this file was taken and modified from main-ros.
8 * This work is free software; you can redistribute it and/or modify it
9 * under the terms of either:
11 * a) the GNU General Public License as published by the Free Software
12 * Foundation, version 2, or
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.
26 #include "SDL_mixer.h"
29 /* Don't cache audio */
30 static bool no_cache_audio
= FALSE
;
32 /* Path to sound files */
33 static const char *ANGBAND_DIR_XTRA_SOUND
;
37 /* Arbitary limit on number of samples per event */
40 /* Struct representing all data about an event sample */
43 int num
; /* Number of samples for this event */
44 Mix_Chunk
*wavs
[MAX_SAMPLES
]; /* Sample array */
45 const char *paths
[MAX_SAMPLES
]; /* Relative pathnames for samples */
50 * Just need an array of SampInfos
52 static sample_list samples
[MSG_MAX
];
56 * Shut down the sound system and free resources.
58 static void close_audio(void)
63 /* Free all the sample data*/
64 for (i
= 0; i
< MSG_MAX
; i
++)
66 sample_list
*smp
= &samples
[i
];
68 /* Nuke all samples */
69 for (j
= 0; j
< smp
->num
; j
++)
71 Mix_FreeChunk(smp
->wavs
[j
]);
72 string_free(smp
->paths
[j
]);
79 /* XXX This may conflict with the SDL port */
85 * Initialise SDL and open the mixer
87 static bool open_audio(void)
93 /* Initialize variables */
95 audio_format
= AUDIO_S16
;
98 /* Initialize the SDL library */
99 if (SDL_Init(SDL_INIT_AUDIO
) < 0)
101 plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
105 /* Try to open the audio */
106 if (Mix_OpenAudio(audio_rate
, audio_format
, audio_channels
, 4096) < 0)
108 plog_fmt("Couldn't open mixer: %s", SDL_GetError());
119 * Read sound.cfg and map events to sounds; then load all the sounds into
120 * memory to avoid I/O latency later.
122 static bool sound_sdl_init(bool no_cache
)
129 /* Initialise the mixer */
134 /* Build the "sound" path */
135 path_build(path
, sizeof(path
), ANGBAND_DIR_XTRA
, "sound");
136 ANGBAND_DIR_XTRA_SOUND
= string_make(path
);
138 /* Find and open the config file */
139 path_build(path
, sizeof(path
), ANGBAND_DIR_XTRA_SOUND
, "sound.cfg");
140 fff
= my_fopen(path
, "r");
145 plog_fmt("Failed to open sound config (%s):\n %s",
146 path
, strerror(errno
));
151 /* Lines are always of the form "name = sample [sample ...]" */
152 while (my_fgets(fff
, buffer
, sizeof(buffer
)) == 0)
161 /* Skip anything not beginning with an alphabetic character */
162 if (!buffer
[0] || !isalpha((unsigned char)buffer
[0])) continue;
164 /* Split the line into two: message name, and the rest */
165 search
= strchr(buffer
, ' ');
166 sample_list
= strchr(search
+ 1, ' ');
167 if (!search
) continue;
168 if (!sample_list
) continue;
170 /* Set the message name, and terminate at first space */
175 /* Make sure this is a valid event name */
176 for (event
= MSG_MAX
- 1; event
>= 0; event
--)
178 if (strcmp(msg_name
, angband_sound_name
[event
]) == 0)
181 if (event
< 0) continue;
183 /* Advance the sample list pointer so it's at the beginning of text */
185 if (!sample_list
[0]) continue;
187 /* Terminate the current token */
188 cur_token
= sample_list
;
189 search
= strchr(cur_token
, ' ');
193 next_token
= search
+ 1;
201 * Now we find all the sample names and add them one by one
205 int num
= samples
[event
].num
;
207 /* Don't allow too many samples */
208 if (num
>= MAX_SAMPLES
) break;
210 /* Build the path to the sample */
211 path_build(path
, sizeof(path
), ANGBAND_DIR_XTRA_SOUND
, cur_token
);
212 if (!my_fexists(path
)) goto next_token
;
214 /* Don't load now if we're not caching */
217 /* Just save the path for later */
218 samples
[event
].paths
[num
] = string_make(path
);
222 /* Load the file now */
223 samples
[event
].wavs
[num
] = Mix_LoadWAV(path
);
224 if (!samples
[event
].wavs
[num
])
226 plog_fmt("%s: %s", SDL_GetError(), strerror(errno
));
231 /* Imcrement the sample count */
232 samples
[event
].num
++;
236 /* Figure out next token */
237 cur_token
= next_token
;
240 /* Try to find a space */
241 search
= strchr(cur_token
, ' ');
243 /* If we can find one, terminate, and set new "next" */
247 next_token
= search
+ 1;
251 /* Otherwise prevent infinite looping */
267 * Play a sound of type "event".
269 static void play_sound(int event
)
271 Mix_Chunk
*wave
= NULL
;
275 if (event
< 0 || event
>= MSG_MAX
) return;
277 /* Check there are samples for this event */
278 if (!samples
[event
].num
) return;
280 /* Choose a random event */
281 s
= rand_int(samples
[event
].num
);
282 wave
= samples
[event
].wavs
[s
];
284 /* Try loading it, if it's not cached */
287 /* Verify it exists */
288 const char *filename
= samples
[event
].paths
[s
];
289 if (!my_fexists(filename
)) return;
292 wave
= Mix_LoadWAV(filename
);
295 /* Check to see if we have a wave again */
298 plog("SDL sound load failed.");
302 /* Actually play the thing */
303 Mix_PlayChannel(-1, wave
, 0);
308 * Init the SDL sound "module".
310 errr
init_sound_sdl(int argc
, char **argv
)
315 for (i
= 1; i
< argc
; i
++)
317 if (prefix(argv
[i
], "-c"))
319 no_cache_audio
= TRUE
;
320 plog("Audio cache disabled.");
325 /* Load sound preferences if requested */
326 if (!sound_sdl_init(no_cache_audio
))
328 plog("Failed to load sound config");
335 sound_hook
= play_sound
;
343 #endif /* SOUND_SDL */