1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      ESD sound driver.
12  *
13  *      By Michael Bukin.
14  *
15  *      Bug fixes by Peter Wang and Eduard Bloch.
16  *
17  *      See readme.txt for copyright information.
18  */
19 
20 
21 #include "allegro.h"
22 
23 #if (defined ALLEGRO_WITH_ESDDIGI) && ((!defined ALLEGRO_WITH_MODULES) || (defined ALLEGRO_MODULE))
24 
25 #include "allegro/internal/aintern.h"
26 #include "allegro/platform/aintunix.h"
27 
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <esd.h>
33 
34 static int _al_esd_fd;
35 static int _al_esd_bufsize;
36 static unsigned char *_al_esd_bufdata;
37 static int _al_esd_bits, _al_esd_signed, _al_esd_rate, _al_esd_stereo;
38 static esd_format_t _al_esd_format;
39 
40 static int _al_esd_detect(int input);
41 static int _al_esd_init(int input, int voices);
42 static void _al_esd_exit(int input);
43 static int _al_esd_set_mixer_volume(int volume);
44 static int _al_esd_buffer_size(void);
45 
46 static char _al_esd_desc[256] = EMPTY_STRING;
47 
48 DIGI_DRIVER digi_esd =
49 {
50    DIGI_ESD,
51    empty_string,
52    empty_string,
53    "Enlightened Sound Daemon",
54    0,
55    0,
56    MIXER_MAX_SFX,
57    MIXER_DEF_SFX,
58 
59    _al_esd_detect,
60    _al_esd_init,
61    _al_esd_exit,
62    _al_esd_set_mixer_volume,
63    NULL,
64 
65    NULL,
66    NULL,
67    _al_esd_buffer_size,
68    _mixer_init_voice,
69    _mixer_release_voice,
70    _mixer_start_voice,
71    _mixer_stop_voice,
72    _mixer_loop_voice,
73 
74    _mixer_get_position,
75    _mixer_set_position,
76 
77    _mixer_get_volume,
78    _mixer_set_volume,
79    _mixer_ramp_volume,
80    _mixer_stop_volume_ramp,
81 
82    _mixer_get_frequency,
83    _mixer_set_frequency,
84    _mixer_sweep_frequency,
85    _mixer_stop_frequency_sweep,
86 
87    _mixer_get_pan,
88    _mixer_set_pan,
89    _mixer_sweep_pan,
90    _mixer_stop_pan_sweep,
91 
92    _mixer_set_echo,
93    _mixer_set_tremolo,
94    _mixer_set_vibrato,
95    0, 0,
96    0,
97    0,
98    0,
99    0,
100    0,
101    0
102 };
103 
104 
105 
106 /* _al_esd_buffer_size:
107  *  Returns the current DMA buffer size, for use by the audiostream code.
108  */
_al_esd_buffer_size(void)109 static int _al_esd_buffer_size(void)
110 {
111    return _al_esd_bufsize / (_al_esd_bits / 8) / (_al_esd_stereo ? 2 : 1);
112 }
113 
114 
115 
116 /* _al_esd_update:
117  *  Update data.
118  */
_al_esd_update(int threaded)119 static void _al_esd_update(int threaded)
120 {
121    fd_set wfds;
122    struct timeval timeout;
123 
124    FD_ZERO(&wfds);
125    FD_SET(_al_esd_fd, &wfds);
126    timeout.tv_sec = 0;
127    timeout.tv_usec = 0;
128 
129    if (select(_al_esd_fd+1, NULL, &wfds, NULL, &timeout) > 0) {
130       write(_al_esd_fd, _al_esd_bufdata, _al_esd_bufsize);
131       _mix_some_samples((uintptr_t) _al_esd_bufdata, 0, _al_esd_signed);
132    }
133 }
134 
135 
136 
137 /* _al_esd_detect:
138  *  Detect driver presence.
139  */
_al_esd_detect(int input)140 static int _al_esd_detect(int input)
141 {
142    int fd;
143    AL_CONST char *server;
144    char tmp1[128], tmp2[128], tmp3[16];
145    char s[256];
146 
147    if (input) {
148       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
149       return FALSE;
150    }
151 
152    /* We don't want esdlib to spawn ESD while we are detecting it.  */
153    putenv("ESD_NO_SPAWN=1");
154 
155    /* Get ESD server name.  */
156    server = get_config_string(uconvert_ascii("sound", tmp1),
157 			      uconvert_ascii("esd_server", tmp2),
158 			      uconvert_ascii("", tmp3));
159 
160    /* Try to open ESD server.  */
161    fd = esd_open_sound(uconvert_toascii(server, s));
162    if (fd < 0) {
163       uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("%s: can not open"),
164 		(ugetc(server) ? server : get_config_text("No server")));
165       return FALSE;
166    }
167 
168    esd_close(fd);
169    return TRUE;
170 }
171 
172 
173 
174 /* _al_esd_init:
175  *  ESD init routine.
176  */
_al_esd_init(int input,int voices)177 static int _al_esd_init(int input, int voices)
178 {
179    AL_CONST char *server;
180    char tmp1[128], tmp2[128], tmp3[16];
181    char s[256];
182 
183    if (input) {
184       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
185       return -1;
186    }
187 
188    server = get_config_string(uconvert_ascii("sound", tmp1),
189 			      uconvert_ascii("esd_server", tmp2),
190 			      uconvert_ascii("", tmp3));
191 
192    _al_esd_bits = (_sound_bits == 8) ? 8 : 16;
193    _al_esd_stereo = (_sound_stereo) ? 1 : 0;
194    _al_esd_rate = (_sound_freq > 0) ? _sound_freq : ESD_DEFAULT_RATE;
195    _al_esd_signed = 1;
196 
197    _al_esd_format = (((_al_esd_bits == 16) ? ESD_BITS16 : ESD_BITS8)
198 		     | (_al_esd_stereo ? ESD_STEREO : ESD_MONO)
199 		     | ESD_STREAM | ESD_PLAY);
200 
201    _al_esd_fd = esd_play_stream_fallback(_al_esd_format, _al_esd_rate,
202 					 uconvert_toascii(server, s), NULL);
203    if (_al_esd_fd < 0) {
204       uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("%s: can not open"),
205 		(ugetc(server) ? server : get_config_text("No server")));
206       return -1;
207    }
208 
209    _al_esd_bufsize = ESD_BUF_SIZE;
210    _al_esd_bufdata = _AL_MALLOC_ATOMIC(_al_esd_bufsize);
211    if (_al_esd_bufdata == 0) {
212       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer"));
213       close(_al_esd_fd);
214       return -1;
215    }
216 
217    digi_esd.voices = voices;
218 
219    if (_mixer_init(_al_esd_bufsize / (_al_esd_bits / 8), _al_esd_rate,
220 		   _al_esd_stereo, ((_al_esd_bits == 16) ? 1 : 0),
221 		   &digi_esd.voices) != 0) {
222       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer"));
223       _AL_FREE(_al_esd_bufdata);
224       _al_esd_bufdata = 0;
225       close(_al_esd_fd);
226       return -1;
227    }
228 
229    _mix_some_samples((uintptr_t) _al_esd_bufdata, 0, _al_esd_signed);
230 
231    /* Add audio interrupt.  */
232    _unix_bg_man->register_func(_al_esd_update);
233 
234    uszprintf(_al_esd_desc, sizeof(_al_esd_desc), get_config_text("%s: %d bits, %s, %d bps, %s"),
235 			  server, _al_esd_bits,
236 			  uconvert_ascii((_al_esd_signed ? "signed" : "unsigned"), tmp1), _al_esd_rate,
237 			  uconvert_ascii((_al_esd_stereo ? "stereo" : "mono"), tmp2));
238 
239    digi_driver->desc = _al_esd_desc;
240 
241    return 0;
242 }
243 
244 
245 
246 /* _al_esd_exit:
247  *  Shutdown ESD driver.
248  */
_al_esd_exit(int input)249 static void _al_esd_exit(int input)
250 {
251    if (input) {
252       return;
253    }
254 
255    _unix_bg_man->unregister_func(_al_esd_update);
256 
257    _AL_FREE(_al_esd_bufdata);
258    _al_esd_bufdata = 0;
259 
260    _mixer_exit();
261 
262    close(_al_esd_fd);
263 }
264 
265 
266 
267 /* _al_esd_set_mixer_volume:
268  *  Set mixer volume.
269  */
_al_esd_set_mixer_volume(int volume)270 static int _al_esd_set_mixer_volume(int volume)
271 {
272    return 0;
273 }
274 
275 
276 
277 #ifdef ALLEGRO_MODULE
278 
279 /* _module_init:
280  *  Called when loaded as a dynamically linked module.
281  */
_module_init(int system_driver)282 void _module_init(int system_driver)
283 {
284    _unix_register_digi_driver(DIGI_ESD, &digi_esd, TRUE, TRUE);
285 }
286 
287 #endif
288 
289 #endif
290 
291