Angband 3.0.9b.
[angband.git] / src / snd-sdl.c
blob3318382782c8f5e4c3c041f2bea5583b005302e9
1 /*
2 * File: snd-sdl.c
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.
19 #include "angband.h"
22 #ifdef SOUND_SDL
25 #include "SDL.h"
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 */
38 #define MAX_SAMPLES 8
40 /* Struct representing all data about an event sample */
41 typedef struct
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 */
46 } sample_list;
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)
60 size_t i;
61 int j;
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]);
76 /* Close the audio */
77 Mix_CloseAudio();
79 /* XXX This may conflict with the SDL port */
80 SDL_Quit();
85 * Initialise SDL and open the mixer
87 static bool open_audio(void)
89 int audio_rate;
90 Uint16 audio_format;
91 int audio_channels;
93 /* Initialize variables */
94 audio_rate = 22050;
95 audio_format = AUDIO_S16;
96 audio_channels = 2;
98 /* Initialize the SDL library */
99 if (SDL_Init(SDL_INIT_AUDIO) < 0)
101 plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
102 return FALSE;
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());
109 return FALSE;
112 /* Success */
113 return TRUE;
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)
124 char path[2048];
125 char buffer[2048];
126 FILE *fff;
129 /* Initialise the mixer */
130 if (!open_audio())
131 return FALSE;
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");
142 /* Handle errors */
143 if (!fff)
145 plog_fmt("Failed to open sound config (%s):\n %s",
146 path, strerror(errno));
147 return FALSE;
150 /* Parse the file */
151 /* Lines are always of the form "name = sample [sample ...]" */
152 while (my_fgets(fff, buffer, sizeof(buffer)) == 0)
154 char *msg_name;
155 char *sample_list;
156 char *search;
157 char *cur_token;
158 char *next_token;
159 int event;
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 */
171 msg_name = buffer;
172 search[0] = '\0';
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)
179 break;
181 if (event < 0) continue;
183 /* Advance the sample list pointer so it's at the beginning of text */
184 sample_list++;
185 if (!sample_list[0]) continue;
187 /* Terminate the current token */
188 cur_token = sample_list;
189 search = strchr(cur_token, ' ');
190 if (search)
192 search[0] = '\0';
193 next_token = search + 1;
195 else
197 next_token = NULL;
201 * Now we find all the sample names and add them one by one
203 while (cur_token)
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 */
215 if (no_cache)
217 /* Just save the path for later */
218 samples[event].paths[num] = string_make(path);
220 else
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));
227 goto next_token;
231 /* Imcrement the sample count */
232 samples[event].num++;
234 next_token:
236 /* Figure out next token */
237 cur_token = next_token;
238 if (next_token)
240 /* Try to find a space */
241 search = strchr(cur_token, ' ');
243 /* If we can find one, terminate, and set new "next" */
244 if (search)
246 search[0] = '\0';
247 next_token = search + 1;
249 else
251 /* Otherwise prevent infinite looping */
252 next_token = NULL;
258 /* Close the file */
259 my_fclose(fff);
262 /* Success */
263 return TRUE;
267 * Play a sound of type "event".
269 static void play_sound(int event)
271 Mix_Chunk *wave = NULL;
272 int s;
274 /* Paranoia */
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 */
285 if (!wave)
287 /* Verify it exists */
288 const char *filename = samples[event].paths[s];
289 if (!my_fexists(filename)) return;
291 /* Load */
292 wave = Mix_LoadWAV(filename);
295 /* Check to see if we have a wave again */
296 if (!wave)
298 plog("SDL sound load failed.");
299 return;
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)
312 int i;
314 /* Parse args */
315 for (i = 1; i < argc; i++)
317 if (prefix(argv[i], "-c"))
319 no_cache_audio = TRUE;
320 plog("Audio cache disabled.");
321 continue;
325 /* Load sound preferences if requested */
326 if (!sound_sdl_init(no_cache_audio))
328 plog("Failed to load sound config");
330 /* Failure */
331 return (1);
334 /* Enable sound */
335 sound_hook = play_sound;
336 atexit(close_audio);
338 /* Success */
339 return (0);
343 #endif /* SOUND_SDL */