1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Jack sound driver.
12  *
13  *      By Elias Pschernig.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include "allegro.h"
20 
21 #if (defined ALLEGRO_WITH_JACKDIGI) && ((!defined ALLEGRO_WITH_MODULES) || (defined ALLEGRO_MODULE))
22 
23 #include "allegro/internal/aintern.h"
24 #include "allegro/platform/aintunix.h"
25 
26 #ifndef SCAN_DEPEND
27    #include <jack/jack.h>
28 #endif
29 
30 /* This still uses Allegro's mixer, and mixes into an intermediate buffer, which
31  * then is transferred to Jack. Another possibility would be to completely
32  * circumvent Allegro's mixer and send each single voice to jack, letting Jack
33  * take care of the mixing. I didn't care about some things in the Jack docs,
34  * like the possibility of buffer sizes changing, or that no mutex_lock function
35  * should be called (inside mix_some_samples).
36  */
37 #define JACK_DEFAULT_BUFFER_SIZE -1
38 #define JACK_DEFAULT_CLIENT_NAME "allegro"
39 #define AMP16 ((sample_t) 32768)
40 #define AMP8 ((sample_t) 128)
41 
42 #define PREFIX_I                "al-jack INFO: "
43 #define PREFIX_W                "al-jack WARNING: "
44 #define PREFIX_E                "al-jack ERROR: "
45 
46 typedef jack_default_audio_sample_t sample_t;
47 
48 static int jack_bufsize = JACK_DEFAULT_BUFFER_SIZE;
49 static char const *jack_client_name = JACK_DEFAULT_CLIENT_NAME;
50 static int jack_16bit;
51 static int jack_stereo;
52 static int jack_signed;
53 static jack_nframes_t jack_rate;
54 static char jack_desc[256] = EMPTY_STRING;
55 static jack_client_t *jack_client = NULL;
56 static jack_port_t *output_left, *output_right;
57 static void *jack_buffer;
58 
59 static int jack_detect(int input);
60 static int jack_init(int input, int voices);
61 static void jack_exit(int input);
62 static int jack_buffer_size(void);
63 static int jack_set_mixer_volume(int volume);
64 
65 DIGI_DRIVER digi_jack =
66 {
67    DIGI_JACK,
68    empty_string,
69    empty_string,
70    "JACK",
71    0,
72    0,
73    MIXER_MAX_SFX,
74    MIXER_DEF_SFX,
75 
76    jack_detect,
77    jack_init,
78    jack_exit,
79    jack_set_mixer_volume,
80    NULL,
81 
82    NULL,
83    NULL,
84    jack_buffer_size,
85    _mixer_init_voice,
86    _mixer_release_voice,
87    _mixer_start_voice,
88    _mixer_stop_voice,
89    _mixer_loop_voice,
90 
91    _mixer_get_position,
92    _mixer_set_position,
93 
94    _mixer_get_volume,
95    _mixer_set_volume,
96    _mixer_ramp_volume,
97    _mixer_stop_volume_ramp,
98 
99    _mixer_get_frequency,
100    _mixer_set_frequency,
101    _mixer_sweep_frequency,
102    _mixer_stop_frequency_sweep,
103 
104    _mixer_get_pan,
105    _mixer_set_pan,
106    _mixer_sweep_pan,
107    _mixer_stop_pan_sweep,
108 
109    _mixer_set_echo,
110    _mixer_set_tremolo,
111    _mixer_set_vibrato,
112    0, 0,
113    0,
114    0,
115    0,
116    0,
117    0,
118    0
119 };
120 
121 
122 
123 /* jack_buffer_size:
124  *  Returns the current buffer size, for use by the audiostream code.
125  */
jack_buffer_size(void)126 static int jack_buffer_size(void)
127 {
128    return jack_bufsize;
129 }
130 
131 
132 
133 /* jack_process:
134  *  The JACK processing functions.
135  */
jack_process(jack_nframes_t nframes,void * arg)136 static int jack_process (jack_nframes_t nframes, void *arg)
137 {
138    jack_nframes_t i;
139    /* TODO: Should be uint16_t and uint8_t? Endianess? */
140    unsigned short *buffer16 = jack_buffer;
141    unsigned char *buffer8 = jack_buffer;
142    jack_default_audio_sample_t *out_left;
143 
144    _mix_some_samples((uintptr_t) jack_buffer, 0, jack_signed);
145 
146    out_left = (jack_default_audio_sample_t *)
147       jack_port_get_buffer (output_left, nframes);
148 
149    if (jack_stereo) {
150       jack_default_audio_sample_t *out_right = (jack_default_audio_sample_t *)
151 	 jack_port_get_buffer (output_right, nframes);
152 
153       if (jack_16bit) {
154 	 for (i = 0; i < nframes; i++) {
155 	    out_left[i] = ((sample_t) buffer16[i * 2] - AMP16) / AMP16;
156 	    out_right[i] = ((sample_t) buffer16[i * 2 + 1] - AMP16) / AMP16;
157 	 }
158       }
159       else {
160 	 for (i = 0; i < nframes; i++) {
161 	    out_left[i] = ((sample_t) buffer8[i * 2] - AMP8) / (sample_t) AMP8;
162 	    out_right[i] = ((sample_t) buffer8[i * 2 + 1] - AMP8) / (sample_t) AMP8;
163 	 }
164       }
165    }
166    else
167    {
168       if (jack_16bit) {
169 	 for (i = 0; i < nframes; i++) {
170 	    out_left[i] = ((sample_t) buffer16[i] - AMP16) / AMP16;
171 	 }
172       }
173       else {
174 	 for (i = 0; i < nframes; i++) {
175 	    out_left[i] = ((sample_t) buffer8[i] - AMP8) / AMP8;
176 	 }
177       }
178    }
179 
180    return 0;
181 }
182 
183 
184 
185 /* jack_detect:
186  *  Detects driver presence.
187  */
jack_detect(int input)188 static int jack_detect(int input)
189 {
190    if (input) {
191       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text(
192          "Input is not supported"));
193       return FALSE;
194    }
195 
196    if (!jack_client)
197    {
198       jack_client_name = get_config_string("sound", "jack_client_name",
199 	 jack_client_name);
200       jack_client = jack_client_new(jack_client_name);
201       if (!jack_client)
202 	 return FALSE;
203    }
204    return TRUE;
205 }
206 
207 
208 
209 /* jack_init:
210  *  JACK init routine.
211  */
jack_init(int input,int voices)212 static int jack_init(int input, int voices)
213 {
214    const char **ports;
215    char tmp[128];
216 
217    if (!jack_detect(input))
218       return -1;
219 
220    jack_bufsize = get_config_int("sound", "jack_buffer_size",
221       jack_bufsize);
222 
223    if (jack_bufsize == -1)
224       jack_bufsize = jack_get_buffer_size (jack_client);
225 
226    /* Those are already read in from the config file by Allegro. */
227    jack_16bit = (_sound_bits == 16 ? 1 : 0);
228    jack_stereo = (_sound_stereo ? 1 : 0);
229 
230    /* Let Allegro mix in its native unsigned format. */
231    jack_signed = 0;
232 
233    jack_set_process_callback (jack_client, jack_process, NULL);
234 
235    output_left = jack_port_register (jack_client, jack_stereo ? "left" : "mono",
236       JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
237 
238    if (jack_stereo)
239       output_right = jack_port_register (jack_client, "right",
240          JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
241 
242    jack_rate = jack_get_sample_rate (jack_client);
243 
244    jack_buffer = _AL_MALLOC_ATOMIC(jack_bufsize * (1 + jack_16bit) * (1 + jack_stereo));
245    if (!jack_buffer) {
246       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text(
247          "Cannot allocate audio buffer"));
248       jack_exit (input);
249       return -1;
250    }
251 
252    digi_jack.voices = voices;
253 
254    if (_mixer_init(jack_bufsize *  (1 + jack_stereo), jack_rate,
255       jack_stereo, jack_16bit, &digi_jack.voices)) {
256       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text(
257          "Cannot init software mixer"));
258       jack_exit (input);
259       return -1;
260    }
261 
262    _mix_some_samples((uintptr_t) jack_buffer, 0, jack_signed);
263 
264    if (jack_activate (jack_client)) {
265       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text(
266          "Cannot activate Jack client"));
267       jack_exit (input);
268       return 1;
269    }
270 
271    /* Try to connect the ports. Failure to connect is not critical, since with
272     * JACK, users may connect/disconnect ports anytime, without Allegro caring.
273     */
274    if ((ports = jack_get_ports (jack_client, NULL, NULL,
275       JackPortIsPhysical|JackPortIsInput)) == NULL) {
276       TRACE (PREFIX_I "Cannot find any physical playback ports");
277    }
278 
279    if (ports) {
280       if (ports[0]) {
281 	 if (jack_connect (jack_client, jack_port_name (output_left), ports[0]) == 0)
282 	    TRACE (PREFIX_I "Connected left playback port to %s", ports[0]);
283       }
284       if (jack_stereo && ports[1]) {
285 	 if (jack_connect (jack_client, jack_port_name (output_right), ports[1]) == 0)
286 	    TRACE (PREFIX_I "Connected right playback port to %s", ports[1]);
287       }
288       _AL_FREE (ports);
289    }
290 
291    uszprintf(jack_desc, sizeof(jack_desc),
292       get_config_text ("Jack, client '%s': %d bits, %s, %d bps, %s"),
293       jack_client_name, jack_16bit ? 16 : 8,
294       uconvert_ascii((jack_signed ? "signed" : "unsigned"), tmp),
295       jack_rate, uconvert_ascii((jack_stereo ? "stereo" : "mono"), tmp));
296 
297    return 0;
298 }
299 
300 
301 
302 /* jack_exit:
303  *  Shuts down the JACK driver.
304  */
jack_exit(int input)305 static void jack_exit(int input)
306 {
307    jack_client_close (jack_client);
308    jack_client = NULL;
309 }
310 
311 
312 
313 /* jack_set_mixer_volume:
314  *  Set mixer volume (0-255)
315  */
jack_set_mixer_volume(int volume)316 static int jack_set_mixer_volume(int volume)
317 {
318    /* Not implemented */
319    return 0;
320 }
321 
322 
323 
324 #ifdef ALLEGRO_MODULE
325 
326 /* _module_init:
327  *  Called when loaded as a dynamically linked module.
328  */
_module_init(int system_driver)329 void _module_init(int system_driver)
330 {
331    _unix_register_digi_driver(DIGI_JACK, &digi_jack, TRUE, TRUE);
332 }
333 
334 #endif
335 
336 #endif
337