2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* Functions for audio drivers to perform runtime conversion of audio format */
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
29 #include "SDL_audio.h"
30 #include "SDL_audio_c.h"
32 #include "SDL_loadso.h"
33 #include "SDL_assert.h"
34 #include "../SDL_dataqueue.h"
35 #include "SDL_cpuinfo.h"
37 #define DEBUG_AUDIOSTREAM 0
40 #define HAVE_SSE3_INTRINSICS 1
43 #if HAVE_SSE3_INTRINSICS
44 /* Convert from stereo to mono. Average left and right. */
46 SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
48 float *dst = (float *) cvt->buf;
49 const float *src = dst;
50 int i = cvt->len_cvt / 8;
52 LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
53 SDL_assert(format == AUDIO_F32SYS);
55 /* We can only do this if dst is aligned to 16 bytes; since src is the
56 same pointer and it moves by 2, it can't be forcibly aligned. */
57 if ((((size_t) dst) & 15) == 0) {
58 /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
59 const __m128 divby2 = _mm_set1_ps(0.5f);
60 while (i >= 4) { /* 4 * float32 */
61 _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
62 i -= 4; src += 8; dst += 4;
66 /* Finish off any leftovers with scalar operations. */
68 *dst = (src[0] + src[1]) * 0.5f;
73 if (cvt->filters[++cvt->filter_index]) {
74 cvt->filters[cvt->filter_index] (cvt, format);
79 /* Convert from stereo to mono. Average left and right. */
81 SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
83 float *dst = (float *) cvt->buf;
84 const float *src = dst;
87 LOG_DEBUG_CONVERT("stereo", "mono");
88 SDL_assert(format == AUDIO_F32SYS);
90 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
91 *(dst++) = (src[0] + src[1]) * 0.5f;
95 if (cvt->filters[++cvt->filter_index]) {
96 cvt->filters[cvt->filter_index] (cvt, format);
101 /* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
103 SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
105 float *dst = (float *) cvt->buf;
106 const float *src = dst;
109 LOG_DEBUG_CONVERT("5.1", "stereo");
110 SDL_assert(format == AUDIO_F32SYS);
112 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
113 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
114 const float front_center_distributed = src[2] * 0.5f;
115 dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
116 dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
120 if (cvt->filters[++cvt->filter_index]) {
121 cvt->filters[cvt->filter_index] (cvt, format);
126 /* Convert from quad to stereo. Average left and right. */
128 SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
130 float *dst = (float *) cvt->buf;
131 const float *src = dst;
134 LOG_DEBUG_CONVERT("quad", "stereo");
135 SDL_assert(format == AUDIO_F32SYS);
137 for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
138 dst[0] = (src[0] + src[2]) * 0.5f; /* left */
139 dst[1] = (src[1] + src[3]) * 0.5f; /* right */
143 if (cvt->filters[++cvt->filter_index]) {
144 cvt->filters[cvt->filter_index] (cvt, format);
149 /* Convert from 7.1 to 5.1. Distribute sides across front and back. */
151 SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
153 float *dst = (float *) cvt->buf;
154 const float *src = dst;
157 LOG_DEBUG_CONVERT("7.1", "5.1");
158 SDL_assert(format == AUDIO_F32SYS);
160 for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
161 const float surround_left_distributed = src[6] * 0.5f;
162 const float surround_right_distributed = src[7] * 0.5f;
163 dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
164 dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
165 dst[2] = src[2] / 1.5f; /* CC */
166 dst[3] = src[3] / 1.5f; /* LFE */
167 dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
168 dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
173 if (cvt->filters[++cvt->filter_index]) {
174 cvt->filters[cvt->filter_index] (cvt, format);
179 /* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
181 SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
183 float *dst = (float *) cvt->buf;
184 const float *src = dst;
187 LOG_DEBUG_CONVERT("5.1", "quad");
188 SDL_assert(format == AUDIO_F32SYS);
190 /* SDL's 4.0 layout: FL+FR+BL+BR */
191 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
192 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
193 const float front_center_distributed = src[2] * 0.5f;
194 dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
195 dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
196 dst[2] = src[4] / 1.5f; /* BL */
197 dst[3] = src[5] / 1.5f; /* BR */
202 if (cvt->filters[++cvt->filter_index]) {
203 cvt->filters[cvt->filter_index] (cvt, format);
208 /* Upmix mono to stereo (by duplication) */
210 SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
212 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
213 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
216 LOG_DEBUG_CONVERT("mono", "stereo");
217 SDL_assert(format == AUDIO_F32SYS);
219 for (i = cvt->len_cvt / sizeof (float); i; --i) {
222 dst[0] = dst[1] = *src;
226 if (cvt->filters[++cvt->filter_index]) {
227 cvt->filters[cvt->filter_index] (cvt, format);
232 /* Upmix stereo to a pseudo-5.1 stream */
234 SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
238 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
239 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
241 LOG_DEBUG_CONVERT("stereo", "5.1");
242 SDL_assert(format == AUDIO_F32SYS);
244 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
249 ce = (lf + rf) * 0.5f;
250 /* !!! FIXME: FL and FR may clip */
251 dst[0] = lf + (lf - ce); /* FL */
252 dst[1] = rf + (rf - ce); /* FR */
253 dst[2] = ce; /* FC */
254 dst[3] = 0; /* LFE (only meant for special LFE effects) */
255 dst[4] = lf; /* BL */
256 dst[5] = rf; /* BR */
260 if (cvt->filters[++cvt->filter_index]) {
261 cvt->filters[cvt->filter_index] (cvt, format);
266 /* Upmix quad to a pseudo-5.1 stream */
268 SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
271 float lf, rf, lb, rb, ce;
272 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
273 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
275 LOG_DEBUG_CONVERT("quad", "5.1");
276 SDL_assert(format == AUDIO_F32SYS);
277 SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
279 for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
286 ce = (lf + rf) * 0.5f;
287 /* !!! FIXME: FL and FR may clip */
288 dst[0] = lf + (lf - ce); /* FL */
289 dst[1] = rf + (rf - ce); /* FR */
290 dst[2] = ce; /* FC */
291 dst[3] = 0; /* LFE (only meant for special LFE effects) */
292 dst[4] = lb; /* BL */
293 dst[5] = rb; /* BR */
296 cvt->len_cvt = cvt->len_cvt * 3 / 2;
297 if (cvt->filters[++cvt->filter_index]) {
298 cvt->filters[cvt->filter_index] (cvt, format);
303 /* Upmix stereo to a pseudo-4.0 stream (by duplication) */
305 SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
307 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
308 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
312 LOG_DEBUG_CONVERT("stereo", "quad");
313 SDL_assert(format == AUDIO_F32SYS);
315 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
320 dst[0] = lf; /* FL */
321 dst[1] = rf; /* FR */
322 dst[2] = lf; /* BL */
323 dst[3] = rf; /* BR */
327 if (cvt->filters[++cvt->filter_index]) {
328 cvt->filters[cvt->filter_index] (cvt, format);
333 /* Upmix 5.1 to 7.1 */
335 SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
337 float lf, rf, lb, rb, ls, rs;
339 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
340 float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
342 LOG_DEBUG_CONVERT("5.1", "7.1");
343 SDL_assert(format == AUDIO_F32SYS);
344 SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
346 for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
353 ls = (lf + lb) * 0.5f;
354 rs = (rf + rb) * 0.5f;
355 /* !!! FIXME: these four may clip */
360 dst[3] = src[3]; /* LFE */
361 dst[2] = src[2]; /* FC */
362 dst[7] = rs; /* SR */
363 dst[6] = ls; /* SL */
364 dst[5] = rb; /* BR */
365 dst[4] = lb; /* BL */
366 dst[1] = rf; /* FR */
367 dst[0] = lf; /* FL */
370 cvt->len_cvt = cvt->len_cvt * 4 / 3;
372 if (cvt->filters[++cvt->filter_index]) {
373 cvt->filters[cvt->filter_index] (cvt, format);
377 /* SDL's resampler uses a "bandlimited interpolation" algorithm:
378 https://ccrma.stanford.edu/~jos/resample/ */
380 #define RESAMPLER_ZERO_CROSSINGS 5
381 #define RESAMPLER_BITS_PER_SAMPLE 16
382 #define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
383 #define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
385 /* This is a "modified" bessel function, so you can't use POSIX j0() */
387 bessel(const double x)
389 const double xdiv2 = x / 2.0;
395 const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
396 if (diff < 1.0e-21f) {
407 /* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
409 kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
411 const int lenm1 = tablelen - 1;
412 const int lenm1div2 = lenm1 / 2;
416 for (i = 1; i < tablelen; i++) {
417 const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
418 table[tablelen - i] = (float) kaiser;
421 for (i = 1; i < tablelen; i++) {
422 const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
423 table[i] *= SDL_sinf(x) / x;
424 diffs[i - 1] = table[i] - table[i - 1];
430 static SDL_SpinLock ResampleFilterSpinlock = 0;
431 static float *ResamplerFilter = NULL;
432 static float *ResamplerFilterDifference = NULL;
435 SDL_PrepareResampleFilter(void)
437 SDL_AtomicLock(&ResampleFilterSpinlock);
438 if (!ResamplerFilter) {
439 /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
440 const double dB = 80.0;
441 const double beta = 0.1102 * (dB - 8.7);
442 const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
444 ResamplerFilter = (float *) SDL_malloc(alloclen);
445 if (!ResamplerFilter) {
446 SDL_AtomicUnlock(&ResampleFilterSpinlock);
447 return SDL_OutOfMemory();
450 ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
451 if (!ResamplerFilterDifference) {
452 SDL_free(ResamplerFilter);
453 ResamplerFilter = NULL;
454 SDL_AtomicUnlock(&ResampleFilterSpinlock);
455 return SDL_OutOfMemory();
457 kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
459 SDL_AtomicUnlock(&ResampleFilterSpinlock);
464 SDL_FreeResampleFilter(void)
466 SDL_free(ResamplerFilter);
467 SDL_free(ResamplerFilterDifference);
468 ResamplerFilter = NULL;
469 ResamplerFilterDifference = NULL;
473 ResamplerPadding(const int inrate, const int outrate)
475 if (inrate == outrate) {
477 } else if (inrate > outrate) {
478 return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
480 return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
483 /* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
485 SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
486 const float *lpadding, const float *rpadding,
487 const float *inbuf, const int inbuflen,
488 float *outbuf, const int outbuflen)
490 const double finrate = (double) inrate;
491 const double outtimeincr = 1.0 / ((float) outrate);
492 const double ratio = ((float) outrate) / ((float) inrate);
493 const int paddinglen = ResamplerPadding(inrate, outrate);
494 const int framelen = chans * (int)sizeof (float);
495 const int inframes = inbuflen / framelen;
496 const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
497 const int maxoutframes = outbuflen / framelen;
498 const int outframes = SDL_min(wantedoutframes, maxoutframes);
500 double outtime = 0.0;
503 for (i = 0; i < outframes; i++) {
504 const int srcindex = (int) (outtime * inrate);
505 const double intime = ((double) srcindex) / finrate;
506 const double innexttime = ((double) (srcindex + 1)) / finrate;
507 const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
508 const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
509 const double interpolation2 = 1.0 - interpolation1;
510 const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
512 for (chan = 0; chan < chans; chan++) {
513 float outsample = 0.0f;
515 /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
516 /* !!! FIXME: do both wings in one loop */
517 for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
518 const int srcframe = srcindex - j;
519 /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
520 const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
521 outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
524 for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
525 const int srcframe = srcindex + 1 + j;
526 /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
527 const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
528 outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
530 *(dst++) = outsample;
533 outtime += outtimeincr;
536 return outframes * chans * sizeof (float);
540 SDL_ConvertAudio(SDL_AudioCVT * cvt)
542 /* !!! FIXME: (cvt) should be const; stack-copy it here. */
543 /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
545 /* Make sure there's data to convert */
546 if (cvt->buf == NULL) {
547 return SDL_SetError("No buffer allocated for conversion");
550 /* Return okay if no conversion is necessary */
551 cvt->len_cvt = cvt->len;
552 if (cvt->filters[0] == NULL) {
556 /* Set up the conversion and go! */
557 cvt->filter_index = 0;
558 cvt->filters[0] (cvt, cvt->src_format);
563 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
566 printf("Converting byte order\n");
569 switch (SDL_AUDIO_BITSIZE(format)) {
570 #define CASESWAP(b) \
572 Uint##b *ptr = (Uint##b *) cvt->buf; \
574 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
575 *ptr = SDL_Swap##b(*ptr); \
586 default: SDL_assert(!"unhandled byteswap datatype!"); break;
589 if (cvt->filters[++cvt->filter_index]) {
590 /* flip endian flag for data. */
591 if (format & SDL_AUDIO_MASK_ENDIAN) {
592 format &= ~SDL_AUDIO_MASK_ENDIAN;
594 format |= SDL_AUDIO_MASK_ENDIAN;
596 cvt->filters[cvt->filter_index](cvt, format);
601 SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
603 if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
604 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
606 if (filter == NULL) {
607 return SDL_SetError("Audio filter pointer is NULL");
609 cvt->filters[cvt->filter_index++] = filter;
610 cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
615 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
617 int retval = 0; /* 0 == no conversion necessary. */
619 if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
620 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
623 retval = 1; /* added a converter. */
626 if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
627 const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
628 const Uint16 dst_bitsize = 32;
629 SDL_AudioFilter filter = NULL;
631 switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
632 case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
633 case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
634 case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
635 case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
636 case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
637 default: SDL_assert(!"Unexpected audio format!"); break;
641 return SDL_SetError("No conversion from source format to float available");
644 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
647 if (src_bitsize < dst_bitsize) {
648 const int mult = (dst_bitsize / src_bitsize);
649 cvt->len_mult *= mult;
650 cvt->len_ratio *= mult;
651 } else if (src_bitsize > dst_bitsize) {
652 cvt->len_ratio /= (src_bitsize / dst_bitsize);
655 retval = 1; /* added a converter. */
662 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
664 int retval = 0; /* 0 == no conversion necessary. */
666 if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
667 const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
668 const Uint16 src_bitsize = 32;
669 SDL_AudioFilter filter = NULL;
670 switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
671 case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
672 case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
673 case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
674 case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
675 case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
676 default: SDL_assert(!"Unexpected audio format!"); break;
680 return SDL_SetError("No conversion from float to destination format available");
683 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
686 if (src_bitsize < dst_bitsize) {
687 const int mult = (dst_bitsize / src_bitsize);
688 cvt->len_mult *= mult;
689 cvt->len_ratio *= mult;
690 } else if (src_bitsize > dst_bitsize) {
691 cvt->len_ratio /= (src_bitsize / dst_bitsize);
693 retval = 1; /* added a converter. */
696 if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
697 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
700 retval = 1; /* added a converter. */
707 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
709 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
710 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
711 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
712 const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
713 const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
714 const float *src = (const float *) cvt->buf;
715 const int srclen = cvt->len_cvt;
716 /*float *dst = (float *) cvt->buf;
717 const int dstlen = (cvt->len * cvt->len_mult);*/
718 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
719 float *dst = (float *) (cvt->buf + srclen);
720 const int dstlen = (cvt->len * cvt->len_mult) - srclen;
721 const int requestedpadding = ResamplerPadding(inrate, outrate);
725 if (requestedpadding < SDL_MAX_SINT32 / chans) {
726 paddingsamples = requestedpadding * chans;
730 SDL_assert(format == AUDIO_F32SYS);
732 /* we keep no streaming state here, so pad with silence on both ends. */
733 padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
739 cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
743 SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
745 if (cvt->filters[++cvt->filter_index]) {
746 cvt->filters[cvt->filter_index](cvt, format);
750 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
751 !!! FIXME: store channel info, so we have to have function entry
752 !!! FIXME: points for each supported channel count and multiple
753 !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */
754 #define RESAMPLER_FUNCS(chans) \
755 static void SDLCALL \
756 SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
757 SDL_ResampleCVT(cvt, chans, format); \
764 #undef RESAMPLER_FUNCS
766 static SDL_AudioFilter
767 ChooseCVTResampler(const int dst_channels)
769 switch (dst_channels) {
770 case 1: return SDL_ResampleCVT_c1;
771 case 2: return SDL_ResampleCVT_c2;
772 case 4: return SDL_ResampleCVT_c4;
773 case 6: return SDL_ResampleCVT_c6;
774 case 8: return SDL_ResampleCVT_c8;
782 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
783 const int src_rate, const int dst_rate)
785 SDL_AudioFilter filter;
787 if (src_rate == dst_rate) {
788 return 0; /* no conversion necessary. */
791 filter = ChooseCVTResampler(dst_channels);
792 if (filter == NULL) {
793 return SDL_SetError("No conversion available for these rates");
796 if (SDL_PrepareResampleFilter() < 0) {
800 /* Update (cvt) with filter details... */
801 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
805 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
806 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
807 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
808 if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
809 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
811 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
812 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
814 if (src_rate < dst_rate) {
815 const double mult = ((double) dst_rate) / ((double) src_rate);
816 cvt->len_mult *= (int) SDL_ceil(mult);
817 cvt->len_ratio *= mult;
819 cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
822 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
823 /* the buffer is big enough to hold the destination now, but
824 we need it large enough to hold a separate scratch buffer. */
827 return 1; /* added a converter. */
831 SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
844 return SDL_TRUE; /* supported. */
850 return SDL_FALSE; /* unsupported. */
854 SDL_SupportedChannelCount(const int channels)
862 return SDL_TRUE; /* supported. */
868 return SDL_FALSE; /* unsupported. */
872 /* Creates a set of audio filters to convert from one format to another.
873 Returns 0 if no conversion is needed, 1 if the audio filter is set up,
874 or -1 if an error like invalid parameter, unsupported format, etc. occurred.
878 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
879 SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
880 SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
882 /* Sanity check target pointer */
884 return SDL_InvalidParamError("cvt");
887 /* Make sure we zero out the audio conversion before error checking */
890 if (!SDL_SupportedAudioFormat(src_fmt)) {
891 return SDL_SetError("Invalid source format");
892 } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
893 return SDL_SetError("Invalid destination format");
894 } else if (!SDL_SupportedChannelCount(src_channels)) {
895 return SDL_SetError("Invalid source channels");
896 } else if (!SDL_SupportedChannelCount(dst_channels)) {
897 return SDL_SetError("Invalid destination channels");
898 } else if (src_rate <= 0) {
899 return SDL_SetError("Source rate is equal to or less than zero");
900 } else if (dst_rate <= 0) {
901 return SDL_SetError("Destination rate is equal to or less than zero");
902 } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
903 return SDL_SetError("Source rate is too high");
904 } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
905 return SDL_SetError("Destination rate is too high");
909 printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
910 src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
913 /* Start off with no conversion necessary */
914 cvt->src_format = src_fmt;
915 cvt->dst_format = dst_fmt;
917 cvt->filter_index = 0;
918 SDL_zeroa(cvt->filters);
920 cvt->len_ratio = 1.0;
921 cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
923 /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
924 SDL_ChooseAudioConverters();
926 /* Type conversion goes like this now:
927 - byteswap to CPU native format first if necessary.
928 - convert to native Float32 if necessary.
929 - resample and change channel count if necessary.
930 - convert back to native format.
931 - byteswap back to foreign format if necessary.
933 The expectation is we can process data faster in float32
934 (possibly with SIMD), and making several passes over the same
935 buffer is likely to be CPU cache-friendly, avoiding the
936 biggest performance hit in modern times. Previously we had
937 (script-generated) custom converters for every data type and
938 it was a bloat on SDL compile times and final library size. */
940 /* see if we can skip float conversion entirely. */
941 if (src_rate == dst_rate && src_channels == dst_channels) {
942 if (src_fmt == dst_fmt) {
946 /* just a byteswap needed? */
947 if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
948 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
956 /* Convert data types, if necessary. Updates (cvt). */
957 if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
958 return -1; /* shouldn't happen, but just in case... */
961 /* Channel conversion */
962 if (src_channels < dst_channels) {
964 /* Mono -> Stereo [-> ...] */
965 if ((src_channels == 1) && (dst_channels > 1)) {
966 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
973 /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
974 if ((src_channels == 2) && (dst_channels >= 6)) {
975 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
982 /* Quad -> 5.1 [-> 7.1] */
983 if ((src_channels == 4) && (dst_channels >= 6)) {
984 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
988 cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
989 cvt->len_ratio *= 1.5;
991 /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
992 if ((src_channels == 6) && (dst_channels == 8)) {
993 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
997 cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
998 /* Should be numerically exact with every valid input to this
1000 cvt->len_ratio = cvt->len_ratio * 4 / 3;
1002 /* [Mono ->] Stereo -> Quad */
1003 if ((src_channels == 2) && (dst_channels == 4)) {
1004 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
1009 cvt->len_ratio *= 2;
1011 } else if (src_channels > dst_channels) {
1013 /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
1014 /* 7.1 -> 5.1 [-> Quad] */
1015 if ((src_channels == 8) && (dst_channels <= 6)) {
1016 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
1020 cvt->len_ratio *= 0.75;
1022 /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
1023 if ((src_channels == 6) && (dst_channels <= 2)) {
1024 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
1028 cvt->len_ratio /= 3;
1031 if ((src_channels == 6) && (dst_channels == 4)) {
1032 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
1036 cvt->len_ratio = cvt->len_ratio * 2 / 3;
1038 /* Quad -> Stereo [-> Mono] */
1039 if ((src_channels == 4) && (dst_channels <= 2)) {
1040 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
1044 cvt->len_ratio /= 2;
1046 /* [... ->] Stereo -> Mono */
1047 if ((src_channels == 2) && (dst_channels == 1)) {
1048 SDL_AudioFilter filter = NULL;
1050 #if HAVE_SSE3_INTRINSICS
1051 if (SDL_HasSSE3()) {
1052 filter = SDL_ConvertStereoToMono_SSE3;
1057 filter = SDL_ConvertStereoToMono;
1060 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
1065 cvt->len_ratio /= 2;
1069 if (src_channels != dst_channels) {
1070 /* All combinations of supported channel counts should have been
1071 handled by now, but let's be defensive */
1072 return SDL_SetError("Invalid channel combination");
1075 /* Do rate conversion, if necessary. Updates (cvt). */
1076 if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
1077 return -1; /* shouldn't happen, but just in case... */
1080 /* Move to final data type. */
1081 if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
1082 return -1; /* shouldn't happen, but just in case... */
1085 cvt->needed = (cvt->filter_index != 0);
1086 return (cvt->needed);
1089 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
1090 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
1091 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
1093 struct _SDL_AudioStream
1095 SDL_AudioCVT cvt_before_resampling;
1096 SDL_AudioCVT cvt_after_resampling;
1097 SDL_DataQueue *queue;
1099 Uint8 *staging_buffer;
1100 int staging_buffer_size;
1101 int staging_buffer_filled;
1102 Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
1103 int work_buffer_len;
1104 int src_sample_frame_size;
1105 SDL_AudioFormat src_format;
1108 int dst_sample_frame_size;
1109 SDL_AudioFormat dst_format;
1113 Uint8 pre_resample_channels;
1115 int resampler_padding_samples;
1116 float *resampler_padding;
1117 void *resampler_state;
1118 SDL_ResampleAudioStreamFunc resampler_func;
1119 SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
1120 SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
1124 EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
1129 if (stream->work_buffer_len >= newlen) {
1130 ptr = stream->work_buffer_base;
1132 ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
1137 /* Make sure we're aligned to 16 bytes for SIMD code. */
1138 stream->work_buffer_base = ptr;
1139 stream->work_buffer_len = newlen;
1142 offset = ((size_t) ptr) & 15;
1143 return offset ? ptr + (16 - offset) : ptr;
1146 #ifdef HAVE_LIBSAMPLERATE_H
1148 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1150 const float *inbuf = (const float *) _inbuf;
1151 float *outbuf = (float *) _outbuf;
1152 const int framelen = sizeof(float) * stream->pre_resample_channels;
1153 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1157 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1159 data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
1160 data.input_frames = inbuflen / framelen;
1161 data.input_frames_used = 0;
1163 data.data_out = outbuf;
1164 data.output_frames = outbuflen / framelen;
1166 data.end_of_input = 0;
1167 data.src_ratio = stream->rate_incr;
1169 result = SRC_src_process(state, &data);
1171 SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
1175 /* If this fails, we need to store them off somewhere */
1176 SDL_assert(data.input_frames_used == data.input_frames);
1178 return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
1182 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
1184 SRC_src_reset((SRC_STATE *)stream->resampler_state);
1188 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
1190 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1192 SRC_src_delete(state);
1195 stream->resampler_state = NULL;
1196 stream->resampler_func = NULL;
1197 stream->reset_resampler_func = NULL;
1198 stream->cleanup_resampler_func = NULL;
1202 SetupLibSampleRateResampling(SDL_AudioStream *stream)
1205 SRC_STATE *state = NULL;
1207 if (SRC_available) {
1208 state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
1210 SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
1215 SDL_CleanupAudioStreamResampler_SRC(stream);
1219 stream->resampler_state = state;
1220 stream->resampler_func = SDL_ResampleAudioStream_SRC;
1221 stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
1222 stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
1226 #endif /* HAVE_LIBSAMPLERATE_H */
1230 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1232 const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
1233 const float *inbuf = (const float *) _inbuf;
1234 float *outbuf = (float *) _outbuf;
1235 const int chans = (int) stream->pre_resample_channels;
1236 const int inrate = stream->src_rate;
1237 const int outrate = stream->dst_rate;
1238 const int paddingsamples = stream->resampler_padding_samples;
1239 const int paddingbytes = paddingsamples * sizeof (float);
1240 float *lpadding = (float *) stream->resampler_state;
1241 const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
1242 const int cpy = SDL_min(inbuflen, paddingbytes);
1245 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1247 retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
1249 /* update our left padding with end of current input, for next run. */
1250 SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
1255 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
1257 /* set all the padding to silence. */
1258 const int len = stream->resampler_padding_samples;
1259 SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
1263 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
1265 SDL_free(stream->resampler_state);
1269 SDL_NewAudioStream(const SDL_AudioFormat src_format,
1270 const Uint8 src_channels,
1272 const SDL_AudioFormat dst_format,
1273 const Uint8 dst_channels,
1276 const int packetlen = 4096; /* !!! FIXME: good enough for now. */
1277 Uint8 pre_resample_channels;
1278 SDL_AudioStream *retval;
1280 retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
1285 /* If increasing channels, do it after resampling, since we'd just
1286 do more work to resample duplicate channels. If we're decreasing, do
1287 it first so we resample the interpolated data instead of interpolating
1288 the resampled data (!!! FIXME: decide if that works in practice, though!). */
1289 pre_resample_channels = SDL_min(src_channels, dst_channels);
1291 retval->first_run = SDL_TRUE;
1292 retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
1293 retval->src_format = src_format;
1294 retval->src_channels = src_channels;
1295 retval->src_rate = src_rate;
1296 retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
1297 retval->dst_format = dst_format;
1298 retval->dst_channels = dst_channels;
1299 retval->dst_rate = dst_rate;
1300 retval->pre_resample_channels = pre_resample_channels;
1301 retval->packetlen = packetlen;
1302 retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
1303 retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
1304 retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float));
1306 if (retval->resampler_padding == NULL) {
1307 SDL_FreeAudioStream(retval);
1312 retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
1313 if (retval->staging_buffer_size > 0) {
1314 retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
1315 if (retval->staging_buffer == NULL) {
1316 SDL_FreeAudioStream(retval);
1322 /* Not resampling? It's an easy conversion (and maybe not even that!) */
1323 if (src_rate == dst_rate) {
1324 retval->cvt_before_resampling.needed = SDL_FALSE;
1325 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1326 SDL_FreeAudioStream(retval);
1327 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1330 /* Don't resample at first. Just get us to Float32 format. */
1331 /* !!! FIXME: convert to int32 on devices without hardware float. */
1332 if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
1333 SDL_FreeAudioStream(retval);
1334 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1337 #ifdef HAVE_LIBSAMPLERATE_H
1338 SetupLibSampleRateResampling(retval);
1341 if (!retval->resampler_func) {
1342 retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
1343 if (!retval->resampler_state) {
1344 SDL_FreeAudioStream(retval);
1349 if (SDL_PrepareResampleFilter() < 0) {
1350 SDL_free(retval->resampler_state);
1351 retval->resampler_state = NULL;
1352 SDL_FreeAudioStream(retval);
1356 retval->resampler_func = SDL_ResampleAudioStream;
1357 retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1358 retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
1361 /* Convert us to the final format after resampling. */
1362 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1363 SDL_FreeAudioStream(retval);
1364 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1368 retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
1369 if (!retval->queue) {
1370 SDL_FreeAudioStream(retval);
1371 return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */
1378 SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
1383 Uint8 *resamplebuf = NULL;
1384 int resamplebuflen = 0;
1385 int neededpaddingbytes;
1388 /* !!! FIXME: several converters can take advantage of SIMD, but only
1389 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1390 !!! FIXME: guarantees the buffer will align, but the
1391 !!! FIXME: converters will iterate over the data backwards if
1392 !!! FIXME: the output grows, and this means we won't align if buflen
1393 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1394 !!! FIXME: a few samples at the end and convert them separately. */
1396 /* no padding prepended on first run. */
1397 neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
1398 paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
1399 stream->first_run = SDL_FALSE;
1401 /* Make sure the work buffer can hold all the data we need at once... */
1402 workbuflen = buflen;
1403 if (stream->cvt_before_resampling.needed) {
1404 workbuflen *= stream->cvt_before_resampling.len_mult;
1407 if (stream->dst_rate != stream->src_rate) {
1408 /* resamples can't happen in place, so make space for second buf. */
1409 const int framesize = stream->pre_resample_channels * sizeof (float);
1410 const int frames = workbuflen / framesize;
1411 resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
1412 #if DEBUG_AUDIOSTREAM
1413 printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
1415 workbuflen += resamplebuflen;
1418 if (stream->cvt_after_resampling.needed) {
1419 /* !!! FIXME: buffer might be big enough already? */
1420 workbuflen *= stream->cvt_after_resampling.len_mult;
1423 workbuflen += neededpaddingbytes;
1425 #if DEBUG_AUDIOSTREAM
1426 printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
1429 workbuf = EnsureStreamBufferSize(stream, workbuflen);
1431 return -1; /* probably out of memory. */
1434 resamplebuf = workbuf; /* default if not resampling. */
1436 SDL_memcpy(workbuf + paddingbytes, buf, buflen);
1438 if (stream->cvt_before_resampling.needed) {
1439 stream->cvt_before_resampling.buf = workbuf + paddingbytes;
1440 stream->cvt_before_resampling.len = buflen;
1441 if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
1442 return -1; /* uhoh! */
1444 buflen = stream->cvt_before_resampling.len_cvt;
1446 #if DEBUG_AUDIOSTREAM
1447 printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
1451 if (stream->dst_rate != stream->src_rate) {
1452 /* save off some samples at the end; they are used for padding now so
1453 the resampler is coherent and then used at the start of the next
1454 put operation. Prepend last put operation's padding, too. */
1456 /* prepend prior put's padding. :P */
1458 SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
1459 buflen += paddingbytes;
1462 /* save off the data at the end for the next run. */
1463 SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
1465 resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
1466 SDL_assert(buflen >= neededpaddingbytes);
1467 if (buflen > neededpaddingbytes) {
1468 buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
1473 #if DEBUG_AUDIOSTREAM
1474 printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
1478 if (stream->cvt_after_resampling.needed && (buflen > 0)) {
1479 stream->cvt_after_resampling.buf = resamplebuf;
1480 stream->cvt_after_resampling.len = buflen;
1481 if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
1482 return -1; /* uhoh! */
1484 buflen = stream->cvt_after_resampling.len_cvt;
1486 #if DEBUG_AUDIOSTREAM
1487 printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
1491 #if DEBUG_AUDIOSTREAM
1492 printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
1496 const int maxbytes = *maxputbytes;
1497 if (buflen > maxbytes)
1499 *maxputbytes -= buflen;
1502 /* resamplebuf holds the final output, even if we didn't resample. */
1503 return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
1507 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
1509 /* !!! FIXME: several converters can take advantage of SIMD, but only
1510 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1511 !!! FIXME: guarantees the buffer will align, but the
1512 !!! FIXME: converters will iterate over the data backwards if
1513 !!! FIXME: the output grows, and this means we won't align if buflen
1514 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1515 !!! FIXME: a few samples at the end and convert them separately. */
1517 #if DEBUG_AUDIOSTREAM
1518 printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
1522 return SDL_InvalidParamError("stream");
1524 return SDL_InvalidParamError("buf");
1525 } else if (len == 0) {
1526 return 0; /* nothing to do. */
1527 } else if ((len % stream->src_sample_frame_size) != 0) {
1528 return SDL_SetError("Can't add partial sample frames");
1531 if (!stream->cvt_before_resampling.needed &&
1532 (stream->dst_rate == stream->src_rate) &&
1533 !stream->cvt_after_resampling.needed) {
1534 #if DEBUG_AUDIOSTREAM
1535 printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
1537 return SDL_WriteToDataQueue(stream->queue, buf, len);
1543 /* If we don't have a staging buffer or we're given enough data that
1544 we don't need to store it for later, skip the staging process.
1546 if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
1547 return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
1550 /* If there's not enough data to fill the staging buffer, just save it */
1551 if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
1552 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
1553 stream->staging_buffer_filled += len;
1557 /* Fill the staging buffer, process it, and continue */
1558 amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
1559 SDL_assert(amount > 0);
1560 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
1561 stream->staging_buffer_filled = 0;
1562 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
1565 buf = (void *)((Uint8 *)buf + amount);
1571 int SDL_AudioStreamFlush(SDL_AudioStream *stream)
1574 return SDL_InvalidParamError("stream");
1577 #if DEBUG_AUDIOSTREAM
1578 printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
1581 /* shouldn't use a staging buffer if we're not resampling. */
1582 SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
1584 if (stream->staging_buffer_filled > 0) {
1585 /* push the staging buffer + silence. We need to flush out not just
1586 the staging buffer, but the piece that the stream was saving off
1587 for right-side resampler padding. */
1588 const SDL_bool first_run = stream->first_run;
1589 const int filled = stream->staging_buffer_filled;
1590 int actual_input_frames = filled / stream->src_sample_frame_size;
1592 actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
1594 if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
1595 /* This is how many bytes we're expecting without silence appended. */
1596 int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
1598 #if DEBUG_AUDIOSTREAM
1599 printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
1602 SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
1603 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1607 /* we have flushed out (or initially filled) the pending right-side
1608 resampler padding, but we need to push more silence to guarantee
1609 the staging buffer is fully flushed out, too. */
1610 SDL_memset(stream->staging_buffer, '\0', filled);
1611 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1617 stream->staging_buffer_filled = 0;
1618 stream->first_run = SDL_TRUE;
1623 /* get converted/resampled data from the stream */
1625 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
1627 #if DEBUG_AUDIOSTREAM
1628 printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
1632 return SDL_InvalidParamError("stream");
1634 return SDL_InvalidParamError("buf");
1635 } else if (len <= 0) {
1636 return 0; /* nothing to do. */
1637 } else if ((len % stream->dst_sample_frame_size) != 0) {
1638 return SDL_SetError("Can't request partial sample frames");
1641 return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
1644 /* number of converted/resampled bytes available */
1646 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
1648 return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
1652 SDL_AudioStreamClear(SDL_AudioStream *stream)
1655 SDL_InvalidParamError("stream");
1657 SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
1658 if (stream->reset_resampler_func) {
1659 stream->reset_resampler_func(stream);
1661 stream->first_run = SDL_TRUE;
1662 stream->staging_buffer_filled = 0;
1666 /* dispose of a stream */
1668 SDL_FreeAudioStream(SDL_AudioStream *stream)
1671 if (stream->cleanup_resampler_func) {
1672 stream->cleanup_resampler_func(stream);
1674 SDL_FreeDataQueue(stream->queue);
1675 SDL_free(stream->staging_buffer);
1676 SDL_free(stream->work_buffer_base);
1677 SDL_free(stream->resampler_padding);
1682 /* vi: set ts=4 sw=4 expandtab: */