1 /**
2 * Originally digi.c from allegro wiki
3 * Original authors: KC/Milan
4 *
5 * Converted to allegro5 by Ryan Dickie
6 */
7
8
9 #include <math.h>
10 #include <stdio.h>
11
12 #include "allegro5/allegro.h"
13 #include "allegro5/allegro_audio.h"
14 #include "allegro5/internal/aintern.h"
15 #include "allegro5/internal/aintern_exitfunc.h"
16 #include "allegro5/internal/aintern_audio.h"
17 #include "allegro5/internal/aintern_audio_cfg.h"
18
19 ALLEGRO_DEBUG_CHANNEL("audio")
20
_al_set_error(int error,char * string)21 void _al_set_error(int error, char* string)
22 {
23 ALLEGRO_ERROR("%s (error code: %d)\n", string, error);
24 }
25
26 ALLEGRO_AUDIO_DRIVER *_al_kcm_driver = NULL;
27
28 #if defined(ALLEGRO_CFG_KCM_OPENAL)
29 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_openal_driver;
30 #endif
31 #if defined(ALLEGRO_CFG_KCM_OPENSL)
32 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_opensl_driver;
33 #endif
34 #if defined(ALLEGRO_CFG_KCM_ALSA)
35 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_alsa_driver;
36 #endif
37 #if defined(ALLEGRO_CFG_KCM_OSS)
38 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_oss_driver;
39 #endif
40 #if defined(ALLEGRO_CFG_KCM_DSOUND)
41 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_dsound_driver;
42 #endif
43 #if defined(ALLEGRO_CFG_KCM_AQUEUE)
44 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_aqueue_driver;
45 #endif
46 #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO)
47 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_pulseaudio_driver;
48 #endif
49 #if defined(ALLEGRO_SDL)
50 extern struct ALLEGRO_AUDIO_DRIVER _al_kcm_sdl_driver;
51 #endif
52
53 /* Channel configuration helpers */
54
55 /* Function: al_get_channel_count
56 */
al_get_channel_count(ALLEGRO_CHANNEL_CONF conf)57 size_t al_get_channel_count(ALLEGRO_CHANNEL_CONF conf)
58 {
59 return (conf>>4)+(conf&0xF);
60 }
61
62 /* Depth configuration helpers */
63 /* Function: al_get_audio_depth_size
64 */
al_get_audio_depth_size(ALLEGRO_AUDIO_DEPTH depth)65 size_t al_get_audio_depth_size(ALLEGRO_AUDIO_DEPTH depth)
66 {
67 switch (depth) {
68 case ALLEGRO_AUDIO_DEPTH_INT8:
69 case ALLEGRO_AUDIO_DEPTH_UINT8:
70 return sizeof(int8_t);
71 case ALLEGRO_AUDIO_DEPTH_INT16:
72 case ALLEGRO_AUDIO_DEPTH_UINT16:
73 return sizeof(int16_t);
74 case ALLEGRO_AUDIO_DEPTH_INT24:
75 case ALLEGRO_AUDIO_DEPTH_UINT24:
76 return sizeof(int32_t);
77 case ALLEGRO_AUDIO_DEPTH_FLOAT32:
78 return sizeof(float);
79 default:
80 ASSERT(false);
81 return 0;
82 }
83 }
84
85 /* FIXME: use the allegro provided helpers */
_al_count_to_channel_conf(int num_channels)86 ALLEGRO_CHANNEL_CONF _al_count_to_channel_conf(int num_channels)
87 {
88 switch (num_channels) {
89 case 1:
90 return ALLEGRO_CHANNEL_CONF_1;
91 case 2:
92 return ALLEGRO_CHANNEL_CONF_2;
93 case 3:
94 return ALLEGRO_CHANNEL_CONF_3;
95 case 4:
96 return ALLEGRO_CHANNEL_CONF_4;
97 case 6:
98 return ALLEGRO_CHANNEL_CONF_5_1;
99 case 7:
100 return ALLEGRO_CHANNEL_CONF_6_1;
101 case 8:
102 return ALLEGRO_CHANNEL_CONF_7_1;
103 default:
104 return 0;
105 }
106 }
107
108 /* FIXME: assumes 8-bit is unsigned, and all others are signed. */
_al_word_size_to_depth_conf(int word_size)109 ALLEGRO_AUDIO_DEPTH _al_word_size_to_depth_conf(int word_size)
110 {
111 switch (word_size) {
112 case 1:
113 return ALLEGRO_AUDIO_DEPTH_UINT8;
114 case 2:
115 return ALLEGRO_AUDIO_DEPTH_INT16;
116 case 3:
117 return ALLEGRO_AUDIO_DEPTH_INT24;
118 case 4:
119 return ALLEGRO_AUDIO_DEPTH_FLOAT32;
120 default:
121 return 0;
122 }
123 }
124
125 /* Function: al_fill_silence
126 */
al_fill_silence(void * buf,unsigned int samples,ALLEGRO_AUDIO_DEPTH depth,ALLEGRO_CHANNEL_CONF chan_conf)127 void al_fill_silence(void *buf, unsigned int samples,
128 ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)
129 {
130 size_t bytes = samples * al_get_audio_depth_size(depth) *
131 al_get_channel_count(chan_conf);
132
133 switch (depth) {
134 case ALLEGRO_AUDIO_DEPTH_INT8:
135 case ALLEGRO_AUDIO_DEPTH_INT16:
136 case ALLEGRO_AUDIO_DEPTH_INT24:
137 case ALLEGRO_AUDIO_DEPTH_FLOAT32:
138 memset(buf, 0, bytes);
139 break;
140 case ALLEGRO_AUDIO_DEPTH_UINT8:
141 memset(buf, 0x80, bytes);
142 break;
143 case ALLEGRO_AUDIO_DEPTH_UINT16:
144 {
145 uint16_t *buffer = buf;
146 size_t n = bytes / sizeof(uint16_t);
147 size_t i;
148
149 for (i = 0; i < n; i++)
150 buffer[i] = 0x8000;
151 }
152 break;
153 case ALLEGRO_AUDIO_DEPTH_UINT24:
154 {
155 uint32_t *buffer = buf;
156 size_t n = bytes / sizeof(uint32_t);
157 size_t i;
158
159 for (i = 0; i < n; i++)
160 buffer[i] = 0x800000;
161 }
162 break;
163 default:
164 ASSERT(false);
165 break;
166 }
167 }
168
get_config_audio_driver(void)169 static ALLEGRO_AUDIO_DRIVER_ENUM get_config_audio_driver(void)
170 {
171 ALLEGRO_CONFIG *config = al_get_system_config();
172 const char *value;
173
174 value = al_get_config_value(config, "audio", "driver");
175 if (!value || value[0] == '\0')
176 return ALLEGRO_AUDIO_DRIVER_AUTODETECT;
177
178 if (0 == _al_stricmp(value, "ALSA"))
179 return ALLEGRO_AUDIO_DRIVER_ALSA;
180
181 if (0 == _al_stricmp(value, "OPENAL"))
182 return ALLEGRO_AUDIO_DRIVER_OPENAL;
183
184 if (0 == _al_stricmp(value, "OPENSL"))
185 return ALLEGRO_AUDIO_DRIVER_OPENSL;
186
187 if (0 == _al_stricmp(value, "OSS"))
188 return ALLEGRO_AUDIO_DRIVER_OSS;
189
190 if (0 == _al_stricmp(value, "PULSEAUDIO"))
191 return ALLEGRO_AUDIO_DRIVER_PULSEAUDIO;
192
193 if (0 == _al_stricmp(value, "DSOUND") || 0 == _al_stricmp(value, "DIRECTSOUND"))
194 return ALLEGRO_AUDIO_DRIVER_DSOUND;
195
196 return ALLEGRO_AUDIO_DRIVER_AUTODETECT;
197 }
198
do_install_audio(ALLEGRO_AUDIO_DRIVER_ENUM mode)199 static bool do_install_audio(ALLEGRO_AUDIO_DRIVER_ENUM mode)
200 {
201 bool retVal;
202
203 /* check to see if a driver is already installed and running */
204 if (_al_kcm_driver) {
205 _al_set_error(ALLEGRO_GENERIC_ERROR, "A driver already running");
206 return false;
207 }
208
209 if (mode == ALLEGRO_AUDIO_DRIVER_AUTODETECT) {
210 mode = get_config_audio_driver();
211 }
212
213 switch (mode) {
214 case ALLEGRO_AUDIO_DRIVER_AUTODETECT:
215 #if defined(ALLEGRO_SDL)
216 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_SDL);
217 if (retVal)
218 return retVal;
219 #endif
220 #if defined(ALLEGRO_CFG_KCM_AQUEUE)
221 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_AQUEUE);
222 if (retVal)
223 return retVal;
224 #endif
225 /* If a PA server is running, we should use it by default as it will
226 * hijack ALSA and OSS and using those then just means extra lag.
227 *
228 * FIXME: Detect if no PA server is running and in that case prefer
229 * ALSA and OSS first.
230 */
231 #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO)
232 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_PULSEAUDIO);
233 if (retVal)
234 return retVal;
235 #endif
236 #if defined(ALLEGRO_CFG_KCM_ALSA)
237 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_ALSA);
238 if (retVal)
239 return retVal;
240 #endif
241 #if defined(ALLEGRO_CFG_KCM_DSOUND)
242 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_DSOUND);
243 if (retVal)
244 return retVal;
245 #endif
246 #if defined(ALLEGRO_CFG_KCM_OSS)
247 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OSS);
248 if (retVal)
249 return retVal;
250 #endif
251 #if defined(ALLEGRO_CFG_KCM_OPENAL)
252 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OPENAL);
253 if (retVal)
254 return retVal;
255 #endif
256 #if defined(ALLEGRO_CFG_KCM_OPENSL)
257 retVal = do_install_audio(ALLEGRO_AUDIO_DRIVER_OPENSL);
258 if (retVal)
259 return retVal;
260 #endif
261
262 _al_set_error(ALLEGRO_INVALID_PARAM, "No audio driver can be used.");
263 _al_kcm_driver = NULL;
264 return false;
265
266 case ALLEGRO_AUDIO_DRIVER_AQUEUE:
267 #if defined(ALLEGRO_CFG_KCM_AQUEUE)
268 if (_al_kcm_aqueue_driver.open() == 0) {
269 ALLEGRO_INFO("Using Apple Audio Queue driver\n");
270 _al_kcm_driver = &_al_kcm_aqueue_driver;
271 return true;
272 }
273 return false;
274 #else
275 _al_set_error(ALLEGRO_INVALID_PARAM, "Audio Queue driver not available on this platform");
276 return false;
277 #endif
278
279 case ALLEGRO_AUDIO_DRIVER_OPENAL:
280 #if defined(ALLEGRO_CFG_KCM_OPENAL)
281 if (_al_kcm_openal_driver.open() == 0) {
282 ALLEGRO_INFO("Using OpenAL driver\n");
283 _al_kcm_driver = &_al_kcm_openal_driver;
284 return true;
285 }
286 return false;
287 #else
288 _al_set_error(ALLEGRO_INVALID_PARAM, "OpenAL not available on this platform");
289 return false;
290 #endif
291
292 case ALLEGRO_AUDIO_DRIVER_OPENSL:
293 #if defined(ALLEGRO_CFG_KCM_OPENSL)
294 if (_al_kcm_opensl_driver.open() == 0) {
295 ALLEGRO_INFO("Using OpenSL driver\n");
296 _al_kcm_driver = &_al_kcm_opensl_driver;
297 return true;
298 }
299 return false;
300 #else
301 _al_set_error(ALLEGRO_INVALID_PARAM, "OpenSL not available on this platform");
302 return false;
303 #endif
304
305 case ALLEGRO_AUDIO_DRIVER_ALSA:
306 #if defined(ALLEGRO_CFG_KCM_ALSA)
307 if (_al_kcm_alsa_driver.open() == 0) {
308 ALLEGRO_INFO("Using ALSA driver\n");
309 _al_kcm_driver = &_al_kcm_alsa_driver;
310 return true;
311 }
312 return false;
313 #else
314 _al_set_error(ALLEGRO_INVALID_PARAM, "ALSA not available on this platform");
315 return false;
316 #endif
317
318 case ALLEGRO_AUDIO_DRIVER_OSS:
319 #if defined(ALLEGRO_CFG_KCM_OSS)
320 if (_al_kcm_oss_driver.open() == 0) {
321 ALLEGRO_INFO("Using OSS driver\n");
322 _al_kcm_driver = &_al_kcm_oss_driver;
323 return true;
324 }
325 return false;
326 #else
327 _al_set_error(ALLEGRO_INVALID_PARAM, "OSS not available on this platform");
328 return false;
329 #endif
330
331 case ALLEGRO_AUDIO_DRIVER_PULSEAUDIO:
332 #if defined(ALLEGRO_CFG_KCM_PULSEAUDIO)
333 if (_al_kcm_pulseaudio_driver.open() == 0) {
334 ALLEGRO_INFO("Using PulseAudio driver\n");
335 _al_kcm_driver = &_al_kcm_pulseaudio_driver;
336 return true;
337 }
338 return false;
339 #else
340 _al_set_error(ALLEGRO_INVALID_PARAM, "PulseAudio not available on this platform");
341 return false;
342 #endif
343
344 case ALLEGRO_AUDIO_DRIVER_DSOUND:
345 #if defined(ALLEGRO_CFG_KCM_DSOUND)
346 if (_al_kcm_dsound_driver.open() == 0) {
347 ALLEGRO_INFO("Using DirectSound driver\n");
348 _al_kcm_driver = &_al_kcm_dsound_driver;
349 return true;
350 }
351 return false;
352 #else
353 _al_set_error(ALLEGRO_INVALID_PARAM, "DirectSound not available on this platform");
354 return false;
355 #endif
356
357 case ALLEGRO_AUDIO_DRIVER_SDL:
358 #if defined(ALLEGRO_SDL)
359 if (_al_kcm_sdl_driver.open() == 0) {
360 ALLEGRO_INFO("Using SDL driver\n");
361 _al_kcm_driver = &_al_kcm_sdl_driver;
362 return true;
363 }
364 return false;
365 #else
366 _al_set_error(ALLEGRO_INVALID_PARAM, "SDL not available on this platform");
367 return false;
368 #endif
369
370 default:
371 _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid audio driver");
372 return false;
373 }
374 }
375
376 /* Function: al_install_audio
377 */
al_install_audio(void)378 bool al_install_audio(void)
379 {
380 bool ret;
381
382 if (_al_kcm_driver)
383 return true;
384
385 /* The destructors are initialised even if the audio driver fails to install
386 * because the user may still create samples.
387 */
388 _al_kcm_init_destructors();
389 _al_add_exit_func(al_uninstall_audio, "al_uninstall_audio");
390
391 ret = do_install_audio(ALLEGRO_AUDIO_DRIVER_AUTODETECT);
392 return ret;
393 }
394
395 /* Function: al_uninstall_audio
396 */
al_uninstall_audio(void)397 void al_uninstall_audio(void)
398 {
399 if (_al_kcm_driver) {
400 _al_kcm_shutdown_default_mixer();
401 _al_kcm_shutdown_destructors();
402 _al_kcm_driver->close();
403 _al_kcm_driver = NULL;
404 }
405 else {
406 _al_kcm_shutdown_destructors();
407 }
408 }
409
410 /* Function: al_is_audio_installed
411 */
al_is_audio_installed(void)412 bool al_is_audio_installed(void)
413 {
414 return _al_kcm_driver ? true : false;
415 }
416
417 /* Function: al_get_allegro_audio_version
418 */
al_get_allegro_audio_version(void)419 uint32_t al_get_allegro_audio_version(void)
420 {
421 return ALLEGRO_VERSION_INT;
422 }
423
424 /* vim: set sts=3 sw=3 et: */
425