1 /* File: sdl-sound.c */
2 /* Purpose: SDL_Audio routines for loading and playing WAVs */
3 #if defined(USE_SDL) || defined(USE_SDL2)
4
5 #include "c-angband.h"
6 #include <SDL.h>
7
8 #ifdef USE_SOUND
9
10 typedef struct sound_wave
11 {
12 Uint8* buffer;
13 Uint32 length;
14 Uint32 pos;
15 bool playing;
16 } sound_wave;
17 sound_wave sound_data[MSG_MAX][SAMPLE_MAX];
18 sound_wave *now_playing = NULL;
19
20 SDL_AudioSpec wav_obtained;
21
wav_play(void * userdata,Uint8 * stream,int len)22 static void wav_play(void *userdata, Uint8 *stream, int len)
23 {
24 /* Grab */
25 sound_wave * wav = now_playing;
26
27 /* Paranoia */
28 Uint32 tocopy = ((wav->length - wav->pos > len) ? len: wav->length - wav->pos);
29
30 /* Samples to copy for silence */
31 Uint32 topad = len - tocopy;
32
33 /* Copy data to audio buffer */
34 memcpy(stream, wav->buffer + wav->pos, tocopy);
35
36 /* Copy silence to audio buffer */
37 /* TODO: for >=16bit unsigned formats, "0" is wrong, but I don't want
38 * to do interleaved memset here :( Ideally, we should have a static
39 * buffer pre-filled with silence and copy from there... */
40 memset(stream + tocopy, 0, topad);
41
42 /* Advance */
43 wav->pos += tocopy;
44 }
45
sdl_play_sound_end(bool wait)46 void sdl_play_sound_end(bool wait)
47 {
48 bool end_sound;
49 sound_wave * wav = now_playing;
50
51 if (wav == NULL) return;
52
53 end_sound = (wait? (wav->pos == wav->length): TRUE);
54
55 /* Wait for end of audio thread */
56 if ((wav->length != 0) && end_sound && wav->playing)
57 {
58 /* Stop playing */
59 SDL_PauseAudio(1);
60 wav->playing = FALSE;
61 }
62 }
63
64 /*
65 * Init sound
66 */
sdl_init_sound()67 void sdl_init_sound()
68 {
69 SDL_AudioSpec wav_desired;
70 int i, j;
71
72 /* Desired audio parameters */
73 wav_desired.freq = 44100;
74 wav_desired.format = 0; /* let OS pick //AUDIO_U16SYS;*/
75 wav_desired.channels = 2;
76 wav_desired.samples = 512;
77 wav_desired.callback = &wav_play;
78 wav_desired.userdata = NULL;
79
80 /* Open the audio device */
81 if (SDL_OpenAudio(&wav_desired, &wav_obtained) != 0)
82 {
83 plog_fmt("Could not open audio: %s", SDL_GetError());
84 use_sound = FALSE;
85 return;
86 }
87
88 /* Clear sound_data */
89 for (j = 0; j < MSG_MAX; j++) for (i = 0; i < SAMPLE_MAX; i++)
90 {
91 (void)WIPE(&sound_data[j][i], sound_wave);
92 }
93 }
94
95 /*
96 * Close sound
97 */
sdl_cleanup_sound()98 void sdl_cleanup_sound()
99 {
100 int j, i;
101
102 /* Close the audio device */
103 SDL_CloseAudio();
104
105 /* Free loaded wavs */
106 for (j = 0; j < MSG_MAX; j++) for (i = 0; i < SAMPLE_MAX; i++)
107 {
108 if (sound_data[j][i].buffer != NULL)
109 {
110 free(sound_data[j][i].buffer);
111 }
112 }
113 }
114 /*
115 * Load a sound
116 */
sdl_load_sound(int v,int s)117 void sdl_load_sound(int v, int s)
118 {
119 SDL_AudioSpec wav_spec;
120 SDL_AudioCVT wav_cvt;
121 char buf[MSG_LEN];
122
123 sound_wave * wav = &sound_data[v][s];
124
125 /* Build the path */
126 path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, sound_file[v][s]);
127
128 /* Load the WAV */
129 if (SDL_LoadWAV(buf, &wav_spec, &wav->buffer, &wav->length) == NULL)
130 {
131 plog_fmt("Could not open %s: %s", buf, SDL_GetError());
132 return;
133 }
134
135 /* Build the audio converter */
136 if (SDL_BuildAudioCVT(&wav_cvt, wav_spec.format, wav_spec.channels, wav_spec.freq,
137 wav_obtained.format, wav_obtained.channels, wav_obtained.freq) < 0)
138 {
139 plog_fmt("Could not build audio converter: %s", SDL_GetError());
140 return;
141 }
142
143 /* Allocate a buffer for the audio converter */
144 wav_cvt.buf = malloc(wav->length * wav_cvt.len_mult);
145 wav_cvt.len = wav->length;
146 memcpy(wav_cvt.buf, wav->buffer, wav->length);
147
148 /* Convert audio data to correct format */
149 if (SDL_ConvertAudio(&wav_cvt) != 0)
150 {
151 plog_fmt("Could not convert audio file: %s", SDL_GetError());
152 return;
153 }
154
155 /* Free the WAV */
156 SDL_FreeWAV(wav->buffer);
157
158 /* Allocate a buffer for the audio data */
159 wav->buffer = malloc(wav_cvt.len_cvt);
160 memcpy(wav->buffer, wav_cvt.buf, wav_cvt.len_cvt);
161 free(wav_cvt.buf);
162 wav->length = wav_cvt.len_cvt;
163 }
164 /*
165 * Make a sound
166 */
sdl_play_sound(int v,int s)167 void sdl_play_sound(int v, int s)
168 {
169 sound_wave * wav = &sound_data[v][s];
170
171 /* If another sound is currently playing, stop it */
172 sdl_play_sound_end(FALSE);
173
174 /* If sound isn't loaded, load it */
175 if (wav->buffer == NULL) sdl_load_sound(v,s);
176
177 /* Start playing */
178 wav->pos = 0;
179 wav->playing = TRUE;
180 SDL_PauseAudio(0);
181
182 now_playing = wav;
183 }
184
185 /*
186 * BONUS API - Play a system beep sound
187 */
188 #ifdef ON_OSX
189 #include "CoreFoundation/CoreFoundation.h"
190 #endif
191 #ifdef WINDOWS
192 /* <windows.h> should already be included by "c-angband.h" */
193 #endif
sdl_bell(void)194 void sdl_bell(void)
195 {
196 #ifdef ON_OSX
197 NSBeep();
198 #elif defined(WINDOWS)
199 MessageBeep(MB_ICONASTERISK);
200 #elif defined(SET_UID) && !defined(MOBILE_UI)
201 /* Hacky fallback for "UNIX" */
202 fprintf(stdout, "\a");
203 #endif
204 }
205
206 #endif
207 #endif
208