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