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