1 /**
2  * Originally digi.c from allegro wiki
3  * Original authors: KC/Milan
4  *
5  * Converted to allegro5 by Ryan Dickie
6  */
7 
8 /* Title: Mixer functions
9  */
10 
11 #include <math.h>
12 #include <stdio.h>
13 
14 #include "allegro5/allegro_audio.h"
15 #include "allegro5/internal/aintern.h"
16 #include "allegro5/internal/aintern_audio.h"
17 #include "allegro5/internal/aintern_audio_cfg.h"
18 
19 ALLEGRO_DEBUG_CHANNEL("audio")
20 
21 
22 typedef union {
23    float f32[ALLEGRO_MAX_CHANNELS]; /* max: 7.1 */
24    int16_t s16[ALLEGRO_MAX_CHANNELS];
25    void *ptr;
26 } SAMP_BUF;
27 
28 
29 
maybe_lock_mutex(ALLEGRO_MUTEX * mutex)30 static void maybe_lock_mutex(ALLEGRO_MUTEX *mutex)
31 {
32    if (mutex) {
33       al_lock_mutex(mutex);
34    }
35 }
36 
37 
maybe_unlock_mutex(ALLEGRO_MUTEX * mutex)38 static void maybe_unlock_mutex(ALLEGRO_MUTEX *mutex)
39 {
40    if (mutex) {
41       al_unlock_mutex(mutex);
42    }
43 }
44 
45 
46 /* _al_rechannel_matrix:
47  *  This function provides a (temporary!) matrix that can be used to convert
48  *  one channel configuration into another.
49  *
50  *  Returns a pointer to a statically allocated array.
51  */
_al_rechannel_matrix(ALLEGRO_CHANNEL_CONF orig,ALLEGRO_CHANNEL_CONF target,float gain,float pan)52 static float *_al_rechannel_matrix(ALLEGRO_CHANNEL_CONF orig,
53    ALLEGRO_CHANNEL_CONF target, float gain, float pan)
54 {
55    /* Max 7.1 (8 channels) for input and output */
56    static float mat[ALLEGRO_MAX_CHANNELS][ALLEGRO_MAX_CHANNELS];
57 
58    size_t dst_chans = al_get_channel_count(target);
59    size_t src_chans = al_get_channel_count(orig);
60    size_t i, j;
61 
62    /* Start with a simple identity matrix */
63    memset(mat, 0, sizeof(mat));
64    for (i = 0; i < src_chans && i < dst_chans; i++) {
65       mat[i][i] = 1.0;
66    }
67 
68    /* Multi-channel -> mono conversion (cuts rear/side channels) */
69    if (dst_chans == 1 && (orig>>4) > 1) {
70       for (i = 0; i < 2; i++) {
71          mat[0][i] = 1.0 / sqrt(2.0);
72       }
73 
74       /* If the source has a center channel, make sure that's copied 1:1
75        * (perhaps it should scale the overall output?)
76        */
77       if ((orig >> 4) & 1) {
78          mat[0][(orig >> 4) - 1] = 1.0;
79       }
80    }
81    /* Center (or mono) -> front l/r conversion */
82    else if (((orig >> 4) & 1) && !((target >> 4) & 1)) {
83       mat[0][(orig >> 4) - 1] = 1.0 / sqrt(2.0);
84       mat[1][(orig >> 4) - 1] = 1.0 / sqrt(2.0);
85    }
86 
87    /* Copy LFE */
88    if ((orig >> 4) != (target >> 4) &&
89       (orig & 0xF) && (target & 0xF))
90    {
91       mat[dst_chans-1][src_chans-1] = 1.0;
92    }
93 
94    /* Apply panning, which is supposed to maintain a constant power level.
95     * I took that to mean we want:
96     *    sqrt(rgain^2 + lgain^2) = 1.0
97     */
98    if (pan != ALLEGRO_AUDIO_PAN_NONE) {
99       float rgain = sqrt(( pan + 1.0f) / 2.0f);
100       float lgain = sqrt((-pan + 1.0f) / 2.0f);
101 
102       /* I dunno what to do about >2 channels, so don't even try for now. */
103       for (j = 0; j < src_chans; j++) {
104          mat[0][j] *= lgain;
105          mat[1][j] *= rgain;
106       }
107    }
108 
109    /* Apply gain */
110    if (gain != 1.0f) {
111       for (i = 0; i < dst_chans; i++) {
112          for (j = 0; j < src_chans; j++) {
113             mat[i][j] *= gain;
114          }
115       }
116    }
117 
118 #ifdef DEBUGMODE
119    {
120       char debug[1024];
121       ALLEGRO_DEBUG("sample matrix:\n");
122       for (i = 0; i < dst_chans; i++) {
123          strcpy(debug, "");
124          for (j = 0; j < src_chans; j++) {
125             sprintf(debug + strlen(debug), " %f", mat[i][j]);
126          }
127          ALLEGRO_DEBUG("%s\n", debug);
128       }
129    }
130 #endif
131 
132    return &mat[0][0];
133 }
134 
135 
136 /* _al_kcm_mixer_rejig_sample_matrix:
137  *  Recompute the mixing matrix for a sample attached to a mixer.
138  *  The caller must be holding the mixer mutex.
139  */
_al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER * mixer,ALLEGRO_SAMPLE_INSTANCE * spl)140 void _al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER *mixer,
141    ALLEGRO_SAMPLE_INSTANCE *spl)
142 {
143    float *mat;
144    size_t dst_chans;
145    size_t src_chans;
146    size_t i, j;
147 
148    mat = _al_rechannel_matrix(spl->spl_data.chan_conf,
149       mixer->ss.spl_data.chan_conf, spl->gain, spl->pan);
150 
151    dst_chans = al_get_channel_count(mixer->ss.spl_data.chan_conf);
152    src_chans = al_get_channel_count(spl->spl_data.chan_conf);
153 
154    if (!spl->matrix)
155       spl->matrix = al_calloc(1, src_chans * dst_chans * sizeof(float));
156 
157    for (i = 0; i < dst_chans; i++) {
158       for (j = 0; j < src_chans; j++) {
159          spl->matrix[i*src_chans + j] = mat[i*ALLEGRO_MAX_CHANNELS + j];
160       }
161    }
162 }
163 
164 
165 /* fix_looped_position:
166  *  When a stream loops, this will fix up the position and anything else to
167  *  allow it to safely continue playing as expected. Returns false if it
168  *  should stop being mixed.
169  */
fix_looped_position(ALLEGRO_SAMPLE_INSTANCE * spl)170 static bool fix_looped_position(ALLEGRO_SAMPLE_INSTANCE *spl)
171 {
172    bool is_empty;
173    ALLEGRO_AUDIO_STREAM *stream;
174 
175    /* Looping! Should be mostly self-explanatory */
176    switch (spl->loop) {
177       case ALLEGRO_PLAYMODE_LOOP:
178          if (spl->loop_end - spl->loop_start != 0) {
179             if (spl->step > 0) {
180                while (spl->pos >= spl->loop_end) {
181                   spl->pos -= (spl->loop_end - spl->loop_start);
182                }
183             }
184             else if (spl->step < 0) {
185                while (spl->pos < spl->loop_start) {
186                   spl->pos += (spl->loop_end - spl->loop_start);
187                }
188             }
189          }
190          return true;
191 
192       case ALLEGRO_PLAYMODE_BIDIR:
193          /* When doing bi-directional looping, you need to do a follow-up
194           * check for the opposite direction if a loop occurred, otherwise
195           * you could end up misplaced on small, high-step loops.
196           */
197          if (spl->loop_end - spl->loop_start != 0) {
198             if (spl->step >= 0) {
199             check_forward:
200                if (spl->pos >= spl->loop_end) {
201                   spl->step = -spl->step;
202                   spl->pos = spl->loop_end - (spl->pos - spl->loop_end) - 1;
203                   goto check_backward;
204                }
205             }
206             else {
207             check_backward:
208                if (spl->pos < spl->loop_start || spl->pos >= spl->loop_end) {
209                   spl->step = -spl->step;
210                   spl->pos = spl->loop_start + (spl->loop_start - spl->pos);
211                   goto check_forward;
212                }
213             }
214          }
215          return true;
216 
217       case ALLEGRO_PLAYMODE_ONCE:
218          if (spl->pos < spl->spl_data.len && spl->pos >= 0) {
219             return true;
220          }
221          if (spl->step >= 0)
222             spl->pos = 0;
223          else
224             spl->pos = spl->spl_data.len - 1;
225          spl->is_playing = false;
226          return false;
227 
228       case _ALLEGRO_PLAYMODE_STREAM_ONCE:
229       case _ALLEGRO_PLAYMODE_STREAM_ONEDIR:
230          stream = (ALLEGRO_AUDIO_STREAM *)spl;
231          is_empty = false;
232          while (spl->pos >= spl->spl_data.len && stream->spl.is_playing && !is_empty) {
233             is_empty = !_al_kcm_refill_stream(stream);
234             if (is_empty && stream->is_draining) {
235                stream->spl.is_playing = false;
236             }
237 
238             _al_kcm_emit_stream_events(stream);
239          }
240          return !(is_empty);
241    }
242 
243    ASSERT(false);
244    return false;
245 }
246 
247 
248 #include "kcm_mixer_helpers.inc"
249 
250 
clamp(int32_t val,int32_t min,int32_t max)251 static INLINE int32_t clamp(int32_t val, int32_t min, int32_t max)
252 {
253    /* Clamp to min */
254    val -= min;
255    val &= (~val) >> 31;
256    val += min;
257 
258    /* Clamp to max */
259    val -= max;
260    val &= val >> 31;
261    val += max;
262 
263    return val;
264 }
265 
266 
267 /* Mix as many sample values as possible from the source sample into a mixer
268  * buffer.  Implements stream_reader_t.
269  *
270  * TYPE is the type of the sample values in the mixer buffer, and
271  * NEXT_SAMPLE_VALUE must return a buffer of the same type.
272  *
273  * Note: Uses Bresenham to keep the precise sample position.
274  */
275 #define BRESENHAM                                                             \
276    do {                                                                       \
277       delta = spl->step > 0 ? spl->step : spl->step - spl->step_denom + 1;    \
278       delta /= spl->step_denom;                                               \
279       delta_error = spl->step - delta * spl->step_denom;                      \
280    } while (0)
281 
282 #define MAKE_MIXER(NAME, NEXT_SAMPLE_VALUE, TYPE)                             \
283 static void NAME(void *source, void **vbuf, unsigned int *samples,            \
284    ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc)                        \
285 {                                                                             \
286    ALLEGRO_SAMPLE_INSTANCE *spl = (ALLEGRO_SAMPLE_INSTANCE *)source;          \
287    TYPE *buf = *vbuf;                                                         \
288    size_t maxc = al_get_channel_count(spl->spl_data.chan_conf);               \
289    size_t samples_l = *samples;                                               \
290    size_t c;                                                                  \
291    int delta, delta_error;                                                    \
292    SAMP_BUF samp_buf;                                                         \
293                                                                               \
294    BRESENHAM;                                                                 \
295                                                                               \
296    if (!spl->is_playing)                                                      \
297       return;                                                                 \
298                                                                               \
299    while (samples_l > 0) {                                                    \
300       const TYPE *s;                                                          \
301       int old_step = spl->step;                                               \
302                                                                               \
303       if (!fix_looped_position(spl))                                          \
304          return;                                                              \
305       if (old_step != spl->step) {                                            \
306          BRESENHAM;                                                           \
307       }                                                                       \
308                                                                               \
309       /* It might be worth preparing multiple sample values at once. */       \
310       s = (TYPE *) NEXT_SAMPLE_VALUE(&samp_buf, spl, maxc);                   \
311                                                                               \
312       for (c = 0; c < dest_maxc; c++) {                                       \
313          ALLEGRO_STATIC_ASSERT(kcm_mixer, ALLEGRO_MAX_CHANNELS == 8);         \
314          switch (maxc) {                                                      \
315             case 8: *buf += s[7] * spl->matrix[c*maxc + 7];                   \
316             /* fall through */                                                \
317             case 7: *buf += s[6] * spl->matrix[c*maxc + 6];                   \
318             /* fall through */                                                \
319             case 6: *buf += s[5] * spl->matrix[c*maxc + 5];                   \
320             /* fall through */                                                \
321             case 5: *buf += s[4] * spl->matrix[c*maxc + 4];                   \
322             /* fall through */                                                \
323             case 4: *buf += s[3] * spl->matrix[c*maxc + 3];                   \
324             /* fall through */                                                \
325             case 3: *buf += s[2] * spl->matrix[c*maxc + 2];                   \
326             /* fall through */                                                \
327             case 2: *buf += s[1] * spl->matrix[c*maxc + 1];                   \
328             /* fall through */                                                \
329             case 1: *buf += s[0] * spl->matrix[c*maxc + 0];                   \
330             /* fall through */                                                \
331             default: break;                                                   \
332          }                                                                    \
333          buf++;                                                               \
334       }                                                                       \
335                                                                               \
336       spl->pos += delta;                                                      \
337       spl->pos_bresenham_error += delta_error;                                \
338       if (spl->pos_bresenham_error >= spl->step_denom) {                      \
339          spl->pos++;                                                          \
340          spl->pos_bresenham_error -= spl->step_denom;                         \
341       }                                                                       \
342       samples_l--;                                                            \
343    }                                                                          \
344    fix_looped_position(spl);                                                  \
345    (void)buffer_depth;                                                        \
346 }
347 
MAKE_MIXER(read_to_mixer_point_float_32,point_spl32,float)348 MAKE_MIXER(read_to_mixer_point_float_32, point_spl32, float)
349 MAKE_MIXER(read_to_mixer_linear_float_32, linear_spl32, float)
350 MAKE_MIXER(read_to_mixer_cubic_float_32, cubic_spl32, float)
351 MAKE_MIXER(read_to_mixer_point_int16_t_16, point_spl16, int16_t)
352 MAKE_MIXER(read_to_mixer_linear_int16_t_16, linear_spl16, int16_t)
353 
354 #undef MAKE_MIXER
355 
356 
357 /* _al_kcm_mixer_read:
358  *  Mixes the streams attached to the mixer and writes additively to the
359  *  specified buffer (or if *buf is NULL, indicating a voice, convert it and
360  *  set it to the buffer pointer).
361  */
362 void _al_kcm_mixer_read(void *source, void **buf, unsigned int *samples,
363    ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc)
364 {
365    const ALLEGRO_MIXER *mixer;
366    ALLEGRO_MIXER *m = (ALLEGRO_MIXER *)source;
367    int maxc = al_get_channel_count(m->ss.spl_data.chan_conf);
368    int samples_l = *samples;
369    int i;
370 
371    if (!m->ss.is_playing)
372       return;
373 
374    /* Make sure the mixer buffer is big enough. */
375    if (m->ss.spl_data.len*maxc < samples_l*maxc) {
376       al_free(m->ss.spl_data.buffer.ptr);
377       m->ss.spl_data.buffer.ptr = al_malloc(samples_l*maxc*al_get_audio_depth_size(m->ss.spl_data.depth));
378       if (!m->ss.spl_data.buffer.ptr) {
379          _al_set_error(ALLEGRO_GENERIC_ERROR,
380             "Out of memory allocating mixer buffer");
381          m->ss.spl_data.len = 0;
382          return;
383       }
384       m->ss.spl_data.len = samples_l;
385    }
386 
387    mixer = m;
388 
389    /* Clear the buffer to silence. */
390    memset(mixer->ss.spl_data.buffer.ptr, 0, samples_l * maxc * al_get_audio_depth_size(mixer->ss.spl_data.depth));
391 
392    /* Mix the streams into the mixer buffer. */
393    for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) {
394       ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i);
395       ALLEGRO_SAMPLE_INSTANCE *spl = *slot;
396       ASSERT(spl->spl_read);
397       spl->spl_read(spl, (void **) &mixer->ss.spl_data.buffer.ptr, samples,
398          m->ss.spl_data.depth, maxc);
399    }
400 
401    /* Call the post-processing callback. */
402    if (mixer->postprocess_callback) {
403       mixer->postprocess_callback(mixer->ss.spl_data.buffer.ptr,
404          *samples, mixer->pp_callback_userdata);
405    }
406 
407    samples_l *= maxc;
408 
409    /* Apply the gain if necessary. */
410    if (mixer->ss.gain != 1.0f) {
411       float mixer_gain = mixer->ss.gain;
412       unsigned long i = samples_l;
413 
414       switch (m->ss.spl_data.depth) {
415          case ALLEGRO_AUDIO_DEPTH_FLOAT32: {
416             float *p = mixer->ss.spl_data.buffer.f32;
417             while (i-- > 0) {
418                *p++ *= mixer_gain;
419             }
420             break;
421          }
422 
423          case ALLEGRO_AUDIO_DEPTH_INT16: {
424             int16_t *p = mixer->ss.spl_data.buffer.s16;
425             while (i-- > 0) {
426                *p++ *= mixer_gain;
427             }
428             break;
429          }
430 
431          case ALLEGRO_AUDIO_DEPTH_INT8:
432          case ALLEGRO_AUDIO_DEPTH_INT24:
433          case ALLEGRO_AUDIO_DEPTH_UINT8:
434          case ALLEGRO_AUDIO_DEPTH_UINT16:
435          case ALLEGRO_AUDIO_DEPTH_UINT24:
436             /* Unsupported mixer depths. */
437             ASSERT(false);
438             break;
439       }
440    }
441 
442    /* Feeding to a non-voice.
443     * Currently we only support mixers of the same audio depth doing this.
444     */
445    if (*buf) {
446       switch (m->ss.spl_data.depth) {
447          case ALLEGRO_AUDIO_DEPTH_FLOAT32: {
448             /* We don't need to clamp in the mixer yet. */
449             float *lbuf = *buf;
450             float *src = mixer->ss.spl_data.buffer.f32;
451             while (samples_l-- > 0) {
452                *lbuf += *src;
453                lbuf++;
454                src++;
455             }
456             break;
457 
458          case ALLEGRO_AUDIO_DEPTH_INT16: {
459             int16_t *lbuf = *buf;
460             int16_t *src = mixer->ss.spl_data.buffer.s16;
461             while (samples_l-- > 0) {
462                int32_t x = *lbuf + *src;
463                if (x < -32768)
464                   x = -32768;
465                else if (x > 32767)
466                   x = 32767;
467                *lbuf = (int16_t)x;
468                lbuf++;
469                src++;
470             }
471             break;
472          }
473 
474          case ALLEGRO_AUDIO_DEPTH_INT8:
475          case ALLEGRO_AUDIO_DEPTH_INT24:
476          case ALLEGRO_AUDIO_DEPTH_UINT8:
477          case ALLEGRO_AUDIO_DEPTH_UINT16:
478          case ALLEGRO_AUDIO_DEPTH_UINT24:
479             /* Unsupported mixer depths. */
480             ASSERT(false);
481             break;
482          }
483       }
484       return;
485    }
486 
487    /* We're feeding to a voice.
488     * Clamp and convert the mixed data for the voice.
489     */
490    *buf = mixer->ss.spl_data.buffer.ptr;
491    switch (buffer_depth & ~ALLEGRO_AUDIO_DEPTH_UNSIGNED) {
492 
493       case ALLEGRO_AUDIO_DEPTH_FLOAT32:
494          /* Do we need to clamp? */
495          break;
496 
497       case ALLEGRO_AUDIO_DEPTH_INT24:
498          switch (mixer->ss.spl_data.depth) {
499             case ALLEGRO_AUDIO_DEPTH_FLOAT32: {
500                int32_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED)
501                               ? 0x800000 : 0);
502                int32_t *lbuf = mixer->ss.spl_data.buffer.s24;
503                float *src = mixer->ss.spl_data.buffer.f32;
504 
505                while (samples_l > 0) {
506                   *lbuf = clamp(*(src++) * ((float)0x7FFFFF + 0.5f),
507                      ~0x7FFFFF, 0x7FFFFF);
508                   *lbuf += off;
509                   lbuf++;
510                   samples_l--;
511                }
512                break;
513             }
514 
515             case ALLEGRO_AUDIO_DEPTH_INT16:
516                /* XXX not yet implemented */
517                ASSERT(false);
518                break;
519 
520             case ALLEGRO_AUDIO_DEPTH_INT8:
521             case ALLEGRO_AUDIO_DEPTH_INT24:
522             case ALLEGRO_AUDIO_DEPTH_UINT8:
523             case ALLEGRO_AUDIO_DEPTH_UINT16:
524             case ALLEGRO_AUDIO_DEPTH_UINT24:
525                /* Unsupported mixer depths. */
526                ASSERT(false);
527                break;
528          }
529          break;
530 
531       case ALLEGRO_AUDIO_DEPTH_INT16:
532          switch (mixer->ss.spl_data.depth) {
533             case ALLEGRO_AUDIO_DEPTH_FLOAT32: {
534                int16_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED)
535                               ? 0x8000 : 0);
536                int16_t *lbuf = mixer->ss.spl_data.buffer.s16;
537                float *src = mixer->ss.spl_data.buffer.f32;
538 
539                while (samples_l > 0) {
540                   *lbuf = clamp(*(src++) * ((float)0x7FFF + 0.5f), ~0x7FFF, 0x7FFF);
541                   *lbuf += off;
542                   lbuf++;
543                   samples_l--;
544                }
545                break;
546             }
547 
548             case ALLEGRO_AUDIO_DEPTH_INT16:
549                /* Handle signedness differences. */
550                if (buffer_depth != ALLEGRO_AUDIO_DEPTH_INT16) {
551                   int16_t *lbuf = mixer->ss.spl_data.buffer.s16;
552                   while (samples_l > 0) {
553                      *lbuf++ ^= 0x8000;
554                      samples_l--;
555                   }
556                }
557                break;
558 
559             case ALLEGRO_AUDIO_DEPTH_INT8:
560             case ALLEGRO_AUDIO_DEPTH_INT24:
561             case ALLEGRO_AUDIO_DEPTH_UINT8:
562             case ALLEGRO_AUDIO_DEPTH_UINT16:
563             case ALLEGRO_AUDIO_DEPTH_UINT24:
564                /* Unsupported mixer depths. */
565                ASSERT(false);
566                break;
567          }
568          break;
569 
570       /* Ugh, do we really want to support 8-bit output? */
571       case ALLEGRO_AUDIO_DEPTH_INT8:
572          switch (mixer->ss.spl_data.depth) {
573             case ALLEGRO_AUDIO_DEPTH_FLOAT32: {
574                int8_t off = ((buffer_depth & ALLEGRO_AUDIO_DEPTH_UNSIGNED)
575                               ? 0x80 : 0);
576                int8_t *lbuf = mixer->ss.spl_data.buffer.s8;
577                float *src = mixer->ss.spl_data.buffer.f32;
578 
579                while (samples_l > 0) {
580                   *lbuf = clamp(*(src++) * ((float)0x7F + 0.5f), ~0x7F, 0x7F);
581                   *lbuf += off;
582                   lbuf++;
583                   samples_l--;
584                }
585                break;
586             }
587 
588             case ALLEGRO_AUDIO_DEPTH_INT16:
589                /* XXX not yet implemented */
590                ASSERT(false);
591                break;
592 
593             case ALLEGRO_AUDIO_DEPTH_INT8:
594             case ALLEGRO_AUDIO_DEPTH_INT24:
595             case ALLEGRO_AUDIO_DEPTH_UINT8:
596             case ALLEGRO_AUDIO_DEPTH_UINT16:
597             case ALLEGRO_AUDIO_DEPTH_UINT24:
598                /* Unsupported mixer depths. */
599                ASSERT(false);
600                break;
601          }
602          break;
603 
604       case ALLEGRO_AUDIO_DEPTH_UINT8:
605       case ALLEGRO_AUDIO_DEPTH_UINT16:
606       case ALLEGRO_AUDIO_DEPTH_UINT24:
607          /* Impossible. */
608          ASSERT(false);
609          break;
610    }
611 
612    (void)dest_maxc;
613 }
614 
615 
616 /* Function: al_create_mixer
617  */
al_create_mixer(unsigned int freq,ALLEGRO_AUDIO_DEPTH depth,ALLEGRO_CHANNEL_CONF chan_conf)618 ALLEGRO_MIXER *al_create_mixer(unsigned int freq,
619    ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)
620 {
621    ALLEGRO_MIXER *mixer;
622    int default_mixer_quality = ALLEGRO_MIXER_QUALITY_LINEAR;
623    const char *p;
624 
625    /* XXX this is in the wrong place */
626    p = al_get_config_value(al_get_system_config(), "audio",
627       "default_mixer_quality");
628    if (p && p[0] != '\0') {
629       if (!_al_stricmp(p, "point")) {
630          ALLEGRO_INFO("Point sampling\n");
631          default_mixer_quality = ALLEGRO_MIXER_QUALITY_POINT;
632       }
633       else if (!_al_stricmp(p, "linear")) {
634          ALLEGRO_INFO("Linear interpolation\n");
635          default_mixer_quality = ALLEGRO_MIXER_QUALITY_LINEAR;
636       }
637       else if (!_al_stricmp(p, "cubic")) {
638          ALLEGRO_INFO("Cubic interpolation\n");
639          default_mixer_quality = ALLEGRO_MIXER_QUALITY_CUBIC;
640       }
641    }
642 
643    if (!freq) {
644       _al_set_error(ALLEGRO_INVALID_PARAM,
645          "Attempted to create mixer with no frequency");
646       return NULL;
647    }
648 
649    if (depth != ALLEGRO_AUDIO_DEPTH_FLOAT32 &&
650          depth != ALLEGRO_AUDIO_DEPTH_INT16) {
651       _al_set_error(ALLEGRO_INVALID_PARAM, "Unsupported mixer depth");
652       return NULL;
653    }
654 
655    mixer = al_calloc(1, sizeof(ALLEGRO_MIXER));
656    if (!mixer) {
657       _al_set_error(ALLEGRO_GENERIC_ERROR,
658          "Out of memory allocating mixer object");
659       return NULL;
660    }
661 
662    mixer->ss.is_playing = true;
663    mixer->ss.spl_data.free_buf = true;
664 
665    mixer->ss.loop = ALLEGRO_PLAYMODE_ONCE;
666    /* XXX should we have a specific loop mode? */
667    mixer->ss.gain = 1.0f;
668    mixer->ss.spl_data.depth     = depth;
669    mixer->ss.spl_data.chan_conf = chan_conf;
670    mixer->ss.spl_data.frequency = freq;
671 
672    mixer->ss.is_mixer = true;
673    mixer->ss.spl_read = NULL;
674 
675    mixer->quality = default_mixer_quality;
676 
677    _al_vector_init(&mixer->streams, sizeof(ALLEGRO_SAMPLE_INSTANCE *));
678 
679    mixer->dtor_item = _al_kcm_register_destructor("mixer", mixer, (void (*)(void *)) al_destroy_mixer);
680 
681    return mixer;
682 }
683 
684 
685 /* Function: al_destroy_mixer
686  */
al_destroy_mixer(ALLEGRO_MIXER * mixer)687 void al_destroy_mixer(ALLEGRO_MIXER *mixer)
688 {
689    if (mixer) {
690       _al_kcm_unregister_destructor(mixer->dtor_item);
691       _al_kcm_destroy_sample(&mixer->ss, false);
692    }
693 }
694 
695 
696 /* This function is ALLEGRO_MIXER aware */
697 /* Function: al_attach_sample_instance_to_mixer
698  */
al_attach_sample_instance_to_mixer(ALLEGRO_SAMPLE_INSTANCE * spl,ALLEGRO_MIXER * mixer)699 bool al_attach_sample_instance_to_mixer(ALLEGRO_SAMPLE_INSTANCE *spl,
700    ALLEGRO_MIXER *mixer)
701 {
702    ALLEGRO_SAMPLE_INSTANCE **slot;
703 
704    ASSERT(mixer);
705    ASSERT(spl);
706 
707    /* Already referenced, do not attach. */
708    if (spl->parent.u.ptr) {
709       _al_set_error(ALLEGRO_INVALID_OBJECT,
710          "Attempted to attach a sample that's already attached");
711       return false;
712    }
713 
714    maybe_lock_mutex(mixer->ss.mutex);
715 
716    _al_kcm_stream_set_mutex(spl, mixer->ss.mutex);
717 
718    slot = _al_vector_alloc_back(&mixer->streams);
719    if (!slot) {
720       if (mixer->ss.mutex) {
721          al_unlock_mutex(mixer->ss.mutex);
722       }
723       _al_set_error(ALLEGRO_GENERIC_ERROR,
724          "Out of memory allocating attachment pointers");
725       return false;
726    }
727    (*slot) = spl;
728 
729    spl->step = (spl->spl_data.frequency) * spl->speed;
730    spl->step_denom = mixer->ss.spl_data.frequency;
731    /* Don't want to be trapped with a step value of 0. */
732    if (spl->step == 0) {
733       if (spl->speed > 0.0f)
734          spl->step = 1;
735       else
736          spl->step = -1;
737    }
738 
739    /* Set the proper sample stream reader. */
740    ASSERT(spl->spl_read == NULL);
741    if (spl->is_mixer) {
742       spl->spl_read = _al_kcm_mixer_read;
743    }
744    else {
745       switch (mixer->ss.spl_data.depth) {
746          case ALLEGRO_AUDIO_DEPTH_FLOAT32:
747             switch (mixer->quality) {
748                case ALLEGRO_MIXER_QUALITY_POINT:
749                   spl->spl_read = read_to_mixer_point_float_32;
750                   break;
751                case ALLEGRO_MIXER_QUALITY_LINEAR:
752                   spl->spl_read = read_to_mixer_linear_float_32;
753                   break;
754                case ALLEGRO_MIXER_QUALITY_CUBIC:
755                   spl->spl_read = read_to_mixer_cubic_float_32;
756                   break;
757             }
758             break;
759 
760          case ALLEGRO_AUDIO_DEPTH_INT16:
761             switch (mixer->quality) {
762                case ALLEGRO_MIXER_QUALITY_POINT:
763                   spl->spl_read = read_to_mixer_point_int16_t_16;
764                   break;
765                case ALLEGRO_MIXER_QUALITY_CUBIC:
766                   ALLEGRO_WARN("Falling back to linear interpolation\n");
767                   /* fallthrough */
768                case ALLEGRO_MIXER_QUALITY_LINEAR:
769                   spl->spl_read = read_to_mixer_linear_int16_t_16;
770                   break;
771             }
772             break;
773 
774          case ALLEGRO_AUDIO_DEPTH_INT8:
775          case ALLEGRO_AUDIO_DEPTH_INT24:
776          case ALLEGRO_AUDIO_DEPTH_UINT8:
777          case ALLEGRO_AUDIO_DEPTH_UINT16:
778          case ALLEGRO_AUDIO_DEPTH_UINT24:
779             /* Unsupported mixer depths. */
780             ASSERT(false);
781             break;
782       }
783 
784       _al_kcm_mixer_rejig_sample_matrix(mixer, spl);
785    }
786 
787    spl->parent.u.mixer = mixer;
788    spl->parent.is_voice = false;
789 
790    maybe_unlock_mutex(mixer->ss.mutex);
791 
792    return true;
793 }
794 
795 
796 /* Function: al_attach_audio_stream_to_mixer
797  */
al_attach_audio_stream_to_mixer(ALLEGRO_AUDIO_STREAM * stream,ALLEGRO_MIXER * mixer)798 bool al_attach_audio_stream_to_mixer(ALLEGRO_AUDIO_STREAM *stream, ALLEGRO_MIXER *mixer)
799 {
800    ASSERT(mixer);
801    ASSERT(stream);
802 
803    return al_attach_sample_instance_to_mixer(&stream->spl, mixer);
804 }
805 
806 
807 /* Function: al_attach_mixer_to_mixer
808  */
al_attach_mixer_to_mixer(ALLEGRO_MIXER * stream,ALLEGRO_MIXER * mixer)809 bool al_attach_mixer_to_mixer(ALLEGRO_MIXER *stream, ALLEGRO_MIXER *mixer)
810 {
811    ASSERT(mixer);
812    ASSERT(stream);
813    ASSERT(mixer != stream);
814 
815    if (mixer->ss.spl_data.frequency != stream->ss.spl_data.frequency) {
816       _al_set_error(ALLEGRO_INVALID_OBJECT,
817          "Attempted to attach a mixer with different frequencies");
818       return false;
819    }
820 
821    if (mixer->ss.spl_data.depth != stream->ss.spl_data.depth) {
822       _al_set_error(ALLEGRO_INVALID_OBJECT,
823          "Mixers of different audio depths cannot be attached to one another");
824       return false;
825    }
826 
827    if (mixer->ss.spl_data.chan_conf != stream->ss.spl_data.chan_conf) {
828       _al_set_error(ALLEGRO_INVALID_OBJECT,
829          "Mixers of different channel configurations cannot be attached to one another");
830       return false;
831    }
832 
833    return al_attach_sample_instance_to_mixer(&stream->ss, mixer);
834 }
835 
836 
837 /* Function: al_set_mixer_postprocess_callback
838  */
al_set_mixer_postprocess_callback(ALLEGRO_MIXER * mixer,void (* pp_callback)(void * buf,unsigned int samples,void * data),void * pp_callback_userdata)839 bool al_set_mixer_postprocess_callback(ALLEGRO_MIXER *mixer,
840    void (*pp_callback)(void *buf, unsigned int samples, void *data),
841    void *pp_callback_userdata)
842 {
843    ASSERT(mixer);
844 
845    maybe_lock_mutex(mixer->ss.mutex);
846 
847    mixer->postprocess_callback = pp_callback;
848    mixer->pp_callback_userdata = pp_callback_userdata;
849 
850    maybe_unlock_mutex(mixer->ss.mutex);
851 
852    return true;
853 }
854 
855 
856 /* Function: al_get_mixer_frequency
857  */
al_get_mixer_frequency(const ALLEGRO_MIXER * mixer)858 unsigned int al_get_mixer_frequency(const ALLEGRO_MIXER *mixer)
859 {
860    ASSERT(mixer);
861 
862    return mixer->ss.spl_data.frequency;
863 }
864 
865 
866 /* Function: al_get_mixer_channels
867  */
al_get_mixer_channels(const ALLEGRO_MIXER * mixer)868 ALLEGRO_CHANNEL_CONF al_get_mixer_channels(const ALLEGRO_MIXER *mixer)
869 {
870    ASSERT(mixer);
871 
872    return mixer->ss.spl_data.chan_conf;
873 }
874 
875 
876 /* Function: al_get_mixer_depth
877  */
al_get_mixer_depth(const ALLEGRO_MIXER * mixer)878 ALLEGRO_AUDIO_DEPTH al_get_mixer_depth(const ALLEGRO_MIXER *mixer)
879 {
880    ASSERT(mixer);
881 
882    return mixer->ss.spl_data.depth;
883 }
884 
885 
886 /* Function: al_get_mixer_quality
887  */
al_get_mixer_quality(const ALLEGRO_MIXER * mixer)888 ALLEGRO_MIXER_QUALITY al_get_mixer_quality(const ALLEGRO_MIXER *mixer)
889 {
890    ASSERT(mixer);
891 
892    return mixer->quality;
893 }
894 
895 
896 /* Function: al_get_mixer_gain
897  */
al_get_mixer_gain(const ALLEGRO_MIXER * mixer)898 float al_get_mixer_gain(const ALLEGRO_MIXER *mixer)
899 {
900    ASSERT(mixer);
901 
902    return mixer->ss.gain;
903 }
904 
905 
906 /* Function: al_get_mixer_playing
907  */
al_get_mixer_playing(const ALLEGRO_MIXER * mixer)908 bool al_get_mixer_playing(const ALLEGRO_MIXER *mixer)
909 {
910    ASSERT(mixer);
911 
912    return mixer->ss.is_playing;
913 }
914 
915 
916 /* Function: al_get_mixer_attached
917  */
al_get_mixer_attached(const ALLEGRO_MIXER * mixer)918 bool al_get_mixer_attached(const ALLEGRO_MIXER *mixer)
919 {
920    ASSERT(mixer);
921 
922    return _al_vector_is_nonempty(&mixer->streams);
923 }
924 
925 
926 /* Function: al_set_mixer_frequency
927  */
al_set_mixer_frequency(ALLEGRO_MIXER * mixer,unsigned int val)928 bool al_set_mixer_frequency(ALLEGRO_MIXER *mixer, unsigned int val)
929 {
930    ASSERT(mixer);
931 
932    /* You can change the frequency of a mixer as long as it's not attached
933     * to anything.
934     */
935    if (mixer->ss.parent.u.ptr) {
936       _al_set_error(ALLEGRO_INVALID_OBJECT,
937             "Attempted to change the frequency of an attached mixer");
938       return false;
939    }
940 
941    mixer->ss.spl_data.frequency = val;
942    return true;
943 }
944 
945 
946 /* Function: al_set_mixer_quality
947  */
al_set_mixer_quality(ALLEGRO_MIXER * mixer,ALLEGRO_MIXER_QUALITY new_quality)948 bool al_set_mixer_quality(ALLEGRO_MIXER *mixer, ALLEGRO_MIXER_QUALITY new_quality)
949 {
950    bool ret;
951    ASSERT(mixer);
952 
953    maybe_lock_mutex(mixer->ss.mutex);
954 
955    if (mixer->quality == new_quality) {
956       ret = true;
957    }
958    else if (_al_vector_size(&mixer->streams) == 0) {
959       mixer->quality = new_quality;
960       ret = true;
961    }
962    else {
963       _al_set_error(ALLEGRO_INVALID_OBJECT,
964          "Attempted to change the quality of a mixer with attachments");
965       ret = false;
966    }
967 
968    maybe_unlock_mutex(mixer->ss.mutex);
969 
970    return ret;
971 }
972 
973 
974 /* Function: al_set_mixer_gain
975  */
al_set_mixer_gain(ALLEGRO_MIXER * mixer,float new_gain)976 bool al_set_mixer_gain(ALLEGRO_MIXER *mixer, float new_gain)
977 {
978    int i;
979    ASSERT(mixer);
980 
981    maybe_lock_mutex(mixer->ss.mutex);
982 
983    if (mixer->ss.gain != new_gain) {
984       mixer->ss.gain = new_gain;
985 
986       for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) {
987          ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i);
988          _al_kcm_mixer_rejig_sample_matrix(mixer, *slot);
989       }
990    }
991 
992    maybe_unlock_mutex(mixer->ss.mutex);
993 
994    return true;
995 }
996 
997 
998 /* Function: al_set_mixer_playing
999  */
al_set_mixer_playing(ALLEGRO_MIXER * mixer,bool val)1000 bool al_set_mixer_playing(ALLEGRO_MIXER *mixer, bool val)
1001 {
1002    ASSERT(mixer);
1003 
1004    mixer->ss.is_playing = val;
1005    return true;
1006 }
1007 
1008 
1009 /* Function: al_detach_mixer
1010  */
al_detach_mixer(ALLEGRO_MIXER * mixer)1011 bool al_detach_mixer(ALLEGRO_MIXER *mixer)
1012 {
1013    ASSERT(mixer);
1014 
1015    _al_kcm_detach_from_parent(&mixer->ss);
1016    ASSERT(mixer->ss.spl_read == NULL);
1017    return true;
1018 }
1019 
1020 
1021 /* vim: set sts=3 sw=3 et: */
1022