1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../SDL_internal.h"
22
23/* Functions for audio drivers to perform runtime conversion of audio format */
24
25/* FIXME: Channel weights when converting from more channels to fewer may need to be adjusted, see https://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
26*/
27
28#include "SDL.h"
29#include "SDL_audio.h"
30#include "SDL_audio_c.h"
31
32#include "SDL_loadso.h"
33#include "../SDL_dataqueue.h"
34#include "SDL_cpuinfo.h"
35
36#define DEBUG_AUDIOSTREAM 0
37
38#ifdef __SSE3__
39#define HAVE_SSE3_INTRINSICS 1
40#endif
41
42#if HAVE_SSE3_INTRINSICS
43/* Convert from stereo to mono. Average left and right. */
44static void SDLCALL
45SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
46{
47 float *dst = (float *) cvt->buf;
48 const float *src = dst;
49 int i = cvt->len_cvt / 8;
50
51 LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
52 SDL_assert(format == AUDIO_F32SYS);
53
54 /* We can only do this if dst is aligned to 16 bytes; since src is the
55 same pointer and it moves by 2, it can't be forcibly aligned. */
56 if ((((size_t) dst) & 15) == 0) {
57 /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
58 const __m128 divby2 = _mm_set1_ps(0.5f);
59 while (i >= 4) { /* 4 * float32 */
60 _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
61 i -= 4; src += 8; dst += 4;
62 }
63 }
64
65 /* Finish off any leftovers with scalar operations. */
66 while (i) {
67 *dst = (src[0] + src[1]) * 0.5f;
68 dst++; i--; src += 2;
69 }
70
71 cvt->len_cvt /= 2;
72 if (cvt->filters[++cvt->filter_index]) {
73 cvt->filters[cvt->filter_index] (cvt, format);
74 }
75}
76#endif
77
78/* Convert from stereo to mono. Average left and right. */
79static void SDLCALL
80SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
81{
82 float *dst = (float *) cvt->buf;
83 const float *src = dst;
84 int i;
85
86 LOG_DEBUG_CONVERT("stereo", "mono");
87 SDL_assert(format == AUDIO_F32SYS);
88
89 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
90 *(dst++) = (src[0] + src[1]) * 0.5f;
91 }
92
93 cvt->len_cvt /= 2;
94 if (cvt->filters[++cvt->filter_index]) {
95 cvt->filters[cvt->filter_index] (cvt, format);
96 }
97}
98
99
100/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
101static void SDLCALL
102SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
103{
104 float *dst = (float *) cvt->buf;
105 const float *src = dst;
106 int i;
107
108 LOG_DEBUG_CONVERT("5.1", "stereo");
109 SDL_assert(format == AUDIO_F32SYS);
110
111 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
112 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
113 const float front_center_distributed = src[2] * 0.5f;
114 dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
115 dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
116 }
117
118 cvt->len_cvt /= 3;
119 if (cvt->filters[++cvt->filter_index]) {
120 cvt->filters[cvt->filter_index] (cvt, format);
121 }
122}
123
124
125/* Convert from quad to stereo. Average left and right. */
126static void SDLCALL
127SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
128{
129 float *dst = (float *) cvt->buf;
130 const float *src = dst;
131 int i;
132
133 LOG_DEBUG_CONVERT("quad", "stereo");
134 SDL_assert(format == AUDIO_F32SYS);
135
136 for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
137 dst[0] = (src[0] + src[2]) * 0.5f; /* left */
138 dst[1] = (src[1] + src[3]) * 0.5f; /* right */
139 }
140
141 cvt->len_cvt /= 2;
142 if (cvt->filters[++cvt->filter_index]) {
143 cvt->filters[cvt->filter_index] (cvt, format);
144 }
145}
146
147
148/* Convert from 7.1 to 5.1. Distribute sides across front and back. */
149static void SDLCALL
150SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
151{
152 float *dst = (float *) cvt->buf;
153 const float *src = dst;
154 int i;
155
156 LOG_DEBUG_CONVERT("7.1", "5.1");
157 SDL_assert(format == AUDIO_F32SYS);
158
159 for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
160 const float surround_left_distributed = src[6] * 0.5f;
161 const float surround_right_distributed = src[7] * 0.5f;
162 dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
163 dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
164 dst[2] = src[2] / 1.5f; /* CC */
165 dst[3] = src[3] / 1.5f; /* LFE */
166 dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
167 dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
168 }
169
170 cvt->len_cvt /= 8;
171 cvt->len_cvt *= 6;
172 if (cvt->filters[++cvt->filter_index]) {
173 cvt->filters[cvt->filter_index] (cvt, format);
174 }
175}
176
177
178/* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
179static void SDLCALL
180SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
181{
182 float *dst = (float *) cvt->buf;
183 const float *src = dst;
184 int i;
185
186 LOG_DEBUG_CONVERT("5.1", "quad");
187 SDL_assert(format == AUDIO_F32SYS);
188
189 /* SDL's 4.0 layout: FL+FR+BL+BR */
190 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
191 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
192 const float front_center_distributed = src[2] * 0.5f;
193 dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
194 dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
195 dst[2] = src[4] / 1.5f; /* BL */
196 dst[3] = src[5] / 1.5f; /* BR */
197 }
198
199 cvt->len_cvt /= 6;
200 cvt->len_cvt *= 4;
201 if (cvt->filters[++cvt->filter_index]) {
202 cvt->filters[cvt->filter_index] (cvt, format);
203 }
204}
205
206
207/* Upmix mono to stereo (by duplication) */
208static void SDLCALL
209SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
210{
211 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
212 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
213 int i;
214
215 LOG_DEBUG_CONVERT("mono", "stereo");
216 SDL_assert(format == AUDIO_F32SYS);
217
218 for (i = cvt->len_cvt / sizeof (float); i; --i) {
219 src--;
220 dst -= 2;
221 dst[0] = dst[1] = *src;
222 }
223
224 cvt->len_cvt *= 2;
225 if (cvt->filters[++cvt->filter_index]) {
226 cvt->filters[cvt->filter_index] (cvt, format);
227 }
228}
229
230
231/* Upmix stereo to a pseudo-5.1 stream */
232static void SDLCALL
233SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
234{
235 int i;
236 float lf, rf, ce;
237 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
238 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
239
240 LOG_DEBUG_CONVERT("stereo", "5.1");
241 SDL_assert(format == AUDIO_F32SYS);
242
243 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
244 dst -= 6;
245 src -= 2;
246 lf = src[0];
247 rf = src[1];
248 ce = (lf + rf) * 0.5f;
249 /* !!! FIXME: FL and FR may clip */
250 dst[0] = lf + (lf - ce); /* FL */
251 dst[1] = rf + (rf - ce); /* FR */
252 dst[2] = ce; /* FC */
253 dst[3] = 0; /* LFE (only meant for special LFE effects) */
254 dst[4] = lf; /* BL */
255 dst[5] = rf; /* BR */
256 }
257
258 cvt->len_cvt *= 3;
259 if (cvt->filters[++cvt->filter_index]) {
260 cvt->filters[cvt->filter_index] (cvt, format);
261 }
262}
263
264
265/* Upmix quad to a pseudo-5.1 stream */
266static void SDLCALL
267SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
268{
269 int i;
270 float lf, rf, lb, rb, ce;
271 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
272 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
273
274 LOG_DEBUG_CONVERT("quad", "5.1");
275 SDL_assert(format == AUDIO_F32SYS);
276 SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
277
278 for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
279 dst -= 6;
280 src -= 4;
281 lf = src[0];
282 rf = src[1];
283 lb = src[2];
284 rb = src[3];
285 ce = (lf + rf) * 0.5f;
286 /* !!! FIXME: FL and FR may clip */
287 dst[0] = lf + (lf - ce); /* FL */
288 dst[1] = rf + (rf - ce); /* FR */
289 dst[2] = ce; /* FC */
290 dst[3] = 0; /* LFE (only meant for special LFE effects) */
291 dst[4] = lb; /* BL */
292 dst[5] = rb; /* BR */
293 }
294
295 cvt->len_cvt = cvt->len_cvt * 3 / 2;
296 if (cvt->filters[++cvt->filter_index]) {
297 cvt->filters[cvt->filter_index] (cvt, format);
298 }
299}
300
301
302/* Upmix stereo to a pseudo-4.0 stream (by duplication) */
303static void SDLCALL
304SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
305{
306 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
307 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
308 float lf, rf;
309 int i;
310
311 LOG_DEBUG_CONVERT("stereo", "quad");
312 SDL_assert(format == AUDIO_F32SYS);
313
314 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
315 dst -= 4;
316 src -= 2;
317 lf = src[0];
318 rf = src[1];
319 dst[0] = lf; /* FL */
320 dst[1] = rf; /* FR */
321 dst[2] = lf; /* BL */
322 dst[3] = rf; /* BR */
323 }
324
325 cvt->len_cvt *= 2;
326 if (cvt->filters[++cvt->filter_index]) {
327 cvt->filters[cvt->filter_index] (cvt, format);
328 }
329}
330
331
332/* Upmix 5.1 to 7.1 */
333static void SDLCALL
334SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
335{
336 float lf, rf, lb, rb, ls, rs;
337 int i;
338 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
339 float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
340
341 LOG_DEBUG_CONVERT("5.1", "7.1");
342 SDL_assert(format == AUDIO_F32SYS);
343 SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
344
345 for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
346 dst -= 8;
347 src -= 6;
348 lf = src[0];
349 rf = src[1];
350 lb = src[4];
351 rb = src[5];
352 ls = (lf + lb) * 0.5f;
353 rs = (rf + rb) * 0.5f;
354 /* !!! FIXME: these four may clip */
355 lf += lf - ls;
356 rf += rf - ls;
357 lb += lb - ls;
358 rb += rb - ls;
359 dst[3] = src[3]; /* LFE */
360 dst[2] = src[2]; /* FC */
361 dst[7] = rs; /* SR */
362 dst[6] = ls; /* SL */
363 dst[5] = rb; /* BR */
364 dst[4] = lb; /* BL */
365 dst[1] = rf; /* FR */
366 dst[0] = lf; /* FL */
367 }
368
369 cvt->len_cvt = cvt->len_cvt * 4 / 3;
370
371 if (cvt->filters[++cvt->filter_index]) {
372 cvt->filters[cvt->filter_index] (cvt, format);
373 }
374}
375
376/* SDL's resampler uses a "bandlimited interpolation" algorithm:
377 https://ccrma.stanford.edu/~jos/resample/ */
378
379#define RESAMPLER_ZERO_CROSSINGS 5
380#define RESAMPLER_BITS_PER_SAMPLE 16
381#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
382#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
383
384/* This is a "modified" bessel function, so you can't use POSIX j0() */
385static double
386bessel(const double x)
387{
388 const double xdiv2 = x / 2.0;
389 double i0 = 1.0f;
390 double f = 1.0f;
391 int i = 1;
392
393 while (SDL_TRUE) {
394 const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
395 if (diff < 1.0e-21f) {
396 break;
397 }
398 i0 += diff;
399 i++;
400 f *= (double) i;
401 }
402
403 return i0;
404}
405
406/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
407static void
408kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
409{
410 const int lenm1 = tablelen - 1;
411 const int lenm1div2 = lenm1 / 2;
412 int i;
413
414 table[0] = 1.0f;
415 for (i = 1; i < tablelen; i++) {
416 const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
417 table[tablelen - i] = (float) kaiser;
418 }
419
420 for (i = 1; i < tablelen; i++) {
421 const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
422 table[i] *= SDL_sinf(x) / x;
423 diffs[i - 1] = table[i] - table[i - 1];
424 }
425 diffs[lenm1] = 0.0f;
426}
427
428
429static SDL_SpinLock ResampleFilterSpinlock = 0;
430static float *ResamplerFilter = NULL;
431static float *ResamplerFilterDifference = NULL;
432
433int
434SDL_PrepareResampleFilter(void)
435{
436 SDL_AtomicLock(&ResampleFilterSpinlock);
437 if (!ResamplerFilter) {
438 /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
439 const double dB = 80.0;
440 const double beta = 0.1102 * (dB - 8.7);
441 const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
442
443 ResamplerFilter = (float *) SDL_malloc(alloclen);
444 if (!ResamplerFilter) {
445 SDL_AtomicUnlock(&ResampleFilterSpinlock);
446 return SDL_OutOfMemory();
447 }
448
449 ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
450 if (!ResamplerFilterDifference) {
451 SDL_free(ResamplerFilter);
452 ResamplerFilter = NULL;
453 SDL_AtomicUnlock(&ResampleFilterSpinlock);
454 return SDL_OutOfMemory();
455 }
456 kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
457 }
458 SDL_AtomicUnlock(&ResampleFilterSpinlock);
459 return 0;
460}
461
462void
463SDL_FreeResampleFilter(void)
464{
465 SDL_free(ResamplerFilter);
466 SDL_free(ResamplerFilterDifference);
467 ResamplerFilter = NULL;
468 ResamplerFilterDifference = NULL;
469}
470
471static int
472ResamplerPadding(const int inrate, const int outrate)
473{
474 if (inrate == outrate) {
475 return 0;
476 } else if (inrate > outrate) {
477 return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
478 }
479 return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
480}
481
482/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
483static int
484SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
485 const float *lpadding, const float *rpadding,
486 const float *inbuf, const int inbuflen,
487 float *outbuf, const int outbuflen)
488{
489 const double finrate = (double) inrate;
490 const double outtimeincr = 1.0 / ((float) outrate);
491 const double ratio = ((float) outrate) / ((float) inrate);
492 const int paddinglen = ResamplerPadding(inrate, outrate);
493 const int framelen = chans * (int)sizeof (float);
494 const int inframes = inbuflen / framelen;
495 const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
496 const int maxoutframes = outbuflen / framelen;
497 const int outframes = SDL_min(wantedoutframes, maxoutframes);
498 float *dst = outbuf;
499 double outtime = 0.0;
500 int i, j, chan;
501
502 for (i = 0; i < outframes; i++) {
503 const int srcindex = (int) (outtime * inrate);
504 const double intime = ((double) srcindex) / finrate;
505 const double innexttime = ((double) (srcindex + 1)) / finrate;
506 const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
507 const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
508 const double interpolation2 = 1.0 - interpolation1;
509 const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
510
511 for (chan = 0; chan < chans; chan++) {
512 float outsample = 0.0f;
513
514 /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
515 /* !!! FIXME: do both wings in one loop */
516 for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
517 const int srcframe = srcindex - j;
518 /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
519 const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
520 outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
521 }
522
523 for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
524 const int srcframe = srcindex + 1 + j;
525 /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
526 const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
527 outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
528 }
529 *(dst++) = outsample;
530 }
531
532 outtime += outtimeincr;
533 }
534
535 return outframes * chans * sizeof (float);
536}
537
538int
539SDL_ConvertAudio(SDL_AudioCVT * cvt)
540{
541 /* !!! FIXME: (cvt) should be const; stack-copy it here. */
542 /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
543
544 /* Make sure there's data to convert */
545 if (cvt->buf == NULL) {
546 return SDL_SetError("No buffer allocated for conversion");
547 }
548
549 /* Return okay if no conversion is necessary */
550 cvt->len_cvt = cvt->len;
551 if (cvt->filters[0] == NULL) {
552 return 0;
553 }
554
555 /* Set up the conversion and go! */
556 cvt->filter_index = 0;
557 cvt->filters[0] (cvt, cvt->src_format);
558 return 0;
559}
560
561static void SDLCALL
562SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
563{
564#if DEBUG_CONVERT
565 printf("Converting byte order\n");
566#endif
567
568 switch (SDL_AUDIO_BITSIZE(format)) {
569 #define CASESWAP(b) \
570 case b: { \
571 Uint##b *ptr = (Uint##b *) cvt->buf; \
572 int i; \
573 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
574 *ptr = SDL_Swap##b(*ptr); \
575 } \
576 break; \
577 }
578
579 CASESWAP(16);
580 CASESWAP(32);
581 CASESWAP(64);
582
583 #undef CASESWAP
584
585 default: SDL_assert(!"unhandled byteswap datatype!"); break;
586 }
587
588 if (cvt->filters[++cvt->filter_index]) {
589 /* flip endian flag for data. */
590 if (format & SDL_AUDIO_MASK_ENDIAN) {
591 format &= ~SDL_AUDIO_MASK_ENDIAN;
592 } else {
593 format |= SDL_AUDIO_MASK_ENDIAN;
594 }
595 cvt->filters[cvt->filter_index](cvt, format);
596 }
597}
598
599static int
600SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
601{
602 if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
603 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
604 }
605 if (filter == NULL) {
606 return SDL_SetError("Audio filter pointer is NULL");
607 }
608 cvt->filters[cvt->filter_index++] = filter;
609 cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
610 return 0;
611}
612
613static int
614SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
615{
616 int retval = 0; /* 0 == no conversion necessary. */
617
618 if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
619 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
620 return -1;
621 }
622 retval = 1; /* added a converter. */
623 }
624
625 if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
626 const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
627 const Uint16 dst_bitsize = 32;
628 SDL_AudioFilter filter = NULL;
629
630 switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
631 case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
632 case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
633 case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
634 case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
635 case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
636 default: SDL_assert(!"Unexpected audio format!"); break;
637 }
638
639 if (!filter) {
640 return SDL_SetError("No conversion from source format to float available");
641 }
642
643 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
644 return -1;
645 }
646 if (src_bitsize < dst_bitsize) {
647 const int mult = (dst_bitsize / src_bitsize);
648 cvt->len_mult *= mult;
649 cvt->len_ratio *= mult;
650 } else if (src_bitsize > dst_bitsize) {
651 cvt->len_ratio /= (src_bitsize / dst_bitsize);
652 }
653
654 retval = 1; /* added a converter. */
655 }
656
657 return retval;
658}
659
660static int
661SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
662{
663 int retval = 0; /* 0 == no conversion necessary. */
664
665 if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
666 const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
667 const Uint16 src_bitsize = 32;
668 SDL_AudioFilter filter = NULL;
669 switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
670 case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
671 case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
672 case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
673 case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
674 case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
675 default: SDL_assert(!"Unexpected audio format!"); break;
676 }
677
678 if (!filter) {
679 return SDL_SetError("No conversion from float to format 0x%.4x available", dst_fmt);
680 }
681
682 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
683 return -1;
684 }
685 if (src_bitsize < dst_bitsize) {
686 const int mult = (dst_bitsize / src_bitsize);
687 cvt->len_mult *= mult;
688 cvt->len_ratio *= mult;
689 } else if (src_bitsize > dst_bitsize) {
690 cvt->len_ratio /= (src_bitsize / dst_bitsize);
691 }
692 retval = 1; /* added a converter. */
693 }
694
695 if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
696 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
697 return -1;
698 }
699 retval = 1; /* added a converter. */
700 }
701
702 return retval;
703}
704
705static void
706SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
707{
708 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
709 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
710 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
711 const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
712 const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
713 const float *src = (const float *) cvt->buf;
714 const int srclen = cvt->len_cvt;
715 /*float *dst = (float *) cvt->buf;
716 const int dstlen = (cvt->len * cvt->len_mult);*/
717 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
718 float *dst = (float *) (cvt->buf + srclen);
719 const int dstlen = (cvt->len * cvt->len_mult) - srclen;
720 const int requestedpadding = ResamplerPadding(inrate, outrate);
721 int paddingsamples;
722 float *padding;
723
724 if (requestedpadding < SDL_MAX_SINT32 / chans) {
725 paddingsamples = requestedpadding * chans;
726 } else {
727 paddingsamples = 0;
728 }
729 SDL_assert(format == AUDIO_F32SYS);
730
731 /* we keep no streaming state here, so pad with silence on both ends. */
732 padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
733 if (!padding) {
734 SDL_OutOfMemory();
735 return;
736 }
737
738 cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
739
740 SDL_free(padding);
741
742 SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
743
744 if (cvt->filters[++cvt->filter_index]) {
745 cvt->filters[cvt->filter_index](cvt, format);
746 }
747}
748
749/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
750 !!! FIXME: store channel info, so we have to have function entry
751 !!! FIXME: points for each supported channel count and multiple
752 !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */
753#define RESAMPLER_FUNCS(chans) \
754 static void SDLCALL \
755 SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
756 SDL_ResampleCVT(cvt, chans, format); \
757 }
758RESAMPLER_FUNCS(1)
759RESAMPLER_FUNCS(2)
760RESAMPLER_FUNCS(4)
761RESAMPLER_FUNCS(6)
762RESAMPLER_FUNCS(8)
763#undef RESAMPLER_FUNCS
764
765static SDL_AudioFilter
766ChooseCVTResampler(const int dst_channels)
767{
768 switch (dst_channels) {
769 case 1: return SDL_ResampleCVT_c1;
770 case 2: return SDL_ResampleCVT_c2;
771 case 4: return SDL_ResampleCVT_c4;
772 case 6: return SDL_ResampleCVT_c6;
773 case 8: return SDL_ResampleCVT_c8;
774 default: break;
775 }
776
777 return NULL;
778}
779
780static int
781SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
782 const int src_rate, const int dst_rate)
783{
784 SDL_AudioFilter filter;
785
786 if (src_rate == dst_rate) {
787 return 0; /* no conversion necessary. */
788 }
789
790 filter = ChooseCVTResampler(dst_channels);
791 if (filter == NULL) {
792 return SDL_SetError("No conversion available for these rates");
793 }
794
795 if (SDL_PrepareResampleFilter() < 0) {
796 return -1;
797 }
798
799 /* Update (cvt) with filter details... */
800 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
801 return -1;
802 }
803
804 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
805 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
806 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
807 if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
808 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
809 }
810 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
811 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
812
813 if (src_rate < dst_rate) {
814 const double mult = ((double) dst_rate) / ((double) src_rate);
815 cvt->len_mult *= (int) SDL_ceil(mult);
816 cvt->len_ratio *= mult;
817 } else {
818 cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
819 }
820
821 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
822 /* the buffer is big enough to hold the destination now, but
823 we need it large enough to hold a separate scratch buffer. */
824 cvt->len_mult *= 2;
825
826 return 1; /* added a converter. */
827}
828
829static SDL_bool
830SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
831{
832 switch (fmt) {
833 case AUDIO_U8:
834 case AUDIO_S8:
835 case AUDIO_U16LSB:
836 case AUDIO_S16LSB:
837 case AUDIO_U16MSB:
838 case AUDIO_S16MSB:
839 case AUDIO_S32LSB:
840 case AUDIO_S32MSB:
841 case AUDIO_F32LSB:
842 case AUDIO_F32MSB:
843 return SDL_TRUE; /* supported. */
844
845 default:
846 break;
847 }
848
849 return SDL_FALSE; /* unsupported. */
850}
851
852static SDL_bool
853SDL_SupportedChannelCount(const int channels)
854{
855 switch (channels) {
856 case 1: /* mono */
857 case 2: /* stereo */
858 case 4: /* quad */
859 case 6: /* 5.1 */
860 case 8: /* 7.1 */
861 return SDL_TRUE; /* supported. */
862
863 default:
864 break;
865 }
866
867 return SDL_FALSE; /* unsupported. */
868}
869
870
871/* Creates a set of audio filters to convert from one format to another.
872 Returns 0 if no conversion is needed, 1 if the audio filter is set up,
873 or -1 if an error like invalid parameter, unsupported format, etc. occurred.
874*/
875
876int
877SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
878 SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
879 SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
880{
881 /* Sanity check target pointer */
882 if (cvt == NULL) {
883 return SDL_InvalidParamError("cvt");
884 }
885
886 /* Make sure we zero out the audio conversion before error checking */
887 SDL_zerop(cvt);
888
889 if (!SDL_SupportedAudioFormat(src_fmt)) {
890 return SDL_SetError("Invalid source format");
891 } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
892 return SDL_SetError("Invalid destination format");
893 } else if (!SDL_SupportedChannelCount(src_channels)) {
894 return SDL_SetError("Invalid source channels");
895 } else if (!SDL_SupportedChannelCount(dst_channels)) {
896 return SDL_SetError("Invalid destination channels");
897 } else if (src_rate <= 0) {
898 return SDL_SetError("Source rate is equal to or less than zero");
899 } else if (dst_rate <= 0) {
900 return SDL_SetError("Destination rate is equal to or less than zero");
901 } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
902 return SDL_SetError("Source rate is too high");
903 } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
904 return SDL_SetError("Destination rate is too high");
905 }
906
907#if DEBUG_CONVERT
908 printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
909 src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
910#endif
911
912 /* Start off with no conversion necessary */
913 cvt->src_format = src_fmt;
914 cvt->dst_format = dst_fmt;
915 cvt->needed = 0;
916 cvt->filter_index = 0;
917 SDL_zeroa(cvt->filters);
918 cvt->len_mult = 1;
919 cvt->len_ratio = 1.0;
920 cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
921
922 /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
923 SDL_ChooseAudioConverters();
924
925 /* Type conversion goes like this now:
926 - byteswap to CPU native format first if necessary.
927 - convert to native Float32 if necessary.
928 - resample and change channel count if necessary.
929 - convert back to native format.
930 - byteswap back to foreign format if necessary.
931
932 The expectation is we can process data faster in float32
933 (possibly with SIMD), and making several passes over the same
934 buffer is likely to be CPU cache-friendly, avoiding the
935 biggest performance hit in modern times. Previously we had
936 (script-generated) custom converters for every data type and
937 it was a bloat on SDL compile times and final library size. */
938
939 /* see if we can skip float conversion entirely. */
940 if (src_rate == dst_rate && src_channels == dst_channels) {
941 if (src_fmt == dst_fmt) {
942 return 0;
943 }
944
945 /* just a byteswap needed? */
946 if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
947 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
948 return -1;
949 }
950 cvt->needed = 1;
951 return 1;
952 }
953 }
954
955 /* Convert data types, if necessary. Updates (cvt). */
956 if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
957 return -1; /* shouldn't happen, but just in case... */
958 }
959
960 /* Channel conversion */
961 if (src_channels < dst_channels) {
962 /* Upmixing */
963 /* Mono -> Stereo [-> ...] */
964 if ((src_channels == 1) && (dst_channels > 1)) {
965 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
966 return -1;
967 }
968 cvt->len_mult *= 2;
969 src_channels = 2;
970 cvt->len_ratio *= 2;
971 }
972 /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
973 if ((src_channels == 2) && (dst_channels >= 6)) {
974 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
975 return -1;
976 }
977 src_channels = 6;
978 cvt->len_mult *= 3;
979 cvt->len_ratio *= 3;
980 }
981 /* Quad -> 5.1 [-> 7.1] */
982 if ((src_channels == 4) && (dst_channels >= 6)) {
983 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
984 return -1;
985 }
986 src_channels = 6;
987 cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
988 cvt->len_ratio *= 1.5;
989 }
990 /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
991 if ((src_channels == 6) && (dst_channels == 8)) {
992 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
993 return -1;
994 }
995 src_channels = 8;
996 cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
997 /* Should be numerically exact with every valid input to this
998 function */
999 cvt->len_ratio = cvt->len_ratio * 4 / 3;
1000 }
1001 /* [Mono ->] Stereo -> Quad */
1002 if ((src_channels == 2) && (dst_channels == 4)) {
1003 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
1004 return -1;
1005 }
1006 src_channels = 4;
1007 cvt->len_mult *= 2;
1008 cvt->len_ratio *= 2;
1009 }
1010 } else if (src_channels > dst_channels) {
1011 /* Downmixing */
1012 /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
1013 /* 7.1 -> 5.1 [-> Quad] */
1014 if ((src_channels == 8) && (dst_channels <= 6)) {
1015 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
1016 return -1;
1017 }
1018 src_channels = 6;
1019 cvt->len_ratio *= 0.75;
1020 }
1021 /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
1022 if ((src_channels == 6) && (dst_channels <= 2)) {
1023 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
1024 return -1;
1025 }
1026 src_channels = 2;
1027 cvt->len_ratio /= 3;
1028 }
1029 /* 5.1 -> Quad */
1030 if ((src_channels == 6) && (dst_channels == 4)) {
1031 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
1032 return -1;
1033 }
1034 src_channels = 4;
1035 cvt->len_ratio = cvt->len_ratio * 2 / 3;
1036 }
1037 /* Quad -> Stereo [-> Mono] */
1038 if ((src_channels == 4) && (dst_channels <= 2)) {
1039 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
1040 return -1;
1041 }
1042 src_channels = 2;
1043 cvt->len_ratio /= 2;
1044 }
1045 /* [... ->] Stereo -> Mono */
1046 if ((src_channels == 2) && (dst_channels == 1)) {
1047 SDL_AudioFilter filter = NULL;
1048
1049 #if HAVE_SSE3_INTRINSICS
1050 if (SDL_HasSSE3()) {
1051 filter = SDL_ConvertStereoToMono_SSE3;
1052 }
1053 #endif
1054
1055 if (!filter) {
1056 filter = SDL_ConvertStereoToMono;
1057 }
1058
1059 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
1060 return -1;
1061 }
1062
1063 src_channels = 1;
1064 cvt->len_ratio /= 2;
1065 }
1066 }
1067
1068 if (src_channels != dst_channels) {
1069 /* All combinations of supported channel counts should have been
1070 handled by now, but let's be defensive */
1071 return SDL_SetError("Invalid channel combination");
1072 }
1073
1074 /* Do rate conversion, if necessary. Updates (cvt). */
1075 if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
1076 return -1; /* shouldn't happen, but just in case... */
1077 }
1078
1079 /* Move to final data type. */
1080 if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
1081 return -1; /* shouldn't happen, but just in case... */
1082 }
1083
1084 cvt->needed = (cvt->filter_index != 0);
1085 return (cvt->needed);
1086}
1087
1088typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
1089typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
1090typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
1091
1092struct _SDL_AudioStream
1093{
1094 SDL_AudioCVT cvt_before_resampling;
1095 SDL_AudioCVT cvt_after_resampling;
1096 SDL_DataQueue *queue;
1097 SDL_bool first_run;
1098 Uint8 *staging_buffer;
1099 int staging_buffer_size;
1100 int staging_buffer_filled;
1101 Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
1102 int work_buffer_len;
1103 int src_sample_frame_size;
1104 SDL_AudioFormat src_format;
1105 Uint8 src_channels;
1106 int src_rate;
1107 int dst_sample_frame_size;
1108 SDL_AudioFormat dst_format;
1109 Uint8 dst_channels;
1110 int dst_rate;
1111 double rate_incr;
1112 Uint8 pre_resample_channels;
1113 int packetlen;
1114 int resampler_padding_samples;
1115 float *resampler_padding;
1116 void *resampler_state;
1117 SDL_ResampleAudioStreamFunc resampler_func;
1118 SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
1119 SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
1120};
1121
1122static Uint8 *
1123EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
1124{
1125 Uint8 *ptr;
1126 size_t offset;
1127
1128 if (stream->work_buffer_len >= newlen) {
1129 ptr = stream->work_buffer_base;
1130 } else {
1131 ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
1132 if (!ptr) {
1133 SDL_OutOfMemory();
1134 return NULL;
1135 }
1136 /* Make sure we're aligned to 16 bytes for SIMD code. */
1137 stream->work_buffer_base = ptr;
1138 stream->work_buffer_len = newlen;
1139 }
1140
1141 offset = ((size_t) ptr) & 15;
1142 return offset ? ptr + (16 - offset) : ptr;
1143}
1144
1145#ifdef HAVE_LIBSAMPLERATE_H
1146static int
1147SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1148{
1149 const float *inbuf = (const float *) _inbuf;
1150 float *outbuf = (float *) _outbuf;
1151 const int framelen = sizeof(float) * stream->pre_resample_channels;
1152 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1153 SRC_DATA data;
1154 int result;
1155
1156 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1157
1158 data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
1159 data.input_frames = inbuflen / framelen;
1160 data.input_frames_used = 0;
1161
1162 data.data_out = outbuf;
1163 data.output_frames = outbuflen / framelen;
1164
1165 data.end_of_input = 0;
1166 data.src_ratio = stream->rate_incr;
1167
1168 result = SRC_src_process(state, &data);
1169 if (result != 0) {
1170 SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
1171 return 0;
1172 }
1173
1174 /* If this fails, we need to store them off somewhere */
1175 SDL_assert(data.input_frames_used == data.input_frames);
1176
1177 return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
1178}
1179
1180static void
1181SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
1182{
1183 SRC_src_reset((SRC_STATE *)stream->resampler_state);
1184}
1185
1186static void
1187SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
1188{
1189 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1190 if (state) {
1191 SRC_src_delete(state);
1192 }
1193
1194 stream->resampler_state = NULL;
1195 stream->resampler_func = NULL;
1196 stream->reset_resampler_func = NULL;
1197 stream->cleanup_resampler_func = NULL;
1198}
1199
1200static SDL_bool
1201SetupLibSampleRateResampling(SDL_AudioStream *stream)
1202{
1203 int result = 0;
1204 SRC_STATE *state = NULL;
1205
1206 if (SRC_available) {
1207 state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
1208 if (!state) {
1209 SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
1210 }
1211 }
1212
1213 if (!state) {
1214 SDL_CleanupAudioStreamResampler_SRC(stream);
1215 return SDL_FALSE;
1216 }
1217
1218 stream->resampler_state = state;
1219 stream->resampler_func = SDL_ResampleAudioStream_SRC;
1220 stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
1221 stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
1222
1223 return SDL_TRUE;
1224}
1225#endif /* HAVE_LIBSAMPLERATE_H */
1226
1227
1228static int
1229SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1230{
1231 const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
1232 const float *inbuf = (const float *) _inbuf;
1233 float *outbuf = (float *) _outbuf;
1234 const int chans = (int) stream->pre_resample_channels;
1235 const int inrate = stream->src_rate;
1236 const int outrate = stream->dst_rate;
1237 const int paddingsamples = stream->resampler_padding_samples;
1238 const int paddingbytes = paddingsamples * sizeof (float);
1239 float *lpadding = (float *) stream->resampler_state;
1240 const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
1241 const int cpy = SDL_min(inbuflen, paddingbytes);
1242 int retval;
1243
1244 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1245
1246 retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
1247
1248 /* update our left padding with end of current input, for next run. */
1249 SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
1250 return retval;
1251}
1252
1253static void
1254SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
1255{
1256 /* set all the padding to silence. */
1257 const int len = stream->resampler_padding_samples;
1258 SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
1259}
1260
1261static void
1262SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
1263{
1264 SDL_free(stream->resampler_state);
1265}
1266
1267SDL_AudioStream *
1268SDL_NewAudioStream(const SDL_AudioFormat src_format,
1269 const Uint8 src_channels,
1270 const int src_rate,
1271 const SDL_AudioFormat dst_format,
1272 const Uint8 dst_channels,
1273 const int dst_rate)
1274{
1275 const int packetlen = 4096; /* !!! FIXME: good enough for now. */
1276 Uint8 pre_resample_channels;
1277 SDL_AudioStream *retval;
1278
1279 retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
1280 if (!retval) {
1281 return NULL;
1282 }
1283
1284 /* If increasing channels, do it after resampling, since we'd just
1285 do more work to resample duplicate channels. If we're decreasing, do
1286 it first so we resample the interpolated data instead of interpolating
1287 the resampled data (!!! FIXME: decide if that works in practice, though!). */
1288 pre_resample_channels = SDL_min(src_channels, dst_channels);
1289
1290 retval->first_run = SDL_TRUE;
1291 retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
1292 retval->src_format = src_format;
1293 retval->src_channels = src_channels;
1294 retval->src_rate = src_rate;
1295 retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
1296 retval->dst_format = dst_format;
1297 retval->dst_channels = dst_channels;
1298 retval->dst_rate = dst_rate;
1299 retval->pre_resample_channels = pre_resample_channels;
1300 retval->packetlen = packetlen;
1301 retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
1302 retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
1303 retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float));
1304
1305 if (retval->resampler_padding == NULL) {
1306 SDL_FreeAudioStream(retval);
1307 SDL_OutOfMemory();
1308 return NULL;
1309 }
1310
1311 retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
1312 if (retval->staging_buffer_size > 0) {
1313 retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
1314 if (retval->staging_buffer == NULL) {
1315 SDL_FreeAudioStream(retval);
1316 SDL_OutOfMemory();
1317 return NULL;
1318 }
1319 }
1320
1321 /* Not resampling? It's an easy conversion (and maybe not even that!) */
1322 if (src_rate == dst_rate) {
1323 retval->cvt_before_resampling.needed = SDL_FALSE;
1324 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1325 SDL_FreeAudioStream(retval);
1326 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1327 }
1328 } else {
1329 /* Don't resample at first. Just get us to Float32 format. */
1330 /* !!! FIXME: convert to int32 on devices without hardware float. */
1331 if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
1332 SDL_FreeAudioStream(retval);
1333 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1334 }
1335
1336#ifdef HAVE_LIBSAMPLERATE_H
1337 SetupLibSampleRateResampling(retval);
1338#endif
1339
1340 if (!retval->resampler_func) {
1341 retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
1342 if (!retval->resampler_state) {
1343 SDL_FreeAudioStream(retval);
1344 SDL_OutOfMemory();
1345 return NULL;
1346 }
1347
1348 if (SDL_PrepareResampleFilter() < 0) {
1349 SDL_free(retval->resampler_state);
1350 retval->resampler_state = NULL;
1351 SDL_FreeAudioStream(retval);
1352 return NULL;
1353 }
1354
1355 retval->resampler_func = SDL_ResampleAudioStream;
1356 retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1357 retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
1358 }
1359
1360 /* Convert us to the final format after resampling. */
1361 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1362 SDL_FreeAudioStream(retval);
1363 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1364 }
1365 }
1366
1367 retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
1368 if (!retval->queue) {
1369 SDL_FreeAudioStream(retval);
1370 return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */
1371 }
1372
1373 return retval;
1374}
1375
1376static int
1377SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
1378{
1379 int buflen = len;
1380 int workbuflen;
1381 Uint8 *workbuf;
1382 Uint8 *resamplebuf = NULL;
1383 int resamplebuflen = 0;
1384 int neededpaddingbytes;
1385 int paddingbytes;
1386
1387 /* !!! FIXME: several converters can take advantage of SIMD, but only
1388 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1389 !!! FIXME: guarantees the buffer will align, but the
1390 !!! FIXME: converters will iterate over the data backwards if
1391 !!! FIXME: the output grows, and this means we won't align if buflen
1392 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1393 !!! FIXME: a few samples at the end and convert them separately. */
1394
1395 /* no padding prepended on first run. */
1396 neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
1397 paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
1398 stream->first_run = SDL_FALSE;
1399
1400 /* Make sure the work buffer can hold all the data we need at once... */
1401 workbuflen = buflen;
1402 if (stream->cvt_before_resampling.needed) {
1403 workbuflen *= stream->cvt_before_resampling.len_mult;
1404 }
1405
1406 if (stream->dst_rate != stream->src_rate) {
1407 /* resamples can't happen in place, so make space for second buf. */
1408 const int framesize = stream->pre_resample_channels * sizeof (float);
1409 const int frames = workbuflen / framesize;
1410 resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
1411 #if DEBUG_AUDIOSTREAM
1412 printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
1413 #endif
1414 workbuflen += resamplebuflen;
1415 }
1416
1417 if (stream->cvt_after_resampling.needed) {
1418 /* !!! FIXME: buffer might be big enough already? */
1419 workbuflen *= stream->cvt_after_resampling.len_mult;
1420 }
1421
1422 workbuflen += neededpaddingbytes;
1423
1424 #if DEBUG_AUDIOSTREAM
1425 printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
1426 #endif
1427
1428 workbuf = EnsureStreamBufferSize(stream, workbuflen);
1429 if (!workbuf) {
1430 return -1; /* probably out of memory. */
1431 }
1432
1433 resamplebuf = workbuf; /* default if not resampling. */
1434
1435 SDL_memcpy(workbuf + paddingbytes, buf, buflen);
1436
1437 if (stream->cvt_before_resampling.needed) {
1438 stream->cvt_before_resampling.buf = workbuf + paddingbytes;
1439 stream->cvt_before_resampling.len = buflen;
1440 if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
1441 return -1; /* uhoh! */
1442 }
1443 buflen = stream->cvt_before_resampling.len_cvt;
1444
1445 #if DEBUG_AUDIOSTREAM
1446 printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
1447 #endif
1448 }
1449
1450 if (stream->dst_rate != stream->src_rate) {
1451 /* save off some samples at the end; they are used for padding now so
1452 the resampler is coherent and then used at the start of the next
1453 put operation. Prepend last put operation's padding, too. */
1454
1455 /* prepend prior put's padding. :P */
1456 if (paddingbytes) {
1457 SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
1458 buflen += paddingbytes;
1459 }
1460
1461 /* save off the data at the end for the next run. */
1462 SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
1463
1464 resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
1465 SDL_assert(buflen >= neededpaddingbytes);
1466 if (buflen > neededpaddingbytes) {
1467 buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
1468 } else {
1469 buflen = 0;
1470 }
1471
1472 #if DEBUG_AUDIOSTREAM
1473 printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
1474 #endif
1475 }
1476
1477 if (stream->cvt_after_resampling.needed && (buflen > 0)) {
1478 stream->cvt_after_resampling.buf = resamplebuf;
1479 stream->cvt_after_resampling.len = buflen;
1480 if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
1481 return -1; /* uhoh! */
1482 }
1483 buflen = stream->cvt_after_resampling.len_cvt;
1484
1485 #if DEBUG_AUDIOSTREAM
1486 printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
1487 #endif
1488 }
1489
1490 #if DEBUG_AUDIOSTREAM
1491 printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
1492 #endif
1493
1494 if (maxputbytes) {
1495 const int maxbytes = *maxputbytes;
1496 if (buflen > maxbytes)
1497 buflen = maxbytes;
1498 *maxputbytes -= buflen;
1499 }
1500
1501 /* resamplebuf holds the final output, even if we didn't resample. */
1502 return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
1503}
1504
1505int
1506SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
1507{
1508 /* !!! FIXME: several converters can take advantage of SIMD, but only
1509 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1510 !!! FIXME: guarantees the buffer will align, but the
1511 !!! FIXME: converters will iterate over the data backwards if
1512 !!! FIXME: the output grows, and this means we won't align if buflen
1513 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1514 !!! FIXME: a few samples at the end and convert them separately. */
1515
1516 #if DEBUG_AUDIOSTREAM
1517 printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
1518 #endif
1519
1520 if (!stream) {
1521 return SDL_InvalidParamError("stream");
1522 } else if (!buf) {
1523 return SDL_InvalidParamError("buf");
1524 } else if (len == 0) {
1525 return 0; /* nothing to do. */
1526 } else if ((len % stream->src_sample_frame_size) != 0) {
1527 return SDL_SetError("Can't add partial sample frames");
1528 }
1529
1530 if (!stream->cvt_before_resampling.needed &&
1531 (stream->dst_rate == stream->src_rate) &&
1532 !stream->cvt_after_resampling.needed) {
1533 #if DEBUG_AUDIOSTREAM
1534 printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
1535 #endif
1536 return SDL_WriteToDataQueue(stream->queue, buf, len);
1537 }
1538
1539 while (len > 0) {
1540 int amount;
1541
1542 /* If we don't have a staging buffer or we're given enough data that
1543 we don't need to store it for later, skip the staging process.
1544 */
1545 if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
1546 return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
1547 }
1548
1549 /* If there's not enough data to fill the staging buffer, just save it */
1550 if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
1551 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
1552 stream->staging_buffer_filled += len;
1553 return 0;
1554 }
1555
1556 /* Fill the staging buffer, process it, and continue */
1557 amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
1558 SDL_assert(amount > 0);
1559 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
1560 stream->staging_buffer_filled = 0;
1561 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
1562 return -1;
1563 }
1564 buf = (void *)((Uint8 *)buf + amount);
1565 len -= amount;
1566 }
1567 return 0;
1568}
1569
1570int SDL_AudioStreamFlush(SDL_AudioStream *stream)
1571{
1572 if (!stream) {
1573 return SDL_InvalidParamError("stream");
1574 }
1575
1576 #if DEBUG_AUDIOSTREAM
1577 printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
1578 #endif
1579
1580 /* shouldn't use a staging buffer if we're not resampling. */
1581 SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
1582
1583 if (stream->staging_buffer_filled > 0) {
1584 /* push the staging buffer + silence. We need to flush out not just
1585 the staging buffer, but the piece that the stream was saving off
1586 for right-side resampler padding. */
1587 const SDL_bool first_run = stream->first_run;
1588 const int filled = stream->staging_buffer_filled;
1589 int actual_input_frames = filled / stream->src_sample_frame_size;
1590 if (!first_run)
1591 actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
1592
1593 if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
1594 /* This is how many bytes we're expecting without silence appended. */
1595 int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
1596
1597 #if DEBUG_AUDIOSTREAM
1598 printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
1599 #endif
1600
1601 SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
1602 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1603 return -1;
1604 }
1605
1606 /* we have flushed out (or initially filled) the pending right-side
1607 resampler padding, but we need to push more silence to guarantee
1608 the staging buffer is fully flushed out, too. */
1609 SDL_memset(stream->staging_buffer, '\0', filled);
1610 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1611 return -1;
1612 }
1613 }
1614 }
1615
1616 stream->staging_buffer_filled = 0;
1617 stream->first_run = SDL_TRUE;
1618
1619 return 0;
1620}
1621
1622/* get converted/resampled data from the stream */
1623int
1624SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
1625{
1626 #if DEBUG_AUDIOSTREAM
1627 printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
1628 #endif
1629
1630 if (!stream) {
1631 return SDL_InvalidParamError("stream");
1632 } else if (!buf) {
1633 return SDL_InvalidParamError("buf");
1634 } else if (len <= 0) {
1635 return 0; /* nothing to do. */
1636 } else if ((len % stream->dst_sample_frame_size) != 0) {
1637 return SDL_SetError("Can't request partial sample frames");
1638 }
1639
1640 return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
1641}
1642
1643/* number of converted/resampled bytes available */
1644int
1645SDL_AudioStreamAvailable(SDL_AudioStream *stream)
1646{
1647 return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
1648}
1649
1650void
1651SDL_AudioStreamClear(SDL_AudioStream *stream)
1652{
1653 if (!stream) {
1654 SDL_InvalidParamError("stream");
1655 } else {
1656 SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
1657 if (stream->reset_resampler_func) {
1658 stream->reset_resampler_func(stream);
1659 }
1660 stream->first_run = SDL_TRUE;
1661 stream->staging_buffer_filled = 0;
1662 }
1663}
1664
1665/* dispose of a stream */
1666void
1667SDL_FreeAudioStream(SDL_AudioStream *stream)
1668{
1669 if (stream) {
1670 if (stream->cleanup_resampler_func) {
1671 stream->cleanup_resampler_func(stream);
1672 }
1673 SDL_FreeDataQueue(stream->queue);
1674 SDL_free(stream->staging_buffer);
1675 SDL_free(stream->work_buffer_base);
1676 SDL_free(stream->resampler_padding);
1677 SDL_free(stream);
1678 }
1679}
1680
1681/* vi: set ts=4 sw=4 expandtab: */
1682
1683