1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Sample audio interface.
12  *
13  *      By Peter Wang.
14  *
15  *      See LICENSE.txt for copyright information.
16  */
17 
18 /* Title: Sample audio interface
19  */
20 
21 #include "allegro5/allegro.h"
22 #include "allegro5/allegro_audio.h"
23 #include "allegro5/internal/aintern.h"
24 #include "allegro5/internal/aintern_audio.h"
25 #include "allegro5/internal/aintern_vector.h"
26 
27 ALLEGRO_DEBUG_CHANNEL("audio")
28 
29 
30 static ALLEGRO_VOICE *allegro_voice = NULL;
31 static ALLEGRO_MIXER *allegro_mixer = NULL;
32 static ALLEGRO_MIXER *default_mixer = NULL;
33 
34 
35 typedef struct AUTO_SAMPLE {
36    ALLEGRO_SAMPLE_INSTANCE *instance;
37    int id;
38    bool locked;
39 } AUTO_SAMPLE;
40 
41 static _AL_VECTOR auto_samples = _AL_VECTOR_INITIALIZER(AUTO_SAMPLE);
42 
43 
44 static bool create_default_mixer(void);
45 static bool do_play_sample(ALLEGRO_SAMPLE_INSTANCE *spl, ALLEGRO_SAMPLE *data,
46       float gain, float pan, float speed, ALLEGRO_PLAYMODE loop);
47 static void free_sample_vector(void);
48 
49 
string_to_depth(const char * s)50 static int string_to_depth(const char *s)
51 {
52    // FIXME: fill in the rest
53    if (!_al_stricmp(s, "int16")) {
54       return ALLEGRO_AUDIO_DEPTH_INT16;
55    }
56    else {
57       return ALLEGRO_AUDIO_DEPTH_FLOAT32;
58    }
59 }
60 
61 
62 /* Creates the default voice and mixer if they haven't been created yet. */
create_default_mixer(void)63 static bool create_default_mixer(void)
64 {
65    int voice_frequency = 44100;
66    int voice_depth = ALLEGRO_AUDIO_DEPTH_INT16;
67    int mixer_frequency = 44100;
68    int mixer_depth = ALLEGRO_AUDIO_DEPTH_FLOAT32;
69 
70    ALLEGRO_CONFIG *config = al_get_system_config();
71    const char *p;
72    p = al_get_config_value(config, "audio", "primary_voice_frequency");
73    if (p && p[0] != '\0') {
74       voice_frequency = atoi(p);
75    }
76    p = al_get_config_value(config, "audio", "primary_mixer_frequency");
77    if (p && p[0] != '\0') {
78       mixer_frequency = atoi(p);
79    }
80    p = al_get_config_value(config, "audio", "primary_voice_depth");
81    if (p && p[0] != '\0') {
82       voice_depth = string_to_depth(p);
83    }
84    p = al_get_config_value(config, "audio", "primary_mixer_depth");
85    if (p && p[0] != '\0') {
86       mixer_depth = string_to_depth(p);
87    }
88 
89    if (!allegro_voice) {
90       allegro_voice = al_create_voice(voice_frequency, voice_depth,
91          ALLEGRO_CHANNEL_CONF_2);
92       if (!allegro_voice) {
93          ALLEGRO_ERROR("al_create_voice failed\n");
94          goto Error;
95       }
96    }
97 
98    if (!allegro_mixer) {
99       allegro_mixer = al_create_mixer(mixer_frequency, mixer_depth,
100          ALLEGRO_CHANNEL_CONF_2);
101       if (!allegro_mixer) {
102          ALLEGRO_ERROR("al_create_voice failed\n");
103          goto Error;
104       }
105    }
106 
107    /* In case this function is called multiple times. */
108    al_detach_mixer(allegro_mixer);
109 
110    if (!al_attach_mixer_to_voice(allegro_mixer, allegro_voice)) {
111       ALLEGRO_ERROR("al_attach_mixer_to_voice failed\n");
112       goto Error;
113    }
114 
115    return true;
116 
117 Error:
118 
119    if (allegro_mixer) {
120       al_destroy_mixer(allegro_mixer);
121       allegro_mixer = NULL;
122    }
123 
124    if (allegro_voice) {
125       al_destroy_voice(allegro_voice);
126       allegro_voice = NULL;
127    }
128 
129    return false;
130 }
131 
132 
133 /* Function: al_create_sample
134  */
al_create_sample(void * buf,unsigned int samples,unsigned int freq,ALLEGRO_AUDIO_DEPTH depth,ALLEGRO_CHANNEL_CONF chan_conf,bool free_buf)135 ALLEGRO_SAMPLE *al_create_sample(void *buf, unsigned int samples,
136    unsigned int freq, ALLEGRO_AUDIO_DEPTH depth,
137    ALLEGRO_CHANNEL_CONF chan_conf, bool free_buf)
138 {
139    ALLEGRO_SAMPLE *spl;
140 
141    ASSERT(buf);
142 
143    if (!freq) {
144       _al_set_error(ALLEGRO_INVALID_PARAM, "Invalid sample frequency");
145       return NULL;
146    }
147 
148    spl = al_calloc(1, sizeof(*spl));
149    if (!spl) {
150       _al_set_error(ALLEGRO_GENERIC_ERROR,
151          "Out of memory allocating sample data object");
152       return NULL;
153    }
154 
155    spl->depth = depth;
156    spl->chan_conf = chan_conf;
157    spl->frequency = freq;
158    spl->len = samples;
159    spl->buffer.ptr = buf;
160    spl->free_buf = free_buf;
161 
162    spl->dtor_item = _al_kcm_register_destructor("sample", spl, (void (*)(void *)) al_destroy_sample);
163 
164    return spl;
165 }
166 
167 
168 /* Stop any sample instances which are still playing a sample buffer which
169  * is about to be destroyed.
170  */
stop_sample_instances_helper(void * object,void (* func)(void *),void * userdata)171 static void stop_sample_instances_helper(void *object, void (*func)(void *),
172    void *userdata)
173 {
174    ALLEGRO_SAMPLE_INSTANCE *splinst = object;
175 
176    /* This is ugly. */
177    if (func == (void (*)(void *)) al_destroy_sample_instance
178       && al_get_sample_data(al_get_sample(splinst)) == userdata
179       && al_get_sample_instance_playing(splinst))
180    {
181       al_stop_sample_instance(splinst);
182    }
183 }
184 
185 
186 /* Function: al_destroy_sample
187  */
al_destroy_sample(ALLEGRO_SAMPLE * spl)188 void al_destroy_sample(ALLEGRO_SAMPLE *spl)
189 {
190    if (spl) {
191       _al_kcm_foreach_destructor(stop_sample_instances_helper,
192          al_get_sample_data(spl));
193       _al_kcm_unregister_destructor(spl->dtor_item);
194 
195       if (spl->free_buf && spl->buffer.ptr) {
196          al_free(spl->buffer.ptr);
197       }
198       spl->buffer.ptr = NULL;
199       spl->free_buf = false;
200       al_free(spl);
201    }
202 }
203 
204 
205 /* Function: al_reserve_samples
206  */
al_reserve_samples(int reserve_samples)207 bool al_reserve_samples(int reserve_samples)
208 {
209    int i;
210    int current_samples_count = (int) _al_vector_size(&auto_samples);
211 
212    ASSERT(reserve_samples >= 0);
213 
214    /* If no default mixer has been set by the user, then create a voice
215     * and a mixer, and set them to be the default one for use with
216     * al_play_sample().
217     */
218    if (default_mixer == NULL) {
219       if (!al_restore_default_mixer())
220          goto Error;
221    }
222 
223    if (current_samples_count < reserve_samples) {
224       /* We need to reserve more samples than currently are reserved. */
225       for (i = 0; i < reserve_samples - current_samples_count; i++) {
226          AUTO_SAMPLE *slot = _al_vector_alloc_back(&auto_samples);
227          slot->id = 0;
228          slot->instance = al_create_sample_instance(NULL);
229          slot->locked = false;
230          if (!slot->instance) {
231             ALLEGRO_ERROR("al_create_sample failed\n");
232             goto Error;
233          }
234          if (!al_attach_sample_instance_to_mixer(slot->instance, default_mixer)) {
235             ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n");
236             goto Error;
237          }
238       }
239    }
240    else if (current_samples_count > reserve_samples) {
241       /* We need to reserve fewer samples than currently are reserved. */
242       while (current_samples_count-- > reserve_samples) {
243          AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, current_samples_count);
244          al_destroy_sample_instance(slot->instance);
245          _al_vector_delete_at(&auto_samples, current_samples_count);
246       }
247    }
248 
249    return true;
250 
251  Error:
252    free_sample_vector();
253 
254    return false;
255 }
256 
257 
258 /* Function: al_get_default_mixer
259  */
al_get_default_mixer(void)260 ALLEGRO_MIXER *al_get_default_mixer(void)
261 {
262    return default_mixer;
263 }
264 
265 
266 /* Function: al_set_default_mixer
267  */
al_set_default_mixer(ALLEGRO_MIXER * mixer)268 bool al_set_default_mixer(ALLEGRO_MIXER *mixer)
269 {
270    ASSERT(mixer != NULL);
271 
272    if (mixer != default_mixer) {
273       int i;
274 
275       default_mixer = mixer;
276 
277       /* Destroy all current sample instances, recreate them, and
278        * attach them to the new mixer */
279       for (i = 0; i < (int) _al_vector_size(&auto_samples); i++) {
280          AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i);
281 
282          slot->id = 0;
283          al_destroy_sample_instance(slot->instance);
284          slot->locked = false;
285 
286          slot->instance = al_create_sample_instance(NULL);
287          if (!slot->instance) {
288             ALLEGRO_ERROR("al_create_sample failed\n");
289             goto Error;
290          }
291          if (!al_attach_sample_instance_to_mixer(slot->instance, default_mixer)) {
292             ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n");
293             goto Error;
294          }
295       }
296    }
297 
298    return true;
299 
300 Error:
301    free_sample_vector();
302    default_mixer = NULL;
303    return false;
304 }
305 
306 
307 /* Function: al_restore_default_mixer
308  */
al_restore_default_mixer(void)309 bool al_restore_default_mixer(void)
310 {
311    if (!create_default_mixer())
312       return false;
313 
314    if (!al_set_default_mixer(allegro_mixer))
315       return false;
316 
317    return true;
318 }
319 
320 
321 /* Function: al_get_default_voice
322  */
al_get_default_voice(void)323 ALLEGRO_VOICE *al_get_default_voice(void)
324 {
325    return allegro_voice;
326 }
327 
328 
329 /* Function: al_set_default_voice
330  */
al_set_default_voice(ALLEGRO_VOICE * voice)331 void al_set_default_voice(ALLEGRO_VOICE *voice)
332 {
333    if (allegro_voice) {
334       al_destroy_voice(allegro_voice);
335    }
336    allegro_voice = voice;
337 }
338 
339 
340 /* Function: al_play_sample
341  */
al_play_sample(ALLEGRO_SAMPLE * spl,float gain,float pan,float speed,ALLEGRO_PLAYMODE loop,ALLEGRO_SAMPLE_ID * ret_id)342 bool al_play_sample(ALLEGRO_SAMPLE *spl, float gain, float pan, float speed,
343    ALLEGRO_PLAYMODE loop, ALLEGRO_SAMPLE_ID *ret_id)
344 {
345    static int next_id = 0;
346    unsigned int i;
347 
348    ASSERT(spl);
349 
350    if (ret_id != NULL) {
351       ret_id->_id = -1;
352       ret_id->_index = 0;
353    }
354 
355    for (i = 0; i < _al_vector_size(&auto_samples); i++) {
356       AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i);
357 
358       if (!al_get_sample_instance_playing(slot->instance) && !slot->locked) {
359          if (!do_play_sample(slot->instance, spl, gain, pan, speed, loop))
360             break;
361 
362          if (ret_id != NULL) {
363             ret_id->_index = (int) i;
364             ret_id->_id = slot->id = ++next_id;
365          }
366 
367          return true;
368       }
369    }
370 
371    return false;
372 }
373 
374 
do_play_sample(ALLEGRO_SAMPLE_INSTANCE * splinst,ALLEGRO_SAMPLE * spl,float gain,float pan,float speed,ALLEGRO_PLAYMODE loop)375 static bool do_play_sample(ALLEGRO_SAMPLE_INSTANCE *splinst,
376    ALLEGRO_SAMPLE *spl, float gain, float pan, float speed, ALLEGRO_PLAYMODE loop)
377 {
378    if (!al_set_sample(splinst, spl)) {
379       ALLEGRO_ERROR("al_set_sample failed\n");
380       return false;
381    }
382 
383    if (!al_set_sample_instance_gain(splinst, gain) ||
384          !al_set_sample_instance_pan(splinst, pan) ||
385          !al_set_sample_instance_speed(splinst, speed) ||
386          !al_set_sample_instance_playmode(splinst, loop)) {
387       return false;
388    }
389 
390    if (!al_play_sample_instance(splinst)) {
391       ALLEGRO_ERROR("al_play_sample_instance failed\n");
392       return false;
393    }
394 
395    return true;
396 }
397 
398 
399 /* Function: al_stop_sample
400  */
al_stop_sample(ALLEGRO_SAMPLE_ID * spl_id)401 void al_stop_sample(ALLEGRO_SAMPLE_ID *spl_id)
402 {
403    AUTO_SAMPLE *slot;
404 
405    ASSERT(spl_id->_id != -1);
406    ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples));
407 
408    slot = _al_vector_ref(&auto_samples, spl_id->_index);
409    if (slot->id == spl_id->_id) {
410       al_stop_sample_instance(slot->instance);
411    }
412 }
413 
414 
415 /* Function: al_lock_sample_id
416  */
al_lock_sample_id(ALLEGRO_SAMPLE_ID * spl_id)417 ALLEGRO_SAMPLE_INSTANCE* al_lock_sample_id(ALLEGRO_SAMPLE_ID *spl_id)
418 {
419    AUTO_SAMPLE *slot;
420 
421    ASSERT(spl_id->_id != -1);
422    ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples));
423 
424    slot = _al_vector_ref(&auto_samples, spl_id->_index);
425    if (slot->id == spl_id->_id) {
426       slot->locked = true;
427       return slot->instance;
428    }
429    return NULL;
430 }
431 
432 
433 /* Function: al_unlock_sample_id
434  */
al_unlock_sample_id(ALLEGRO_SAMPLE_ID * spl_id)435 void al_unlock_sample_id(ALLEGRO_SAMPLE_ID *spl_id)
436 {
437    AUTO_SAMPLE *slot;
438 
439    ASSERT(spl_id->_id != -1);
440    ASSERT(spl_id->_index < (int) _al_vector_size(&auto_samples));
441 
442    slot = _al_vector_ref(&auto_samples, spl_id->_index);
443    if (slot->id == spl_id->_id) {
444       slot->locked = false;
445    }
446 }
447 
448 
449 /* Function: al_stop_samples
450  */
al_stop_samples(void)451 void al_stop_samples(void)
452 {
453    unsigned int i;
454 
455    for (i = 0; i < _al_vector_size(&auto_samples); i++) {
456       AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i);
457       al_stop_sample_instance(slot->instance);
458    }
459 }
460 
461 
462 /* Function: al_get_sample_frequency
463  */
al_get_sample_frequency(const ALLEGRO_SAMPLE * spl)464 unsigned int al_get_sample_frequency(const ALLEGRO_SAMPLE *spl)
465 {
466    ASSERT(spl);
467 
468    return spl->frequency;
469 }
470 
471 
472 /* Function: al_get_sample_length
473  */
al_get_sample_length(const ALLEGRO_SAMPLE * spl)474 unsigned int al_get_sample_length(const ALLEGRO_SAMPLE *spl)
475 {
476    ASSERT(spl);
477 
478    return spl->len;
479 }
480 
481 
482 /* Function: al_get_sample_depth
483  */
al_get_sample_depth(const ALLEGRO_SAMPLE * spl)484 ALLEGRO_AUDIO_DEPTH al_get_sample_depth(const ALLEGRO_SAMPLE *spl)
485 {
486    ASSERT(spl);
487 
488    return spl->depth;
489 }
490 
491 
492 /* Function: al_get_sample_channels
493  */
al_get_sample_channels(const ALLEGRO_SAMPLE * spl)494 ALLEGRO_CHANNEL_CONF al_get_sample_channels(const ALLEGRO_SAMPLE *spl)
495 {
496    ASSERT(spl);
497 
498    return spl->chan_conf;
499 }
500 
501 
502 /* Function: al_get_sample_data
503  */
al_get_sample_data(const ALLEGRO_SAMPLE * spl)504 void *al_get_sample_data(const ALLEGRO_SAMPLE *spl)
505 {
506    ASSERT(spl);
507 
508    return spl->buffer.ptr;
509 }
510 
511 
512 /* Destroy all sample instances, and frees the associated vectors. */
free_sample_vector(void)513 static void free_sample_vector(void)
514 {
515    int j;
516 
517    for (j = 0; j < (int) _al_vector_size(&auto_samples); j++) {
518       AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, j);
519       al_destroy_sample_instance(slot->instance);
520    }
521    _al_vector_free(&auto_samples);
522 }
523 
524 
_al_kcm_shutdown_default_mixer(void)525 void _al_kcm_shutdown_default_mixer(void)
526 {
527    free_sample_vector();
528    al_destroy_mixer(allegro_mixer);
529    al_destroy_voice(allegro_voice);
530 
531    allegro_mixer = NULL;
532    allegro_voice = NULL;
533    default_mixer = NULL;
534 }
535 
536 
537 /* vim: set sts=3 sw=3 et: */
538