Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (audio_mixer.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #ifdef HAVE_CONFIG_H | |
24 | #include "../../config.h" | |
25 | #endif | |
26 | ||
27 | #include <audio/audio_mixer.h> | |
28 | #include <audio/audio_resampler.h> | |
29 | ||
30 | #ifdef HAVE_RWAV | |
31 | #include <formats/rwav.h> | |
32 | #endif | |
33 | #include <memalign.h> | |
34 | ||
35 | #include <stdio.h> | |
36 | #include <stdlib.h> | |
37 | #include <string.h> | |
38 | #include <math.h> | |
39 | ||
40 | #ifdef HAVE_STB_VORBIS | |
41 | #define STB_VORBIS_NO_PUSHDATA_API | |
42 | #define STB_VORBIS_NO_STDIO | |
43 | #define STB_VORBIS_NO_CRT | |
44 | ||
45 | #include <stb/stb_vorbis.h> | |
46 | #endif | |
47 | ||
48 | #ifdef HAVE_DR_FLAC | |
49 | #define DR_FLAC_IMPLEMENTATION | |
50 | #include <dr/dr_flac.h> | |
51 | #endif | |
52 | ||
53 | #ifdef HAVE_DR_MP3 | |
54 | #define DR_MP3_IMPLEMENTATION | |
55 | #include <retro_assert.h> | |
56 | #define DRMP3_ASSERT(expression) retro_assert(expression) | |
57 | #include <dr/dr_mp3.h> | |
58 | #endif | |
59 | ||
60 | #ifdef HAVE_IBXM | |
61 | #include <ibxm/ibxm.h> | |
62 | #endif | |
63 | ||
64 | #ifdef HAVE_THREADS | |
65 | #include <rthreads/rthreads.h> | |
66 | #define AUDIO_MIXER_LOCK(voice) slock_lock(voice->lock) | |
67 | #define AUDIO_MIXER_UNLOCK(voice) slock_unlock(voice->lock) | |
68 | #else | |
69 | #define AUDIO_MIXER_LOCK(voice) do {} while(0) | |
70 | #define AUDIO_MIXER_UNLOCK(voice) do {} while(0) | |
71 | #endif | |
72 | ||
73 | #define AUDIO_MIXER_MAX_VOICES 8 | |
74 | #define AUDIO_MIXER_TEMP_BUFFER 8192 | |
75 | ||
76 | struct audio_mixer_sound | |
77 | { | |
78 | enum audio_mixer_type type; | |
79 | ||
80 | union | |
81 | { | |
82 | struct | |
83 | { | |
84 | /* wav */ | |
85 | const float* pcm; | |
86 | unsigned frames; | |
87 | } wav; | |
88 | ||
89 | #ifdef HAVE_STB_VORBIS | |
90 | struct | |
91 | { | |
92 | /* ogg */ | |
93 | const void* data; | |
94 | unsigned size; | |
95 | } ogg; | |
96 | #endif | |
97 | ||
98 | #ifdef HAVE_DR_FLAC | |
99 | struct | |
100 | { | |
101 | /* flac */ | |
102 | const void* data; | |
103 | unsigned size; | |
104 | } flac; | |
105 | #endif | |
106 | ||
107 | #ifdef HAVE_DR_MP3 | |
108 | struct | |
109 | { | |
110 | /* mp */ | |
111 | const void* data; | |
112 | unsigned size; | |
113 | } mp3; | |
114 | #endif | |
115 | ||
116 | #ifdef HAVE_IBXM | |
117 | struct | |
118 | { | |
119 | /* mod/s3m/xm */ | |
120 | const void* data; | |
121 | unsigned size; | |
122 | } mod; | |
123 | #endif | |
124 | } types; | |
125 | }; | |
126 | ||
127 | struct audio_mixer_voice | |
128 | { | |
129 | struct | |
130 | { | |
131 | struct | |
132 | { | |
133 | unsigned position; | |
134 | } wav; | |
135 | ||
136 | #ifdef HAVE_STB_VORBIS | |
137 | struct | |
138 | { | |
139 | stb_vorbis *stream; | |
140 | void *resampler_data; | |
141 | const retro_resampler_t *resampler; | |
142 | float *buffer; | |
143 | unsigned position; | |
144 | unsigned samples; | |
145 | unsigned buf_samples; | |
146 | float ratio; | |
147 | } ogg; | |
148 | #endif | |
149 | ||
150 | #ifdef HAVE_DR_FLAC | |
151 | struct | |
152 | { | |
153 | float* buffer; | |
154 | drflac *stream; | |
155 | void *resampler_data; | |
156 | const retro_resampler_t *resampler; | |
157 | unsigned position; | |
158 | unsigned samples; | |
159 | unsigned buf_samples; | |
160 | float ratio; | |
161 | } flac; | |
162 | #endif | |
163 | ||
164 | #ifdef HAVE_DR_MP3 | |
165 | struct | |
166 | { | |
167 | drmp3 stream; | |
168 | void *resampler_data; | |
169 | const retro_resampler_t *resampler; | |
170 | float* buffer; | |
171 | unsigned position; | |
172 | unsigned samples; | |
173 | unsigned buf_samples; | |
174 | float ratio; | |
175 | } mp3; | |
176 | #endif | |
177 | ||
178 | #ifdef HAVE_IBXM | |
179 | struct | |
180 | { | |
181 | int* buffer; | |
182 | struct replay* stream; | |
183 | struct module* module; | |
184 | unsigned position; | |
185 | unsigned samples; | |
186 | unsigned buf_samples; | |
187 | } mod; | |
188 | #endif | |
189 | } types; | |
190 | audio_mixer_sound_t *sound; | |
191 | audio_mixer_stop_cb_t stop_cb; | |
192 | unsigned type; | |
193 | float volume; | |
194 | bool repeat; | |
195 | #ifdef HAVE_THREADS | |
196 | slock_t *lock; | |
197 | #endif | |
198 | }; | |
199 | ||
200 | /* TODO/FIXME - static globals */ | |
201 | static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0}; | |
202 | static unsigned s_rate = 0; | |
203 | ||
204 | static void audio_mixer_release(audio_mixer_voice_t* voice); | |
205 | ||
206 | #ifdef HAVE_RWAV | |
207 | static bool wav_to_float(const rwav_t* wav, float** pcm, size_t samples_out) | |
208 | { | |
209 | size_t i; | |
210 | /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */ | |
211 | float *f = (float*)memalign_alloc(16, | |
212 | ((samples_out + 15) & ~15) * sizeof(float)); | |
213 | ||
214 | if (!f) | |
215 | return false; | |
216 | ||
217 | *pcm = f; | |
218 | ||
219 | if (wav->bitspersample == 8) | |
220 | { | |
221 | float sample = 0.0f; | |
222 | const uint8_t *u8 = (const uint8_t*)wav->samples; | |
223 | ||
224 | if (wav->numchannels == 1) | |
225 | { | |
226 | for (i = wav->numsamples; i != 0; i--) | |
227 | { | |
228 | sample = (float)*u8++ / 255.0f; | |
229 | sample = sample * 2.0f - 1.0f; | |
230 | *f++ = sample; | |
231 | *f++ = sample; | |
232 | } | |
233 | } | |
234 | else if (wav->numchannels == 2) | |
235 | { | |
236 | for (i = wav->numsamples; i != 0; i--) | |
237 | { | |
238 | sample = (float)*u8++ / 255.0f; | |
239 | sample = sample * 2.0f - 1.0f; | |
240 | *f++ = sample; | |
241 | sample = (float)*u8++ / 255.0f; | |
242 | sample = sample * 2.0f - 1.0f; | |
243 | *f++ = sample; | |
244 | } | |
245 | } | |
246 | } | |
247 | else | |
248 | { | |
249 | /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float | |
250 | * functions here? */ | |
251 | ||
252 | float sample = 0.0f; | |
253 | const int16_t *s16 = (const int16_t*)wav->samples; | |
254 | ||
255 | if (wav->numchannels == 1) | |
256 | { | |
257 | for (i = wav->numsamples; i != 0; i--) | |
258 | { | |
259 | sample = (float)((int)*s16++ + 32768) / 65535.0f; | |
260 | sample = sample * 2.0f - 1.0f; | |
261 | *f++ = sample; | |
262 | *f++ = sample; | |
263 | } | |
264 | } | |
265 | else if (wav->numchannels == 2) | |
266 | { | |
267 | for (i = wav->numsamples; i != 0; i--) | |
268 | { | |
269 | sample = (float)((int)*s16++ + 32768) / 65535.0f; | |
270 | sample = sample * 2.0f - 1.0f; | |
271 | *f++ = sample; | |
272 | sample = (float)((int)*s16++ + 32768) / 65535.0f; | |
273 | sample = sample * 2.0f - 1.0f; | |
274 | *f++ = sample; | |
275 | } | |
276 | } | |
277 | } | |
278 | ||
279 | return true; | |
280 | } | |
281 | ||
282 | static bool one_shot_resample(const float* in, size_t samples_in, | |
283 | unsigned rate, const char *resampler_ident, enum resampler_quality quality, | |
284 | float** out, size_t* samples_out) | |
285 | { | |
286 | struct resampler_data info; | |
287 | void* data = NULL; | |
288 | const retro_resampler_t* resampler = NULL; | |
289 | float ratio = (double)s_rate / (double)rate; | |
290 | ||
291 | if (!retro_resampler_realloc(&data, &resampler, | |
292 | resampler_ident, quality, ratio)) | |
293 | return false; | |
294 | ||
295 | /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We | |
296 | * add 16 more samples in the formula below just as safeguard, because | |
297 | * resampler->process sometimes reports more output samples than the | |
298 | * formula below calculates. Ideally, audio resamplers should have a | |
299 | * function to return the number of samples they will output given a | |
300 | * count of input samples. */ | |
301 | *samples_out = (size_t)(samples_in * ratio); | |
302 | *out = (float*)memalign_alloc(16, | |
303 | (((*samples_out + 16) + 15) & ~15) * sizeof(float)); | |
304 | ||
305 | if (*out == NULL) | |
306 | return false; | |
307 | ||
308 | info.data_in = in; | |
309 | info.data_out = *out; | |
310 | info.input_frames = samples_in / 2; | |
311 | info.output_frames = 0; | |
312 | info.ratio = ratio; | |
313 | ||
314 | resampler->process(data, &info); | |
315 | resampler->free(data); | |
316 | return true; | |
317 | } | |
318 | #endif | |
319 | ||
320 | void audio_mixer_init(unsigned rate) | |
321 | { | |
322 | unsigned i; | |
323 | ||
324 | s_rate = rate; | |
325 | ||
326 | for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++) | |
327 | { | |
328 | audio_mixer_voice_t *voice = &s_voices[i]; | |
329 | ||
330 | voice->type = AUDIO_MIXER_TYPE_NONE; | |
331 | #ifdef HAVE_THREADS | |
332 | if (!voice->lock) | |
333 | voice->lock = slock_new(); | |
334 | #endif | |
335 | } | |
336 | } | |
337 | ||
338 | void audio_mixer_done(void) | |
339 | { | |
340 | unsigned i; | |
341 | ||
342 | for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++) | |
343 | { | |
344 | audio_mixer_voice_t *voice = &s_voices[i]; | |
345 | ||
346 | AUDIO_MIXER_LOCK(voice); | |
347 | audio_mixer_release(voice); | |
348 | AUDIO_MIXER_UNLOCK(voice); | |
349 | #ifdef HAVE_THREADS | |
350 | slock_free(voice->lock); | |
351 | voice->lock = NULL; | |
352 | #endif | |
353 | } | |
354 | } | |
355 | ||
356 | audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size, | |
357 | const char *resampler_ident, enum resampler_quality quality) | |
358 | { | |
359 | #ifdef HAVE_RWAV | |
360 | /* WAV data */ | |
361 | rwav_t wav; | |
362 | /* WAV samples converted to float */ | |
363 | float* pcm = NULL; | |
364 | size_t samples = 0; | |
365 | /* Result */ | |
366 | audio_mixer_sound_t* sound = NULL; | |
367 | ||
368 | wav.bitspersample = 0; | |
369 | wav.numchannels = 0; | |
370 | wav.samplerate = 0; | |
371 | wav.numsamples = 0; | |
372 | wav.subchunk2size = 0; | |
373 | wav.samples = NULL; | |
374 | ||
375 | if ((rwav_load(&wav, buffer, size)) != RWAV_ITERATE_DONE) | |
376 | return NULL; | |
377 | ||
378 | samples = wav.numsamples * 2; | |
379 | ||
380 | if (!wav_to_float(&wav, &pcm, samples)) | |
381 | return NULL; | |
382 | ||
383 | if (wav.samplerate != s_rate) | |
384 | { | |
385 | float* resampled = NULL; | |
386 | ||
387 | if (!one_shot_resample(pcm, samples, wav.samplerate, | |
388 | resampler_ident, quality, | |
389 | &resampled, &samples)) | |
390 | return NULL; | |
391 | ||
392 | memalign_free((void*)pcm); | |
393 | pcm = resampled; | |
394 | } | |
395 | ||
396 | sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); | |
397 | ||
398 | if (!sound) | |
399 | { | |
400 | memalign_free((void*)pcm); | |
401 | return NULL; | |
402 | } | |
403 | ||
404 | sound->type = AUDIO_MIXER_TYPE_WAV; | |
405 | sound->types.wav.frames = (unsigned)(samples / 2); | |
406 | sound->types.wav.pcm = pcm; | |
407 | ||
408 | rwav_free(&wav); | |
409 | ||
410 | return sound; | |
411 | #else | |
412 | return NULL; | |
413 | #endif | |
414 | } | |
415 | ||
416 | audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size) | |
417 | { | |
418 | #ifdef HAVE_STB_VORBIS | |
419 | audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); | |
420 | ||
421 | if (!sound) | |
422 | return NULL; | |
423 | ||
424 | sound->type = AUDIO_MIXER_TYPE_OGG; | |
425 | sound->types.ogg.size = size; | |
426 | sound->types.ogg.data = buffer; | |
427 | ||
428 | return sound; | |
429 | #else | |
430 | return NULL; | |
431 | #endif | |
432 | } | |
433 | ||
434 | audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size) | |
435 | { | |
436 | #ifdef HAVE_DR_FLAC | |
437 | audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); | |
438 | ||
439 | if (!sound) | |
440 | return NULL; | |
441 | ||
442 | sound->type = AUDIO_MIXER_TYPE_FLAC; | |
443 | sound->types.flac.size = size; | |
444 | sound->types.flac.data = buffer; | |
445 | ||
446 | return sound; | |
447 | #else | |
448 | return NULL; | |
449 | #endif | |
450 | } | |
451 | ||
452 | audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size) | |
453 | { | |
454 | #ifdef HAVE_DR_MP3 | |
455 | audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); | |
456 | ||
457 | if (!sound) | |
458 | return NULL; | |
459 | ||
460 | sound->type = AUDIO_MIXER_TYPE_MP3; | |
461 | sound->types.mp3.size = size; | |
462 | sound->types.mp3.data = buffer; | |
463 | ||
464 | return sound; | |
465 | #else | |
466 | return NULL; | |
467 | #endif | |
468 | } | |
469 | ||
470 | audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size) | |
471 | { | |
472 | #ifdef HAVE_IBXM | |
473 | audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound)); | |
474 | ||
475 | if (!sound) | |
476 | return NULL; | |
477 | ||
478 | sound->type = AUDIO_MIXER_TYPE_MOD; | |
479 | sound->types.mod.size = size; | |
480 | sound->types.mod.data = buffer; | |
481 | ||
482 | return sound; | |
483 | #else | |
484 | return NULL; | |
485 | #endif | |
486 | } | |
487 | ||
488 | void audio_mixer_destroy(audio_mixer_sound_t* sound) | |
489 | { | |
490 | void *handle = NULL; | |
491 | if (!sound) | |
492 | return; | |
493 | ||
494 | switch (sound->type) | |
495 | { | |
496 | case AUDIO_MIXER_TYPE_WAV: | |
497 | handle = (void*)sound->types.wav.pcm; | |
498 | if (handle) | |
499 | memalign_free(handle); | |
500 | break; | |
501 | case AUDIO_MIXER_TYPE_OGG: | |
502 | #ifdef HAVE_STB_VORBIS | |
503 | handle = (void*)sound->types.ogg.data; | |
504 | if (handle) | |
505 | free(handle); | |
506 | #endif | |
507 | break; | |
508 | case AUDIO_MIXER_TYPE_MOD: | |
509 | #ifdef HAVE_IBXM | |
510 | handle = (void*)sound->types.mod.data; | |
511 | if (handle) | |
512 | free(handle); | |
513 | #endif | |
514 | break; | |
515 | case AUDIO_MIXER_TYPE_FLAC: | |
516 | #ifdef HAVE_DR_FLAC | |
517 | handle = (void*)sound->types.flac.data; | |
518 | if (handle) | |
519 | free(handle); | |
520 | #endif | |
521 | break; | |
522 | case AUDIO_MIXER_TYPE_MP3: | |
523 | #ifdef HAVE_DR_MP3 | |
524 | handle = (void*)sound->types.mp3.data; | |
525 | if (handle) | |
526 | free(handle); | |
527 | #endif | |
528 | break; | |
529 | case AUDIO_MIXER_TYPE_NONE: | |
530 | break; | |
531 | } | |
532 | ||
533 | free(sound); | |
534 | } | |
535 | ||
536 | static bool audio_mixer_play_wav(audio_mixer_sound_t* sound, | |
537 | audio_mixer_voice_t* voice, bool repeat, float volume, | |
538 | audio_mixer_stop_cb_t stop_cb) | |
539 | { | |
540 | voice->types.wav.position = 0; | |
541 | return true; | |
542 | } | |
543 | ||
544 | #ifdef HAVE_STB_VORBIS | |
545 | static bool audio_mixer_play_ogg( | |
546 | audio_mixer_sound_t* sound, | |
547 | audio_mixer_voice_t* voice, | |
548 | bool repeat, float volume, | |
549 | const char *resampler_ident, | |
550 | enum resampler_quality quality, | |
551 | audio_mixer_stop_cb_t stop_cb) | |
552 | { | |
553 | stb_vorbis_info info; | |
554 | int res = 0; | |
555 | float ratio = 1.0f; | |
556 | unsigned samples = 0; | |
557 | void *ogg_buffer = NULL; | |
558 | void *resampler_data = NULL; | |
559 | const retro_resampler_t* resamp = NULL; | |
560 | stb_vorbis *stb_vorbis = stb_vorbis_open_memory( | |
561 | (const unsigned char*)sound->types.ogg.data, | |
562 | sound->types.ogg.size, &res, NULL); | |
563 | ||
564 | if (!stb_vorbis) | |
565 | return false; | |
566 | ||
567 | info = stb_vorbis_get_info(stb_vorbis); | |
568 | ||
569 | if (info.sample_rate != s_rate) | |
570 | { | |
571 | ratio = (double)s_rate / (double)info.sample_rate; | |
572 | ||
573 | if (!retro_resampler_realloc(&resampler_data, | |
574 | &resamp, resampler_ident, quality, | |
575 | ratio)) | |
576 | goto error; | |
577 | } | |
578 | ||
579 | /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We | |
580 | * add 16 more samples in the formula below just as safeguard, because | |
581 | * resampler->process sometimes reports more output samples than the | |
582 | * formula below calculates. Ideally, audio resamplers should have a | |
583 | * function to return the number of samples they will output given a | |
584 | * count of input samples. */ | |
585 | samples = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio); | |
586 | ogg_buffer = (float*)memalign_alloc(16, | |
587 | (((samples + 16) + 15) & ~15) * sizeof(float)); | |
588 | ||
589 | if (!ogg_buffer) | |
590 | { | |
591 | if (resamp && resampler_data) | |
592 | resamp->free(resampler_data); | |
593 | goto error; | |
594 | } | |
595 | ||
596 | voice->types.ogg.resampler = resamp; | |
597 | voice->types.ogg.resampler_data = resampler_data; | |
598 | voice->types.ogg.buffer = (float*)ogg_buffer; | |
599 | voice->types.ogg.buf_samples = samples; | |
600 | voice->types.ogg.ratio = ratio; | |
601 | voice->types.ogg.stream = stb_vorbis; | |
602 | voice->types.ogg.position = 0; | |
603 | voice->types.ogg.samples = 0; | |
604 | ||
605 | return true; | |
606 | ||
607 | error: | |
608 | stb_vorbis_close(stb_vorbis); | |
609 | return false; | |
610 | } | |
611 | ||
612 | static void audio_mixer_release_ogg(audio_mixer_voice_t* voice) | |
613 | { | |
614 | if (voice->types.ogg.stream) | |
615 | stb_vorbis_close(voice->types.ogg.stream); | |
616 | if (voice->types.ogg.resampler && voice->types.ogg.resampler_data) | |
617 | voice->types.ogg.resampler->free(voice->types.ogg.resampler_data); | |
618 | if (voice->types.ogg.buffer) | |
619 | memalign_free(voice->types.ogg.buffer); | |
620 | } | |
621 | ||
622 | #endif | |
623 | ||
624 | #ifdef HAVE_IBXM | |
625 | static bool audio_mixer_play_mod( | |
626 | audio_mixer_sound_t* sound, | |
627 | audio_mixer_voice_t* voice, | |
628 | bool repeat, float volume, | |
629 | audio_mixer_stop_cb_t stop_cb) | |
630 | { | |
631 | struct data data; | |
632 | char message[64]; | |
633 | int buf_samples = 0; | |
634 | int samples = 0; | |
635 | void *mod_buffer = NULL; | |
636 | struct module* module = NULL; | |
637 | struct replay* replay = NULL; | |
638 | ||
639 | data.buffer = (char*)sound->types.mod.data; | |
640 | data.length = sound->types.mod.size; | |
641 | module = module_load(&data, message); | |
642 | ||
643 | if (!module) | |
644 | { | |
645 | printf("audio_mixer_play_mod module_load() failed with error: %s\n", message); | |
646 | goto error; | |
647 | } | |
648 | ||
649 | if (voice->types.mod.module) | |
650 | dispose_module(voice->types.mod.module); | |
651 | ||
652 | voice->types.mod.module = module; | |
653 | ||
654 | replay = new_replay(module, s_rate, 1); | |
655 | ||
656 | if (!replay) | |
657 | { | |
658 | printf("audio_mixer_play_mod new_replay() failed\n"); | |
659 | goto error; | |
660 | } | |
661 | ||
662 | buf_samples = calculate_mix_buf_len(s_rate); | |
663 | mod_buffer = memalign_alloc(16, ((buf_samples + 15) & ~15) * sizeof(int)); | |
664 | ||
665 | if (!mod_buffer) | |
666 | { | |
667 | printf("audio_mixer_play_mod cannot allocate mod_buffer !\n"); | |
668 | goto error; | |
669 | } | |
670 | ||
671 | samples = replay_calculate_duration(replay); | |
672 | ||
673 | if (!samples) | |
674 | { | |
675 | printf("audio_mixer_play_mod cannot retrieve duration !\n"); | |
676 | goto error; | |
677 | } | |
678 | ||
679 | voice->types.mod.buffer = (int*)mod_buffer; | |
680 | voice->types.mod.buf_samples = buf_samples; | |
681 | voice->types.mod.stream = replay; | |
682 | voice->types.mod.position = 0; | |
683 | voice->types.mod.samples = 0; /* samples; */ | |
684 | ||
685 | return true; | |
686 | ||
687 | error: | |
688 | if (mod_buffer) | |
689 | memalign_free(mod_buffer); | |
690 | if (module) | |
691 | dispose_module(module); | |
692 | return false; | |
693 | ||
694 | } | |
695 | ||
696 | static void audio_mixer_release_mod(audio_mixer_voice_t* voice) | |
697 | { | |
698 | if (voice->types.mod.stream) | |
699 | dispose_replay(voice->types.mod.stream); | |
700 | if (voice->types.mod.buffer) | |
701 | memalign_free(voice->types.mod.buffer); | |
702 | } | |
703 | #endif | |
704 | ||
705 | #ifdef HAVE_DR_FLAC | |
706 | static bool audio_mixer_play_flac( | |
707 | audio_mixer_sound_t* sound, | |
708 | audio_mixer_voice_t* voice, | |
709 | bool repeat, float volume, | |
710 | const char *resampler_ident, | |
711 | enum resampler_quality quality, | |
712 | audio_mixer_stop_cb_t stop_cb) | |
713 | { | |
714 | float ratio = 1.0f; | |
715 | unsigned samples = 0; | |
716 | void *flac_buffer = NULL; | |
717 | void *resampler_data = NULL; | |
718 | const retro_resampler_t* resamp = NULL; | |
719 | drflac *dr_flac = drflac_open_memory((const unsigned char*)sound->types.flac.data,sound->types.flac.size); | |
720 | ||
721 | if (!dr_flac) | |
722 | return false; | |
723 | if (dr_flac->sampleRate != s_rate) | |
724 | { | |
725 | ratio = (double)s_rate / (double)(dr_flac->sampleRate); | |
726 | ||
727 | if (!retro_resampler_realloc(&resampler_data, | |
728 | &resamp, resampler_ident, quality, | |
729 | ratio)) | |
730 | goto error; | |
731 | } | |
732 | ||
733 | /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We | |
734 | * add 16 more samples in the formula below just as safeguard, because | |
735 | * resampler->process sometimes reports more output samples than the | |
736 | * formula below calculates. Ideally, audio resamplers should have a | |
737 | * function to return the number of samples they will output given a | |
738 | * count of input samples. */ | |
739 | samples = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio); | |
740 | flac_buffer = (float*)memalign_alloc(16, | |
741 | (((samples + 16) + 15) & ~15) * sizeof(float)); | |
742 | ||
743 | if (!flac_buffer) | |
744 | { | |
745 | if (resamp && resamp->free) | |
746 | resamp->free(resampler_data); | |
747 | goto error; | |
748 | } | |
749 | ||
750 | voice->types.flac.resampler = resamp; | |
751 | voice->types.flac.resampler_data = resampler_data; | |
752 | voice->types.flac.buffer = (float*)flac_buffer; | |
753 | voice->types.flac.buf_samples = samples; | |
754 | voice->types.flac.ratio = ratio; | |
755 | voice->types.flac.stream = dr_flac; | |
756 | voice->types.flac.position = 0; | |
757 | voice->types.flac.samples = 0; | |
758 | ||
759 | return true; | |
760 | ||
761 | error: | |
762 | drflac_close(dr_flac); | |
763 | return false; | |
764 | } | |
765 | ||
766 | static void audio_mixer_release_flac(audio_mixer_voice_t* voice) | |
767 | { | |
768 | if (voice->types.flac.stream) | |
769 | drflac_close(voice->types.flac.stream); | |
770 | if (voice->types.flac.resampler && voice->types.flac.resampler_data) | |
771 | voice->types.flac.resampler->free(voice->types.flac.resampler_data); | |
772 | if (voice->types.flac.buffer) | |
773 | memalign_free(voice->types.flac.buffer); | |
774 | } | |
775 | #endif | |
776 | ||
777 | #ifdef HAVE_DR_MP3 | |
778 | static bool audio_mixer_play_mp3( | |
779 | audio_mixer_sound_t* sound, | |
780 | audio_mixer_voice_t* voice, | |
781 | bool repeat, float volume, | |
782 | const char *resampler_ident, | |
783 | enum resampler_quality quality, | |
784 | audio_mixer_stop_cb_t stop_cb) | |
785 | { | |
786 | float ratio = 1.0f; | |
787 | unsigned samples = 0; | |
788 | void *mp3_buffer = NULL; | |
789 | void *resampler_data = NULL; | |
790 | const retro_resampler_t* resamp = NULL; | |
791 | bool res; | |
792 | ||
793 | res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL); | |
794 | ||
795 | if (!res) | |
796 | return false; | |
797 | ||
798 | if (voice->types.mp3.stream.sampleRate != s_rate) | |
799 | { | |
800 | ratio = (double)s_rate / (double)(voice->types.mp3.stream.sampleRate); | |
801 | ||
802 | if (!retro_resampler_realloc(&resampler_data, | |
803 | &resamp, resampler_ident, quality, | |
804 | ratio)) | |
805 | goto error; | |
806 | } | |
807 | ||
808 | /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We | |
809 | * add 16 more samples in the formula below just as safeguard, because | |
810 | * resampler->process sometimes reports more output samples than the | |
811 | * formula below calculates. Ideally, audio resamplers should have a | |
812 | * function to return the number of samples they will output given a | |
813 | * count of input samples. */ | |
814 | samples = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio); | |
815 | mp3_buffer = (float*)memalign_alloc(16, | |
816 | (((samples + 16) + 15) & ~15) * sizeof(float)); | |
817 | ||
818 | if (!mp3_buffer) | |
819 | { | |
820 | if (resamp && resampler_data) | |
821 | resamp->free(resampler_data); | |
822 | goto error; | |
823 | } | |
824 | ||
825 | voice->types.mp3.resampler = resamp; | |
826 | voice->types.mp3.resampler_data = resampler_data; | |
827 | voice->types.mp3.buffer = (float*)mp3_buffer; | |
828 | voice->types.mp3.buf_samples = samples; | |
829 | voice->types.mp3.ratio = ratio; | |
830 | voice->types.mp3.position = 0; | |
831 | voice->types.mp3.samples = 0; | |
832 | ||
833 | return true; | |
834 | ||
835 | error: | |
836 | drmp3_uninit(&voice->types.mp3.stream); | |
837 | return false; | |
838 | } | |
839 | ||
840 | static void audio_mixer_release_mp3(audio_mixer_voice_t* voice) | |
841 | { | |
842 | if (voice->types.mp3.resampler && voice->types.mp3.resampler_data) | |
843 | voice->types.mp3.resampler->free(voice->types.mp3.resampler_data); | |
844 | if (voice->types.mp3.buffer) | |
845 | memalign_free(voice->types.mp3.buffer); | |
846 | if (voice->types.mp3.stream.pData) | |
847 | drmp3_uninit(&voice->types.mp3.stream); | |
848 | } | |
849 | ||
850 | #endif | |
851 | ||
852 | audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, | |
853 | bool repeat, float volume, | |
854 | const char *resampler_ident, | |
855 | enum resampler_quality quality, | |
856 | audio_mixer_stop_cb_t stop_cb) | |
857 | { | |
858 | unsigned i; | |
859 | bool res = false; | |
860 | audio_mixer_voice_t* voice = s_voices; | |
861 | ||
862 | if (!sound) | |
863 | return NULL; | |
864 | ||
865 | for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) | |
866 | { | |
867 | if (voice->type != AUDIO_MIXER_TYPE_NONE) | |
868 | continue; | |
869 | ||
870 | AUDIO_MIXER_LOCK(voice); | |
871 | ||
872 | if (voice->type != AUDIO_MIXER_TYPE_NONE) | |
873 | { | |
874 | AUDIO_MIXER_UNLOCK(voice); | |
875 | continue; | |
876 | } | |
877 | ||
878 | /* claim the voice, also helps with cleanup on error */ | |
879 | voice->type = sound->type; | |
880 | ||
881 | switch (sound->type) | |
882 | { | |
883 | case AUDIO_MIXER_TYPE_WAV: | |
884 | res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb); | |
885 | break; | |
886 | case AUDIO_MIXER_TYPE_OGG: | |
887 | #ifdef HAVE_STB_VORBIS | |
888 | res = audio_mixer_play_ogg(sound, voice, repeat, volume, | |
889 | resampler_ident, quality, stop_cb); | |
890 | #endif | |
891 | break; | |
892 | case AUDIO_MIXER_TYPE_MOD: | |
893 | #ifdef HAVE_IBXM | |
894 | res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb); | |
895 | #endif | |
896 | break; | |
897 | case AUDIO_MIXER_TYPE_FLAC: | |
898 | #ifdef HAVE_DR_FLAC | |
899 | res = audio_mixer_play_flac(sound, voice, repeat, volume, | |
900 | resampler_ident, quality, stop_cb); | |
901 | #endif | |
902 | break; | |
903 | case AUDIO_MIXER_TYPE_MP3: | |
904 | #ifdef HAVE_DR_MP3 | |
905 | res = audio_mixer_play_mp3(sound, voice, repeat, volume, | |
906 | resampler_ident, quality, stop_cb); | |
907 | #endif | |
908 | break; | |
909 | case AUDIO_MIXER_TYPE_NONE: | |
910 | break; | |
911 | } | |
912 | ||
913 | break; | |
914 | } | |
915 | ||
916 | if (res) | |
917 | { | |
918 | voice->repeat = repeat; | |
919 | voice->volume = volume; | |
920 | voice->sound = sound; | |
921 | voice->stop_cb = stop_cb; | |
922 | AUDIO_MIXER_UNLOCK(voice); | |
923 | } | |
924 | else | |
925 | { | |
926 | if (i < AUDIO_MIXER_MAX_VOICES) | |
927 | { | |
928 | audio_mixer_release(voice); | |
929 | AUDIO_MIXER_UNLOCK(voice); | |
930 | } | |
931 | voice = NULL; | |
932 | } | |
933 | ||
934 | return voice; | |
935 | } | |
936 | ||
937 | /* Need to hold lock for voice. */ | |
938 | static void audio_mixer_release(audio_mixer_voice_t* voice) | |
939 | { | |
940 | if (!voice) | |
941 | return; | |
942 | ||
943 | switch (voice->type) | |
944 | { | |
945 | #ifdef HAVE_STB_VORBIS | |
946 | case AUDIO_MIXER_TYPE_OGG: | |
947 | audio_mixer_release_ogg(voice); | |
948 | break; | |
949 | #endif | |
950 | #ifdef HAVE_IBXM | |
951 | case AUDIO_MIXER_TYPE_MOD: | |
952 | audio_mixer_release_mod(voice); | |
953 | break; | |
954 | #endif | |
955 | #ifdef HAVE_DR_FLAC | |
956 | case AUDIO_MIXER_TYPE_FLAC: | |
957 | audio_mixer_release_flac(voice); | |
958 | break; | |
959 | #endif | |
960 | #ifdef HAVE_DR_MP3 | |
961 | case AUDIO_MIXER_TYPE_MP3: | |
962 | audio_mixer_release_mp3(voice); | |
963 | break; | |
964 | #endif | |
965 | default: | |
966 | break; | |
967 | } | |
968 | ||
969 | memset(&voice->types, 0, sizeof(voice->types)); | |
970 | voice->type = AUDIO_MIXER_TYPE_NONE; | |
971 | } | |
972 | ||
973 | void audio_mixer_stop(audio_mixer_voice_t* voice) | |
974 | { | |
975 | audio_mixer_stop_cb_t stop_cb = NULL; | |
976 | audio_mixer_sound_t* sound = NULL; | |
977 | ||
978 | if (voice) | |
979 | { | |
980 | AUDIO_MIXER_LOCK(voice); | |
981 | stop_cb = voice->stop_cb; | |
982 | sound = voice->sound; | |
983 | ||
984 | audio_mixer_release(voice); | |
985 | ||
986 | AUDIO_MIXER_UNLOCK(voice); | |
987 | ||
988 | if (stop_cb) | |
989 | stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED); | |
990 | } | |
991 | } | |
992 | ||
993 | static void audio_mixer_mix_wav(float* buffer, size_t num_frames, | |
994 | audio_mixer_voice_t* voice, | |
995 | float volume) | |
996 | { | |
997 | int i; | |
998 | unsigned buf_free = (unsigned)(num_frames * 2); | |
999 | const audio_mixer_sound_t* sound = voice->sound; | |
1000 | unsigned pcm_available = sound->types.wav.frames | |
1001 | * 2 - voice->types.wav.position; | |
1002 | const float* pcm = sound->types.wav.pcm + | |
1003 | voice->types.wav.position; | |
1004 | ||
1005 | again: | |
1006 | if (pcm_available < buf_free) | |
1007 | { | |
1008 | for (i = pcm_available; i != 0; i--) | |
1009 | *buffer++ += *pcm++ * volume; | |
1010 | ||
1011 | if (voice->repeat) | |
1012 | { | |
1013 | if (voice->stop_cb) | |
1014 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); | |
1015 | ||
1016 | buf_free -= pcm_available; | |
1017 | pcm_available = sound->types.wav.frames * 2; | |
1018 | pcm = sound->types.wav.pcm; | |
1019 | voice->types.wav.position = 0; | |
1020 | goto again; | |
1021 | } | |
1022 | ||
1023 | if (voice->stop_cb) | |
1024 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); | |
1025 | ||
1026 | audio_mixer_release(voice); | |
1027 | } | |
1028 | else | |
1029 | { | |
1030 | for (i = buf_free; i != 0; i--) | |
1031 | *buffer++ += *pcm++ * volume; | |
1032 | ||
1033 | voice->types.wav.position += buf_free; | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | #ifdef HAVE_STB_VORBIS | |
1038 | static void audio_mixer_mix_ogg(float* buffer, size_t num_frames, | |
1039 | audio_mixer_voice_t* voice, | |
1040 | float volume) | |
1041 | { | |
1042 | int i; | |
1043 | float* temp_buffer = NULL; | |
1044 | unsigned buf_free = (unsigned)(num_frames * 2); | |
1045 | unsigned temp_samples = 0; | |
1046 | float* pcm = NULL; | |
1047 | ||
1048 | if (!voice->types.ogg.stream) | |
1049 | return; | |
1050 | ||
1051 | if (voice->types.ogg.position == voice->types.ogg.samples) | |
1052 | { | |
1053 | again: | |
1054 | if (temp_buffer == NULL) | |
1055 | temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float)); | |
1056 | ||
1057 | temp_samples = stb_vorbis_get_samples_float_interleaved( | |
1058 | voice->types.ogg.stream, 2, temp_buffer, | |
1059 | AUDIO_MIXER_TEMP_BUFFER) * 2; | |
1060 | ||
1061 | if (temp_samples == 0) | |
1062 | { | |
1063 | if (voice->repeat) | |
1064 | { | |
1065 | if (voice->stop_cb) | |
1066 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); | |
1067 | ||
1068 | stb_vorbis_seek_start(voice->types.ogg.stream); | |
1069 | goto again; | |
1070 | } | |
1071 | ||
1072 | if (voice->stop_cb) | |
1073 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); | |
1074 | ||
1075 | audio_mixer_release(voice); | |
1076 | goto cleanup; | |
1077 | } | |
1078 | ||
1079 | if (voice->types.ogg.resampler) | |
1080 | { | |
1081 | struct resampler_data info; | |
1082 | info.data_in = temp_buffer; | |
1083 | info.data_out = voice->types.ogg.buffer; | |
1084 | info.input_frames = temp_samples / 2; | |
1085 | info.output_frames = 0; | |
1086 | info.ratio = voice->types.ogg.ratio; | |
1087 | ||
1088 | voice->types.ogg.resampler->process( | |
1089 | voice->types.ogg.resampler_data, &info); | |
1090 | } | |
1091 | else | |
1092 | memcpy(voice->types.ogg.buffer, temp_buffer, | |
1093 | temp_samples * sizeof(float)); | |
1094 | ||
1095 | voice->types.ogg.position = 0; | |
1096 | voice->types.ogg.samples = voice->types.ogg.buf_samples; | |
1097 | } | |
1098 | ||
1099 | pcm = voice->types.ogg.buffer + voice->types.ogg.position; | |
1100 | ||
1101 | if (voice->types.ogg.samples < buf_free) | |
1102 | { | |
1103 | for (i = voice->types.ogg.samples; i != 0; i--) | |
1104 | *buffer++ += *pcm++ * volume; | |
1105 | ||
1106 | buf_free -= voice->types.ogg.samples; | |
1107 | goto again; | |
1108 | } | |
1109 | ||
1110 | for (i = buf_free; i != 0; --i ) | |
1111 | *buffer++ += *pcm++ * volume; | |
1112 | ||
1113 | voice->types.ogg.position += buf_free; | |
1114 | voice->types.ogg.samples -= buf_free; | |
1115 | ||
1116 | cleanup: | |
1117 | if (temp_buffer != NULL) | |
1118 | free(temp_buffer); | |
1119 | } | |
1120 | #endif | |
1121 | ||
1122 | #ifdef HAVE_IBXM | |
1123 | static void audio_mixer_mix_mod(float* buffer, size_t num_frames, | |
1124 | audio_mixer_voice_t* voice, | |
1125 | float volume) | |
1126 | { | |
1127 | int i; | |
1128 | float samplef = 0.0f; | |
1129 | unsigned temp_samples = 0; | |
1130 | unsigned buf_free = (unsigned)(num_frames * 2); | |
1131 | int* pcm = NULL; | |
1132 | ||
1133 | if (voice->types.mod.samples == 0) | |
1134 | { | |
1135 | again: | |
1136 | temp_samples = replay_get_audio( | |
1137 | voice->types.mod.stream, voice->types.mod.buffer, 0 ) * 2; | |
1138 | ||
1139 | if (temp_samples == 0) | |
1140 | { | |
1141 | if (voice->repeat) | |
1142 | { | |
1143 | if (voice->stop_cb) | |
1144 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); | |
1145 | ||
1146 | replay_seek( voice->types.mod.stream, 0); | |
1147 | goto again; | |
1148 | } | |
1149 | ||
1150 | if (voice->stop_cb) | |
1151 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); | |
1152 | ||
1153 | audio_mixer_release(voice); | |
1154 | return; | |
1155 | } | |
1156 | ||
1157 | voice->types.mod.position = 0; | |
1158 | voice->types.mod.samples = temp_samples; | |
1159 | } | |
1160 | pcm = voice->types.mod.buffer + voice->types.mod.position; | |
1161 | ||
1162 | if (voice->types.mod.samples < buf_free) | |
1163 | { | |
1164 | for (i = voice->types.mod.samples; i != 0; i--) | |
1165 | { | |
1166 | samplef = ((float)(*pcm++) + 32768.0f) / 65535.0f; | |
1167 | samplef = samplef * 2.0f - 1.0f; | |
1168 | *buffer++ += samplef * volume; | |
1169 | } | |
1170 | ||
1171 | buf_free -= voice->types.mod.samples; | |
1172 | goto again; | |
1173 | } | |
1174 | ||
1175 | for (i = buf_free; i != 0; --i ) | |
1176 | { | |
1177 | samplef = ((float)(*pcm++) + 32768.0f) / 65535.0f; | |
1178 | samplef = samplef * 2.0f - 1.0f; | |
1179 | *buffer++ += samplef * volume; | |
1180 | } | |
1181 | ||
1182 | voice->types.mod.position += buf_free; | |
1183 | voice->types.mod.samples -= buf_free; | |
1184 | } | |
1185 | #endif | |
1186 | ||
1187 | #ifdef HAVE_DR_FLAC | |
1188 | static void audio_mixer_mix_flac(float* buffer, size_t num_frames, | |
1189 | audio_mixer_voice_t* voice, | |
1190 | float volume) | |
1191 | { | |
1192 | int i; | |
1193 | struct resampler_data info; | |
1194 | float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 }; | |
1195 | unsigned buf_free = (unsigned)(num_frames * 2); | |
1196 | unsigned temp_samples = 0; | |
1197 | float *pcm = NULL; | |
1198 | ||
1199 | if (voice->types.flac.position == voice->types.flac.samples) | |
1200 | { | |
1201 | again: | |
1202 | temp_samples = (unsigned)drflac_read_f32( voice->types.flac.stream, AUDIO_MIXER_TEMP_BUFFER, temp_buffer); | |
1203 | if (temp_samples == 0) | |
1204 | { | |
1205 | if (voice->repeat) | |
1206 | { | |
1207 | if (voice->stop_cb) | |
1208 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); | |
1209 | ||
1210 | drflac_seek_to_sample(voice->types.flac.stream,0); | |
1211 | goto again; | |
1212 | } | |
1213 | ||
1214 | if (voice->stop_cb) | |
1215 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); | |
1216 | ||
1217 | audio_mixer_release(voice); | |
1218 | return; | |
1219 | } | |
1220 | ||
1221 | info.data_in = temp_buffer; | |
1222 | info.data_out = voice->types.flac.buffer; | |
1223 | info.input_frames = temp_samples / 2; | |
1224 | info.output_frames = 0; | |
1225 | info.ratio = voice->types.flac.ratio; | |
1226 | ||
1227 | if (voice->types.flac.resampler) | |
1228 | voice->types.flac.resampler->process( | |
1229 | voice->types.flac.resampler_data, &info); | |
1230 | else | |
1231 | memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float)); | |
1232 | voice->types.flac.position = 0; | |
1233 | voice->types.flac.samples = voice->types.flac.buf_samples; | |
1234 | } | |
1235 | ||
1236 | pcm = voice->types.flac.buffer + voice->types.flac.position; | |
1237 | ||
1238 | if (voice->types.flac.samples < buf_free) | |
1239 | { | |
1240 | for (i = voice->types.flac.samples; i != 0; i--) | |
1241 | *buffer++ += *pcm++ * volume; | |
1242 | ||
1243 | buf_free -= voice->types.flac.samples; | |
1244 | goto again; | |
1245 | } | |
1246 | ||
1247 | for (i = buf_free; i != 0; --i ) | |
1248 | *buffer++ += *pcm++ * volume; | |
1249 | ||
1250 | voice->types.flac.position += buf_free; | |
1251 | voice->types.flac.samples -= buf_free; | |
1252 | } | |
1253 | #endif | |
1254 | ||
1255 | #ifdef HAVE_DR_MP3 | |
1256 | static void audio_mixer_mix_mp3(float* buffer, size_t num_frames, | |
1257 | audio_mixer_voice_t* voice, | |
1258 | float volume) | |
1259 | { | |
1260 | int i; | |
1261 | struct resampler_data info; | |
1262 | float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 }; | |
1263 | unsigned buf_free = (unsigned)(num_frames * 2); | |
1264 | unsigned temp_samples = 0; | |
1265 | float* pcm = NULL; | |
1266 | ||
1267 | if (voice->types.mp3.position == voice->types.mp3.samples) | |
1268 | { | |
1269 | again: | |
1270 | temp_samples = (unsigned)drmp3_read_f32( | |
1271 | &voice->types.mp3.stream, | |
1272 | AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2; | |
1273 | ||
1274 | if (temp_samples == 0) | |
1275 | { | |
1276 | if (voice->repeat) | |
1277 | { | |
1278 | if (voice->stop_cb) | |
1279 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED); | |
1280 | ||
1281 | drmp3_seek_to_frame(&voice->types.mp3.stream,0); | |
1282 | goto again; | |
1283 | } | |
1284 | ||
1285 | if (voice->stop_cb) | |
1286 | voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); | |
1287 | ||
1288 | audio_mixer_release(voice); | |
1289 | return; | |
1290 | } | |
1291 | ||
1292 | info.data_in = temp_buffer; | |
1293 | info.data_out = voice->types.mp3.buffer; | |
1294 | info.input_frames = temp_samples / 2; | |
1295 | info.output_frames = 0; | |
1296 | info.ratio = voice->types.mp3.ratio; | |
1297 | ||
1298 | if (voice->types.mp3.resampler) | |
1299 | voice->types.mp3.resampler->process( | |
1300 | voice->types.mp3.resampler_data, &info); | |
1301 | else | |
1302 | memcpy(voice->types.mp3.buffer, temp_buffer, | |
1303 | temp_samples * sizeof(float)); | |
1304 | voice->types.mp3.position = 0; | |
1305 | voice->types.mp3.samples = voice->types.mp3.buf_samples; | |
1306 | } | |
1307 | ||
1308 | pcm = voice->types.mp3.buffer + voice->types.mp3.position; | |
1309 | ||
1310 | if (voice->types.mp3.samples < buf_free) | |
1311 | { | |
1312 | for (i = voice->types.mp3.samples; i != 0; i--) | |
1313 | *buffer++ += *pcm++ * volume; | |
1314 | ||
1315 | buf_free -= voice->types.mp3.samples; | |
1316 | goto again; | |
1317 | } | |
1318 | ||
1319 | for (i = buf_free; i != 0; --i ) | |
1320 | *buffer++ += *pcm++ * volume; | |
1321 | ||
1322 | voice->types.mp3.position += buf_free; | |
1323 | voice->types.mp3.samples -= buf_free; | |
1324 | } | |
1325 | #endif | |
1326 | ||
1327 | void audio_mixer_mix(float* buffer, size_t num_frames, | |
1328 | float volume_override, bool override) | |
1329 | { | |
1330 | unsigned i; | |
1331 | size_t j = 0; | |
1332 | float* sample = NULL; | |
1333 | audio_mixer_voice_t* voice = s_voices; | |
1334 | ||
1335 | for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) | |
1336 | { | |
1337 | float volume; | |
1338 | ||
1339 | AUDIO_MIXER_LOCK(voice); | |
1340 | ||
1341 | volume = (override) ? volume_override : voice->volume; | |
1342 | ||
1343 | switch (voice->type) | |
1344 | { | |
1345 | case AUDIO_MIXER_TYPE_WAV: | |
1346 | audio_mixer_mix_wav(buffer, num_frames, voice, volume); | |
1347 | break; | |
1348 | case AUDIO_MIXER_TYPE_OGG: | |
1349 | #ifdef HAVE_STB_VORBIS | |
1350 | audio_mixer_mix_ogg(buffer, num_frames, voice, volume); | |
1351 | #endif | |
1352 | break; | |
1353 | case AUDIO_MIXER_TYPE_MOD: | |
1354 | #ifdef HAVE_IBXM | |
1355 | audio_mixer_mix_mod(buffer, num_frames, voice, volume); | |
1356 | #endif | |
1357 | break; | |
1358 | case AUDIO_MIXER_TYPE_FLAC: | |
1359 | #ifdef HAVE_DR_FLAC | |
1360 | audio_mixer_mix_flac(buffer, num_frames, voice, volume); | |
1361 | #endif | |
1362 | break; | |
1363 | case AUDIO_MIXER_TYPE_MP3: | |
1364 | #ifdef HAVE_DR_MP3 | |
1365 | audio_mixer_mix_mp3(buffer, num_frames, voice, volume); | |
1366 | #endif | |
1367 | break; | |
1368 | case AUDIO_MIXER_TYPE_NONE: | |
1369 | break; | |
1370 | } | |
1371 | ||
1372 | AUDIO_MIXER_UNLOCK(voice); | |
1373 | } | |
1374 | ||
1375 | for (j = 0, sample = buffer; j < num_frames * 2; j++, sample++) | |
1376 | { | |
1377 | if (*sample < -1.0f) | |
1378 | *sample = -1.0f; | |
1379 | else if (*sample > 1.0f) | |
1380 | *sample = 1.0f; | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice) | |
1385 | { | |
1386 | if (!voice) | |
1387 | return 0.0f; | |
1388 | ||
1389 | return voice->volume; | |
1390 | } | |
1391 | ||
1392 | void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val) | |
1393 | { | |
1394 | if (!voice) | |
1395 | return; | |
1396 | ||
1397 | AUDIO_MIXER_LOCK(voice); | |
1398 | voice->volume = val; | |
1399 | AUDIO_MIXER_UNLOCK(voice); | |
1400 | } |