src/audio/SDL_audiocvt.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 12 Jun 2017 16:39:15 -0700
changeset 11096 819384789a7a
parent 10926 97c829825e0e
child 11097 62a0a6e9b48b
permissions -rw-r--r--
Fixed bug 3668 - Overflow of SDL_AudioCVT.filters with some downmixes

Simon Hug

There's a chance that an audio conversion from many channels to a few can use more than 9 audio filters. SDL_AudioCVT has 10 SDL_AudioFilter pointers of which one has to be the terminating NULL pointer. The SDL code has no checks for this limit. If it overflows there can be stack or heap corruption or a call to 0xa.

Attached patch adds a function that checks for this limit and throws an error if it is reached. Also adds some documentation.

Test parameters that trigger this issue:
AUDIO_U16MSB with 224 channels at 46359 Hz
V
AUDIO_S16MSB with 6 channels at 27463 Hz

The fuzzer program I uploaded in bug 3667 has more of them.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #include "SDL_audio.h"
    26 #include "SDL_audio_c.h"
    27 
    28 #include "SDL_loadso.h"
    29 #include "SDL_assert.h"
    30 #include "../SDL_dataqueue.h"
    31 #include "SDL_cpuinfo.h"
    32 
    33 #ifdef __SSE3__
    34 #define HAVE_SSE3_INTRINSICS 1
    35 #endif
    36 
    37 #if HAVE_SSE3_INTRINSICS
    38 /* Effectively mix right and left channels into a single channel */
    39 static void SDLCALL
    40 SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    41 {
    42     float *dst = (float *) cvt->buf;
    43     const float *src = dst;
    44     int i = cvt->len_cvt / 8;
    45 
    46     LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
    47     SDL_assert(format == AUDIO_F32SYS);
    48 
    49     /* We can only do this if dst is aligned to 16 bytes; since src is the
    50        same pointer and it moves by 2, it can't be forcibly aligned. */
    51     if ((((size_t) dst) & 15) == 0) {
    52         /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
    53         const __m128 divby2 = _mm_set1_ps(0.5f);
    54         while (i >= 4) {   /* 4 * float32 */
    55             _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
    56             i -= 4; src += 8; dst += 4;
    57         }
    58     }
    59 
    60     /* Finish off any leftovers with scalar operations. */
    61     while (i) {
    62         *dst = (src[0] + src[1]) * 0.5f;
    63         dst++; i--; src += 2;
    64     }
    65 
    66     cvt->len_cvt /= 2;
    67     if (cvt->filters[++cvt->filter_index]) {
    68         cvt->filters[cvt->filter_index] (cvt, format);
    69     }
    70 }
    71 #endif
    72 
    73 /* Effectively mix right and left channels into a single channel */
    74 static void SDLCALL
    75 SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    76 {
    77     float *dst = (float *) cvt->buf;
    78     const float *src = dst;
    79     int i;
    80 
    81     LOG_DEBUG_CONVERT("stereo", "mono");
    82     SDL_assert(format == AUDIO_F32SYS);
    83 
    84     for (i = cvt->len_cvt / 8; i; --i, src += 2) {
    85         *(dst++) = (src[0] + src[1]) * 0.5f;
    86     }
    87 
    88     cvt->len_cvt /= 2;
    89     if (cvt->filters[++cvt->filter_index]) {
    90         cvt->filters[cvt->filter_index] (cvt, format);
    91     }
    92 }
    93 
    94 
    95 /* Convert from 5.1 to stereo. Average left and right, discard subwoofer. */
    96 static void SDLCALL
    97 SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    98 {
    99     float *dst = (float *) cvt->buf;
   100     const float *src = dst;
   101     int i;
   102 
   103     LOG_DEBUG_CONVERT("5.1", "stereo");
   104     SDL_assert(format == AUDIO_F32SYS);
   105 
   106     /* this assumes FL+FR+FC+subwoof+BL+BR layout. */
   107     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
   108         const double front_center = (double) src[2];
   109         dst[0] = (float) ((src[0] + front_center + src[4]) / 3.0);  /* left */
   110         dst[1] = (float) ((src[1] + front_center + src[5]) / 3.0);  /* right */
   111     }
   112 
   113     cvt->len_cvt /= 3;
   114     if (cvt->filters[++cvt->filter_index]) {
   115         cvt->filters[cvt->filter_index] (cvt, format);
   116     }
   117 }
   118 
   119 
   120 /* Convert from 5.1 to quad */
   121 static void SDLCALL
   122 SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   123 {
   124     float *dst = (float *) cvt->buf;
   125     const float *src = dst;
   126     int i;
   127 
   128     LOG_DEBUG_CONVERT("5.1", "quad");
   129     SDL_assert(format == AUDIO_F32SYS);
   130 
   131     /* assumes quad is FL+FR+BL+BR layout and 5.1 is FL+FR+FC+subwoof+BL+BR */
   132     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
   133         /* FIXME: this is a good candidate for SIMD. */
   134         const double front_center = (double) src[2];
   135         dst[0] = (float) ((src[0] + front_center) * 0.5);  /* FL */
   136         dst[1] = (float) ((src[1] + front_center) * 0.5);  /* FR */
   137         dst[2] = (float) ((src[4] + front_center) * 0.5);  /* BL */
   138         dst[3] = (float) ((src[5] + front_center) * 0.5);  /* BR */
   139     }
   140 
   141     cvt->len_cvt /= 6;
   142     cvt->len_cvt *= 4;
   143     if (cvt->filters[++cvt->filter_index]) {
   144         cvt->filters[cvt->filter_index] (cvt, format);
   145     }
   146 }
   147 
   148 
   149 /* Duplicate a mono channel to both stereo channels */
   150 static void SDLCALL
   151 SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   152 {
   153     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   154     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   155     int i;
   156 
   157     LOG_DEBUG_CONVERT("mono", "stereo");
   158     SDL_assert(format == AUDIO_F32SYS);
   159 
   160     for (i = cvt->len_cvt / sizeof (float); i; --i) {
   161         src--;
   162         dst -= 2;
   163         dst[0] = dst[1] = *src;
   164     }
   165 
   166     cvt->len_cvt *= 2;
   167     if (cvt->filters[++cvt->filter_index]) {
   168         cvt->filters[cvt->filter_index] (cvt, format);
   169     }
   170 }
   171 
   172 
   173 /* Duplicate a stereo channel to a pseudo-5.1 stream */
   174 static void SDLCALL
   175 SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   176 {
   177     int i;
   178     float lf, rf, ce;
   179     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   180     float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
   181 
   182     LOG_DEBUG_CONVERT("stereo", "5.1");
   183     SDL_assert(format == AUDIO_F32SYS);
   184 
   185     for (i = cvt->len_cvt / 8; i; --i) {
   186         dst -= 6;
   187         src -= 2;
   188         lf = src[0];
   189         rf = src[1];
   190         ce = (lf + rf) * 0.5f;
   191         dst[0] = lf + (lf - ce);  /* FL */
   192         dst[1] = rf + (rf - ce);  /* FR */
   193         dst[2] = ce;  /* FC */
   194         dst[3] = ce;  /* !!! FIXME: wrong! This is the subwoofer. */
   195         dst[4] = lf;  /* BL */
   196         dst[5] = rf;  /* BR */
   197     }
   198 
   199     cvt->len_cvt *= 3;
   200     if (cvt->filters[++cvt->filter_index]) {
   201         cvt->filters[cvt->filter_index] (cvt, format);
   202     }
   203 }
   204 
   205 
   206 /* Duplicate a stereo channel to a pseudo-4.0 stream */
   207 static void SDLCALL
   208 SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   209 {
   210     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   211     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   212     float lf, rf;
   213     int i;
   214 
   215     LOG_DEBUG_CONVERT("stereo", "quad");
   216     SDL_assert(format == AUDIO_F32SYS);
   217 
   218     for (i = cvt->len_cvt / 8; i; --i) {
   219         dst -= 4;
   220         src -= 2;
   221         lf = src[0];
   222         rf = src[1];
   223         dst[0] = lf;  /* FL */
   224         dst[1] = rf;  /* FR */
   225         dst[2] = lf;  /* BL */
   226         dst[3] = rf;  /* BR */
   227     }
   228 
   229     cvt->len_cvt *= 2;
   230     if (cvt->filters[++cvt->filter_index]) {
   231         cvt->filters[cvt->filter_index] (cvt, format);
   232     }
   233 }
   234 
   235 static int
   236 SDL_ResampleAudioSimple(const int chans, const double rate_incr,
   237                         float *last_sample, const float *inbuf,
   238                         const int inbuflen, float *outbuf, const int outbuflen)
   239 {
   240     const int framelen = chans * (int)sizeof (float);
   241     const int total = (inbuflen / framelen);
   242     const int finalpos = (total * chans) - chans;
   243     const int dest_samples = (int)(((double)total) * rate_incr);
   244     const double src_incr = 1.0 / rate_incr;
   245     float *dst;
   246     double idx;
   247     int i;
   248 
   249     SDL_assert((dest_samples * framelen) <= outbuflen);
   250     SDL_assert((inbuflen % framelen) == 0);
   251 
   252     if (rate_incr > 1.0) {  /* upsample */
   253         float *target = (outbuf + chans);
   254         dst = outbuf + (dest_samples * chans);
   255         idx = (double) total;
   256 
   257         if (chans == 1) {
   258             const float final_sample = inbuf[finalpos];
   259             float earlier_sample = inbuf[finalpos];
   260             while (dst > target) {
   261                 const int pos = ((int) idx) * chans;
   262                 const float *src = &inbuf[pos];
   263                 const float val = *(--src);
   264                 SDL_assert(pos >= 0.0);
   265                 *(--dst) = (val + earlier_sample) * 0.5f;
   266                 earlier_sample = val;
   267                 idx -= src_incr;
   268             }
   269             /* do last sample, interpolated against previous run's state. */
   270             *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
   271             *last_sample = final_sample;
   272         } else if (chans == 2) {
   273             const float final_sample2 = inbuf[finalpos+1];
   274             const float final_sample1 = inbuf[finalpos];
   275             float earlier_sample2 = inbuf[finalpos];
   276             float earlier_sample1 = inbuf[finalpos-1];
   277             while (dst > target) {
   278                 const int pos = ((int) idx) * chans;
   279                 const float *src = &inbuf[pos];
   280                 const float val2 = *(--src);
   281                 const float val1 = *(--src);
   282                 SDL_assert(pos >= 0.0);
   283                 *(--dst) = (val2 + earlier_sample2) * 0.5f;
   284                 *(--dst) = (val1 + earlier_sample1) * 0.5f;
   285                 earlier_sample2 = val2;
   286                 earlier_sample1 = val1;
   287                 idx -= src_incr;
   288             }
   289             /* do last sample, interpolated against previous run's state. */
   290             *(--dst) = (inbuf[1] + last_sample[1]) * 0.5f;
   291             *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
   292             last_sample[1] = final_sample2;
   293             last_sample[0] = final_sample1;
   294         } else {
   295             const float *earlier_sample = &inbuf[finalpos];
   296             float final_sample[8];
   297             SDL_memcpy(final_sample, &inbuf[finalpos], framelen);
   298             while (dst > target) {
   299                 const int pos = ((int) idx) * chans;
   300                 const float *src = &inbuf[pos];
   301                 SDL_assert(pos >= 0.0);
   302                 for (i = chans - 1; i >= 0; i--) {
   303                     const float val = *(--src);
   304                     *(--dst) = (val + earlier_sample[i]) * 0.5f;
   305                 }
   306                 earlier_sample = src;
   307                 idx -= src_incr;
   308             }
   309             /* do last sample, interpolated against previous run's state. */
   310             for (i = chans - 1; i >= 0; i--) {
   311                 const float val = inbuf[i];
   312                 *(--dst) = (val + last_sample[i]) * 0.5f;
   313             }
   314             SDL_memcpy(last_sample, final_sample, framelen);
   315         }
   316 
   317         dst = (outbuf + (dest_samples * chans));
   318     } else {  /* downsample */
   319         float *target = (outbuf + (dest_samples * chans));
   320         dst = outbuf;
   321         idx = 0.0;
   322         if (chans == 1) {
   323             float last = *last_sample;
   324             while (dst < target) {
   325                 const int pos = ((int) idx) * chans;
   326                 const float val = inbuf[pos];
   327                 SDL_assert(pos <= finalpos);
   328                 *(dst++) = (val + last) * 0.5f;
   329                 last = val;
   330                 idx += src_incr;
   331             }
   332             *last_sample = last;
   333         } else if (chans == 2) {
   334             float last1 = last_sample[0];
   335             float last2 = last_sample[1];
   336             while (dst < target) {
   337                 const int pos = ((int) idx) * chans;
   338                 const float val1 = inbuf[pos];
   339                 const float val2 = inbuf[pos+1];
   340                 SDL_assert(pos <= finalpos);
   341                 *(dst++) = (val1 + last1) * 0.5f;
   342                 *(dst++) = (val2 + last2) * 0.5f;
   343                 last1 = val1;
   344                 last2 = val2;
   345                 idx += src_incr;
   346             }
   347             last_sample[0] = last1;
   348             last_sample[1] = last2;
   349         } else {
   350             while (dst < target) {
   351                 const int pos = ((int) idx) * chans;
   352                 const float *src = &inbuf[pos];
   353                 SDL_assert(pos <= finalpos);
   354                 for (i = 0; i < chans; i++) {
   355                     const float val = *(src++);
   356                     *(dst++) = (val + last_sample[i]) * 0.5f;
   357                     last_sample[i] = val;
   358                 }
   359                 idx += src_incr;
   360             }
   361         }
   362     }
   363 
   364     return (int) ((dst - outbuf) * ((int) sizeof (float)));
   365 }
   366 
   367 /* We keep one special-case fast path around for an extremely common audio format. */
   368 static int
   369 SDL_ResampleAudioSimple_si16_c2(const double rate_incr,
   370                         Sint16 *last_sample, const Sint16 *inbuf,
   371                         const int inbuflen, Sint16 *outbuf, const int outbuflen)
   372 {
   373     const int chans = 2;
   374     const int framelen = 4;  /* stereo 16 bit */
   375     const int total = (inbuflen / framelen);
   376     const int finalpos = (total * chans) - chans;
   377     const int dest_samples = (int)(((double)total) * rate_incr);
   378     const double src_incr = 1.0 / rate_incr;
   379     Sint16 *dst;
   380     double idx;
   381 
   382     SDL_assert((dest_samples * framelen) <= outbuflen);
   383     SDL_assert((inbuflen % framelen) == 0);
   384 
   385     if (rate_incr > 1.0) {
   386         Sint16 *target = (outbuf + chans);
   387         const Sint16 final_right = inbuf[finalpos+1];
   388         const Sint16 final_left = inbuf[finalpos];
   389         Sint16 earlier_right = inbuf[finalpos-1];
   390         Sint16 earlier_left = inbuf[finalpos-2];
   391         dst = outbuf + (dest_samples * chans);
   392         idx = (double) total;
   393 
   394         while (dst > target) {
   395             const int pos = ((int) idx) * chans;
   396             const Sint16 *src = &inbuf[pos];
   397             const Sint16 right = *(--src);
   398             const Sint16 left = *(--src);
   399             SDL_assert(pos >= 0.0);
   400             *(--dst) = (((Sint32) right) + ((Sint32) earlier_right)) >> 1;
   401             *(--dst) = (((Sint32) left) + ((Sint32) earlier_left)) >> 1;
   402             earlier_right = right;
   403             earlier_left = left;
   404             idx -= src_incr;
   405         }
   406 
   407         /* do last sample, interpolated against previous run's state. */
   408         *(--dst) = (((Sint32) inbuf[1]) + ((Sint32) last_sample[1])) >> 1;
   409         *(--dst) = (((Sint32) inbuf[0]) + ((Sint32) last_sample[0])) >> 1;
   410         last_sample[1] = final_right;
   411         last_sample[0] = final_left;
   412 
   413         dst = (outbuf + (dest_samples * chans));
   414     } else {
   415         Sint16 *target = (outbuf + (dest_samples * chans));
   416         dst = outbuf;
   417         idx = 0.0;
   418         while (dst < target) {
   419             const int pos = ((int) idx) * chans;
   420             const Sint16 *src = &inbuf[pos];
   421             const Sint16 left = *(src++);
   422             const Sint16 right = *(src++);
   423             SDL_assert(pos <= finalpos);
   424             *(dst++) = (((Sint32) left) + ((Sint32) last_sample[0])) >> 1;
   425             *(dst++) = (((Sint32) right) + ((Sint32) last_sample[1])) >> 1;
   426             last_sample[0] = left;
   427             last_sample[1] = right;
   428             idx += src_incr;
   429         }
   430     }
   431 
   432     return (int) ((dst - outbuf) * ((int) sizeof (Sint16)));
   433 }
   434 
   435 static void SDLCALL
   436 SDL_ResampleCVT_si16_c2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   437 {
   438     const Sint16 *src = (const Sint16 *) cvt->buf;
   439     const int srclen = cvt->len_cvt;
   440     Sint16 *dst = (Sint16 *) cvt->buf;
   441     const int dstlen = (cvt->len * cvt->len_mult);
   442     Sint16 state[2];
   443 
   444     state[0] = src[0];
   445     state[1] = src[1];
   446 
   447     SDL_assert(format == AUDIO_S16SYS);
   448 
   449     cvt->len_cvt = SDL_ResampleAudioSimple_si16_c2(cvt->rate_incr, state, src, srclen, dst, dstlen);
   450     if (cvt->filters[++cvt->filter_index]) {
   451         cvt->filters[cvt->filter_index](cvt, format);
   452     }
   453 }
   454 
   455 
   456 int
   457 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   458 {
   459     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   460     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   461 
   462     /* Make sure there's data to convert */
   463     if (cvt->buf == NULL) {
   464         return SDL_SetError("No buffer allocated for conversion");
   465     }
   466 
   467     /* Return okay if no conversion is necessary */
   468     cvt->len_cvt = cvt->len;
   469     if (cvt->filters[0] == NULL) {
   470         return 0;
   471     }
   472 
   473     /* Set up the conversion and go! */
   474     cvt->filter_index = 0;
   475     cvt->filters[0] (cvt, cvt->src_format);
   476     return 0;
   477 }
   478 
   479 static void SDLCALL
   480 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   481 {
   482 #if DEBUG_CONVERT
   483     printf("Converting byte order\n");
   484 #endif
   485 
   486     switch (SDL_AUDIO_BITSIZE(format)) {
   487         #define CASESWAP(b) \
   488             case b: { \
   489                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   490                 int i; \
   491                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   492                     *ptr = SDL_Swap##b(*ptr); \
   493                 } \
   494                 break; \
   495             }
   496 
   497         CASESWAP(16);
   498         CASESWAP(32);
   499         CASESWAP(64);
   500 
   501         #undef CASESWAP
   502 
   503         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   504     }
   505 
   506     if (cvt->filters[++cvt->filter_index]) {
   507         /* flip endian flag for data. */
   508         if (format & SDL_AUDIO_MASK_ENDIAN) {
   509             format &= ~SDL_AUDIO_MASK_ENDIAN;
   510         } else {
   511             format |= SDL_AUDIO_MASK_ENDIAN;
   512         }
   513         cvt->filters[cvt->filter_index](cvt, format);
   514     }
   515 }
   516 
   517 static int
   518 SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
   519 {
   520     if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
   521         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
   522     }
   523     if (filter == NULL) {
   524         return SDL_SetError("Audio filter pointer is NULL");
   525     }
   526     cvt->filters[cvt->filter_index++] = filter;
   527     cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
   528     return 0;
   529 }
   530 
   531 static int
   532 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   533 {
   534     int retval = 0;  /* 0 == no conversion necessary. */
   535 
   536     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   537         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   538             return -1;
   539         }
   540         retval = 1;  /* added a converter. */
   541     }
   542 
   543     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   544         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   545         const Uint16 dst_bitsize = 32;
   546         SDL_AudioFilter filter = NULL;
   547 
   548         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   549             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   550             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   551             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   552             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   553             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   554             default: SDL_assert(!"Unexpected audio format!"); break;
   555         }
   556 
   557         if (!filter) {
   558             return SDL_SetError("No conversion available for these formats");
   559         }
   560 
   561         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   562             return -1;
   563         }
   564         if (src_bitsize < dst_bitsize) {
   565             const int mult = (dst_bitsize / src_bitsize);
   566             cvt->len_mult *= mult;
   567             cvt->len_ratio *= mult;
   568         } else if (src_bitsize > dst_bitsize) {
   569             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   570         }
   571 
   572         retval = 1;  /* added a converter. */
   573     }
   574 
   575     return retval;
   576 }
   577 
   578 static int
   579 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   580 {
   581     int retval = 0;  /* 0 == no conversion necessary. */
   582 
   583     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   584         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   585         const Uint16 src_bitsize = 32;
   586         SDL_AudioFilter filter = NULL;
   587         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   588             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   589             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   590             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   591             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   592             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   593             default: SDL_assert(!"Unexpected audio format!"); break;
   594         }
   595 
   596         if (!filter) {
   597             return SDL_SetError("No conversion available for these formats");
   598         }
   599 
   600         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   601             return -1;
   602         }
   603         if (src_bitsize < dst_bitsize) {
   604             const int mult = (dst_bitsize / src_bitsize);
   605             cvt->len_mult *= mult;
   606             cvt->len_ratio *= mult;
   607         } else if (src_bitsize > dst_bitsize) {
   608             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   609         }
   610         retval = 1;  /* added a converter. */
   611     }
   612 
   613     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   614         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   615             return -1;
   616         }
   617         retval = 1;  /* added a converter. */
   618     }
   619 
   620     return retval;
   621 }
   622 
   623 static void
   624 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   625 {
   626     const float *src = (const float *) cvt->buf;
   627     const int srclen = cvt->len_cvt;
   628     float *dst = (float *) cvt->buf;
   629     const int dstlen = (cvt->len * cvt->len_mult);
   630     float state[8];
   631 
   632     SDL_assert(format == AUDIO_F32SYS);
   633 
   634     SDL_memcpy(state, src, chans*sizeof(*src));
   635 
   636     cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   637     if (cvt->filters[++cvt->filter_index]) {
   638         cvt->filters[cvt->filter_index](cvt, format);
   639     }
   640 }
   641 
   642 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   643    !!! FIXME:  store channel info, so we have to have function entry
   644    !!! FIXME:  points for each supported channel count and multiple
   645    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   646 #define RESAMPLER_FUNCS(chans) \
   647     static void SDLCALL \
   648     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   649         SDL_ResampleCVT(cvt, chans, format); \
   650     }
   651 RESAMPLER_FUNCS(1)
   652 RESAMPLER_FUNCS(2)
   653 RESAMPLER_FUNCS(4)
   654 RESAMPLER_FUNCS(6)
   655 RESAMPLER_FUNCS(8)
   656 #undef RESAMPLER_FUNCS
   657 
   658 static SDL_AudioFilter
   659 ChooseCVTResampler(const int dst_channels)
   660 {
   661     switch (dst_channels) {
   662         case 1: return SDL_ResampleCVT_c1;
   663         case 2: return SDL_ResampleCVT_c2;
   664         case 4: return SDL_ResampleCVT_c4;
   665         case 6: return SDL_ResampleCVT_c6;
   666         case 8: return SDL_ResampleCVT_c8;
   667         default: break;
   668     }
   669 
   670     return NULL;
   671 }
   672 
   673 static int
   674 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   675                           const int src_rate, const int dst_rate)
   676 {
   677     SDL_AudioFilter filter;
   678 
   679     if (src_rate == dst_rate) {
   680         return 0;  /* no conversion necessary. */
   681     }
   682 
   683     filter = ChooseCVTResampler(dst_channels);
   684     if (filter == NULL) {
   685         return SDL_SetError("No conversion available for these rates");
   686     }
   687 
   688     /* Update (cvt) with filter details... */
   689     if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   690         return -1;
   691     }
   692     if (src_rate < dst_rate) {
   693         const double mult = ((double) dst_rate) / ((double) src_rate);
   694         cvt->len_mult *= (int) SDL_ceil(mult);
   695         cvt->len_ratio *= mult;
   696     } else {
   697         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   698     }
   699 
   700     return 1;               /* added a converter. */
   701 }
   702 
   703 
   704 /* Creates a set of audio filters to convert from one format to another.
   705    Returns -1 if the format conversion is not supported, 0 if there's
   706    no conversion needed, or 1 if the audio filter is set up.
   707 */
   708 
   709 int
   710 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   711                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   712                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   713 {
   714     /* Sanity check target pointer */
   715     if (cvt == NULL) {
   716         return SDL_InvalidParamError("cvt");
   717     }
   718 
   719     /* Make sure we zero out the audio conversion before error checking */
   720     SDL_zerop(cvt);
   721 
   722     /* there are no unsigned types over 16 bits, so catch this up front. */
   723     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
   724         return SDL_SetError("Invalid source format");
   725     }
   726     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
   727         return SDL_SetError("Invalid destination format");
   728     }
   729 
   730     /* prevent possible divisions by zero, etc. */
   731     if ((src_channels == 0) || (dst_channels == 0)) {
   732         return SDL_SetError("Source or destination channels is zero");
   733     }
   734     if ((src_rate == 0) || (dst_rate == 0)) {
   735         return SDL_SetError("Source or destination rate is zero");
   736     }
   737 #if DEBUG_CONVERT
   738     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   739            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   740 #endif
   741 
   742     /* Start off with no conversion necessary */
   743     cvt->src_format = src_fmt;
   744     cvt->dst_format = dst_fmt;
   745     cvt->needed = 0;
   746     cvt->filter_index = 0;
   747     cvt->filters[0] = NULL;
   748     cvt->len_mult = 1;
   749     cvt->len_ratio = 1.0;
   750     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   751 
   752     /* SDL now favors float32 as its preferred internal format, and considers
   753        everything else to be a degenerate case that we might have to make
   754        multiple passes over the data to convert to and from float32 as
   755        necessary. That being said, we keep one special case around for
   756        efficiency: stereo data in Sint16 format, in the native byte order,
   757        that only needs resampling. This is likely to be the most popular
   758        legacy format, that apps, hardware and the OS are likely to be able
   759        to process directly, so we handle this one case directly without
   760        unnecessary conversions. This means that apps on embedded devices
   761        without floating point hardware should consider aiming for this
   762        format as well. */
   763     if ((src_channels == 2) && (dst_channels == 2) && (src_fmt == AUDIO_S16SYS) && (dst_fmt == AUDIO_S16SYS) && (src_rate != dst_rate)) {
   764         cvt->needed = 1;
   765         if (SDL_AddAudioCVTFilter(cvt, SDL_ResampleCVT_si16_c2) < 0) {
   766             return -1;
   767         }
   768         if (src_rate < dst_rate) {
   769             const double mult = ((double) dst_rate) / ((double) src_rate);
   770             cvt->len_mult *= (int) SDL_ceil(mult);
   771             cvt->len_ratio *= mult;
   772         } else {
   773             cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   774         }
   775         return 1;
   776     }
   777 
   778     /* Type conversion goes like this now:
   779         - byteswap to CPU native format first if necessary.
   780         - convert to native Float32 if necessary.
   781         - resample and change channel count if necessary.
   782         - convert back to native format.
   783         - byteswap back to foreign format if necessary.
   784 
   785        The expectation is we can process data faster in float32
   786        (possibly with SIMD), and making several passes over the same
   787        buffer is likely to be CPU cache-friendly, avoiding the
   788        biggest performance hit in modern times. Previously we had
   789        (script-generated) custom converters for every data type and
   790        it was a bloat on SDL compile times and final library size. */
   791 
   792     /* see if we can skip float conversion entirely. */
   793     if (src_rate == dst_rate && src_channels == dst_channels) {
   794         if (src_fmt == dst_fmt) {
   795             return 0;
   796         }
   797 
   798         /* just a byteswap needed? */
   799         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   800             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   801                 return -1;
   802             }
   803             cvt->needed = 1;
   804             return 1;
   805         }
   806     }
   807 
   808     /* Convert data types, if necessary. Updates (cvt). */
   809     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   810         return -1;              /* shouldn't happen, but just in case... */
   811     }
   812 
   813     /* Channel conversion */
   814     if (src_channels != dst_channels) {
   815         if ((src_channels == 1) && (dst_channels > 1)) {
   816             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
   817                 return -1;
   818             }
   819             cvt->len_mult *= 2;
   820             src_channels = 2;
   821             cvt->len_ratio *= 2;
   822         }
   823         if ((src_channels == 2) && (dst_channels == 6)) {
   824             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
   825                 return -1;
   826             }
   827             src_channels = 6;
   828             cvt->len_mult *= 3;
   829             cvt->len_ratio *= 3;
   830         }
   831         if ((src_channels == 2) && (dst_channels == 4)) {
   832             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
   833                 return -1;
   834             }
   835             src_channels = 4;
   836             cvt->len_mult *= 2;
   837             cvt->len_ratio *= 2;
   838         }
   839         while ((src_channels * 2) <= dst_channels) {
   840             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
   841                 return -1;
   842             }
   843             cvt->len_mult *= 2;
   844             src_channels *= 2;
   845             cvt->len_ratio *= 2;
   846         }
   847         if ((src_channels == 6) && (dst_channels <= 2)) {
   848             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
   849                 return -1;
   850             }
   851             src_channels = 2;
   852             cvt->len_ratio /= 3;
   853         }
   854         if ((src_channels == 6) && (dst_channels == 4)) {
   855             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
   856                 return -1;
   857             }
   858             src_channels = 4;
   859             cvt->len_ratio /= 2;
   860         }
   861         /* This assumes that 4 channel audio is in the format:
   862            Left {front/back} + Right {front/back}
   863            so converting to L/R stereo works properly.
   864          */
   865         while (((src_channels % 2) == 0) &&
   866                ((src_channels / 2) >= dst_channels)) {
   867             SDL_AudioFilter filter = NULL;
   868 
   869             #if HAVE_SSE3_INTRINSICS
   870             if (SDL_HasSSE3()) {
   871                 filter = SDL_ConvertStereoToMono_SSE3;
   872             }
   873             #endif
   874 
   875             if (!filter) {
   876                 filter = SDL_ConvertStereoToMono;
   877             }
   878 
   879             if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   880                 return -1;
   881             }
   882 
   883             src_channels /= 2;
   884             cvt->len_ratio /= 2;
   885         }
   886         if (src_channels != dst_channels) {
   887             /* Uh oh.. */ ;
   888         }
   889     }
   890 
   891     /* Do rate conversion, if necessary. Updates (cvt). */
   892     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
   893         return -1;              /* shouldn't happen, but just in case... */
   894     }
   895 
   896     /* Move to final data type. */
   897     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
   898         return -1;              /* shouldn't happen, but just in case... */
   899     }
   900 
   901     cvt->needed = (cvt->filter_index != 0);
   902     return (cvt->needed);
   903 }
   904 
   905 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
   906 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   907 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   908 
   909 struct SDL_AudioStream
   910 {
   911     SDL_AudioCVT cvt_before_resampling;
   912     SDL_AudioCVT cvt_after_resampling;
   913     SDL_DataQueue *queue;
   914     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
   915     int work_buffer_len;
   916     int src_sample_frame_size;
   917     SDL_AudioFormat src_format;
   918     Uint8 src_channels;
   919     int src_rate;
   920     int dst_sample_frame_size;
   921     SDL_AudioFormat dst_format;
   922     Uint8 dst_channels;
   923     int dst_rate;
   924     double rate_incr;
   925     Uint8 pre_resample_channels;
   926     int packetlen;
   927     void *resampler_state;
   928     SDL_ResampleAudioStreamFunc resampler_func;
   929     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   930     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   931 };
   932 
   933 static Uint8 *
   934 EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
   935 {
   936     Uint8 *ptr;
   937     size_t offset;
   938 
   939     if (stream->work_buffer_len >= newlen) {
   940         ptr = stream->work_buffer_base;
   941     } else {
   942         ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
   943         if (!ptr) {
   944             SDL_OutOfMemory();
   945             return NULL;
   946         }
   947         /* Make sure we're aligned to 16 bytes for SIMD code. */
   948         stream->work_buffer_base = ptr;
   949         stream->work_buffer_len = newlen;
   950     }
   951 
   952     offset = ((size_t) ptr) & 15;
   953     return offset ? ptr + (16 - offset) : ptr;
   954 }
   955 
   956 #ifdef HAVE_LIBSAMPLERATE_H
   957 static int
   958 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
   959 {
   960     const float *inbuf = (const float *) _inbuf;
   961     float *outbuf = (float *) _outbuf;
   962     const int framelen = sizeof(float) * stream->pre_resample_channels;
   963     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   964     SRC_DATA data;
   965     int result;
   966 
   967     if (inbuf == ((const float *) outbuf)) {  /* libsamplerate can't work in-place. */
   968         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
   969         if (ptr == NULL) {
   970             SDL_OutOfMemory();
   971             return 0;
   972         }
   973         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
   974         inbuf = (const float *) (ptr + outbuflen);
   975         outbuf = (float *) ptr;
   976     }
   977 
   978     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   979     data.input_frames = inbuflen / framelen;
   980     data.input_frames_used = 0;
   981 
   982     data.data_out = outbuf;
   983     data.output_frames = outbuflen / framelen;
   984 
   985     data.end_of_input = 0;
   986     data.src_ratio = stream->rate_incr;
   987 
   988     result = SRC_src_process(state, &data);
   989     if (result != 0) {
   990         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   991         return 0;
   992     }
   993 
   994     /* If this fails, we need to store them off somewhere */
   995     SDL_assert(data.input_frames_used == data.input_frames);
   996 
   997     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   998 }
   999 
  1000 static void
  1001 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1002 {
  1003     SRC_src_reset((SRC_STATE *)stream->resampler_state);
  1004 }
  1005 
  1006 static void
  1007 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1008 {
  1009     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1010     if (state) {
  1011         SRC_src_delete(state);
  1012     }
  1013 
  1014     stream->resampler_state = NULL;
  1015     stream->resampler_func = NULL;
  1016     stream->reset_resampler_func = NULL;
  1017     stream->cleanup_resampler_func = NULL;
  1018 }
  1019 
  1020 static SDL_bool
  1021 SetupLibSampleRateResampling(SDL_AudioStream *stream)
  1022 {
  1023     int result = 0;
  1024     SRC_STATE *state = NULL;
  1025 
  1026     if (SRC_available) {
  1027         state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
  1028         if (!state) {
  1029             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
  1030         }
  1031     }
  1032 
  1033     if (!state) {
  1034         SDL_CleanupAudioStreamResampler_SRC(stream);
  1035         return SDL_FALSE;
  1036     }
  1037 
  1038     stream->resampler_state = state;
  1039     stream->resampler_func = SDL_ResampleAudioStream_SRC;
  1040     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
  1041     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
  1042 
  1043     return SDL_TRUE;
  1044 }
  1045 #endif /* HAVE_LIBSAMPLERATE_H */
  1046 
  1047 
  1048 typedef struct
  1049 {
  1050     SDL_bool resampler_seeded;
  1051     union
  1052     {
  1053         float f[8];
  1054         Sint16 si16[2];
  1055     } resampler_state;
  1056 } SDL_AudioStreamResamplerState;
  1057 
  1058 static int
  1059 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1060 {
  1061     const float *inbuf = (const float *) _inbuf;
  1062     float *outbuf = (float *) _outbuf;
  1063     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1064     const int chans = (int)stream->pre_resample_channels;
  1065 
  1066     SDL_assert(chans <= SDL_arraysize(state->resampler_state.f));
  1067 
  1068     if (!state->resampler_seeded) {
  1069         SDL_memcpy(state->resampler_state.f, inbuf, chans * sizeof (float));
  1070         state->resampler_seeded = SDL_TRUE;
  1071     }
  1072 
  1073     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
  1074 }
  1075 
  1076 static int
  1077 SDL_ResampleAudioStream_si16_c2(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1078 {
  1079     const Sint16 *inbuf = (const Sint16 *) _inbuf;
  1080     Sint16 *outbuf = (Sint16 *) _outbuf;
  1081     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1082 
  1083     SDL_assert(((int)stream->pre_resample_channels) <= SDL_arraysize(state->resampler_state.si16));
  1084 
  1085     if (!state->resampler_seeded) {
  1086         state->resampler_state.si16[0] = inbuf[0];
  1087         state->resampler_state.si16[1] = inbuf[1];
  1088         state->resampler_seeded = SDL_TRUE;
  1089     }
  1090 
  1091     return SDL_ResampleAudioSimple_si16_c2(stream->rate_incr, state->resampler_state.si16, inbuf, inbuflen, outbuf, outbuflen);
  1092 }
  1093 
  1094 static void
  1095 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1096 {
  1097     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1098     state->resampler_seeded = SDL_FALSE;
  1099 }
  1100 
  1101 static void
  1102 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1103 {
  1104     SDL_free(stream->resampler_state);
  1105 }
  1106 
  1107 SDL_AudioStream *
  1108 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1109                    const Uint8 src_channels,
  1110                    const int src_rate,
  1111                    const SDL_AudioFormat dst_format,
  1112                    const Uint8 dst_channels,
  1113                    const int dst_rate)
  1114 {
  1115     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1116     Uint8 pre_resample_channels;
  1117     SDL_AudioStream *retval;
  1118 #ifndef HAVE_LIBSAMPLERATE_H
  1119     const SDL_bool SRC_available = SDL_FALSE;
  1120 #endif
  1121 
  1122     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1123     if (!retval) {
  1124         return NULL;
  1125     }
  1126 
  1127     /* If increasing channels, do it after resampling, since we'd just
  1128        do more work to resample duplicate channels. If we're decreasing, do
  1129        it first so we resample the interpolated data instead of interpolating
  1130        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1131     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1132 
  1133     retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
  1134     retval->src_format = src_format;
  1135     retval->src_channels = src_channels;
  1136     retval->src_rate = src_rate;
  1137     retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
  1138     retval->dst_format = dst_format;
  1139     retval->dst_channels = dst_channels;
  1140     retval->dst_rate = dst_rate;
  1141     retval->pre_resample_channels = pre_resample_channels;
  1142     retval->packetlen = packetlen;
  1143     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1144 
  1145     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1146     if (src_rate == dst_rate) {
  1147         retval->cvt_before_resampling.needed = SDL_FALSE;
  1148         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1149             SDL_FreeAudioStream(retval);
  1150             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1151         }
  1152     /* fast path special case for stereo Sint16 data that just needs resampling. */
  1153     } else if ((!SRC_available) && (src_channels == 2) && (dst_channels == 2) && (src_format == AUDIO_S16SYS) && (dst_format == AUDIO_S16SYS)) {
  1154         SDL_assert(src_rate != dst_rate);
  1155         retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1156         if (!retval->resampler_state) {
  1157             SDL_FreeAudioStream(retval);
  1158             SDL_OutOfMemory();
  1159             return NULL;
  1160         }
  1161         retval->resampler_func = SDL_ResampleAudioStream_si16_c2;
  1162         retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1163         retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1164     } else {
  1165         /* Don't resample at first. Just get us to Float32 format. */
  1166         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1167         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1168             SDL_FreeAudioStream(retval);
  1169             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1170         }
  1171 
  1172 #ifdef HAVE_LIBSAMPLERATE_H
  1173         SetupLibSampleRateResampling(retval);
  1174 #endif
  1175 
  1176         if (!retval->resampler_func) {
  1177             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1178             if (!retval->resampler_state) {
  1179                 SDL_FreeAudioStream(retval);
  1180                 SDL_OutOfMemory();
  1181                 return NULL;
  1182             }
  1183             retval->resampler_func = SDL_ResampleAudioStream;
  1184             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1185             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1186         }
  1187 
  1188         /* Convert us to the final format after resampling. */
  1189         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1190             SDL_FreeAudioStream(retval);
  1191             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1192         }
  1193     }
  1194 
  1195     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1196     if (!retval->queue) {
  1197         SDL_FreeAudioStream(retval);
  1198         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1199     }
  1200 
  1201     return retval;
  1202 }
  1203 
  1204 int
  1205 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1206 {
  1207     int buflen = (int) _buflen;
  1208     const void *origbuf = buf;
  1209 
  1210     /* !!! FIXME: several converters can take advantage of SIMD, but only
  1211        !!! FIXME:  if the data is aligned to 16 bytes. EnsureStreamBufferSize()
  1212        !!! FIXME:  guarantees the buffer will align, but the
  1213        !!! FIXME:  converters will iterate over the data backwards if
  1214        !!! FIXME:  the output grows, and this means we won't align if buflen
  1215        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1216        !!! FIXME:  a few samples at the end and convert them separately. */
  1217 
  1218     if (!stream) {
  1219         return SDL_InvalidParamError("stream");
  1220     } else if (!buf) {
  1221         return SDL_InvalidParamError("buf");
  1222     } else if (buflen == 0) {
  1223         return 0;  /* nothing to do. */
  1224     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1225         return SDL_SetError("Can't add partial sample frames");
  1226     }
  1227 
  1228     if (stream->cvt_before_resampling.needed) {
  1229         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1230         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1231         if (workbuf == NULL) {
  1232             return -1;  /* probably out of memory. */
  1233         }
  1234         SDL_assert(buf == origbuf);
  1235         SDL_memcpy(workbuf, buf, buflen);
  1236         stream->cvt_before_resampling.buf = workbuf;
  1237         stream->cvt_before_resampling.len = buflen;
  1238         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1239             return -1;   /* uhoh! */
  1240         }
  1241         buf = workbuf;
  1242         buflen = stream->cvt_before_resampling.len_cvt;
  1243     }
  1244 
  1245     if (stream->dst_rate != stream->src_rate) {
  1246         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1247         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1248         if (workbuf == NULL) {
  1249             return -1;  /* probably out of memory. */
  1250         }
  1251         /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
  1252            libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
  1253         if (buf != origbuf) {
  1254             buf = workbuf;  /* in case we realloc()'d the pointer. */
  1255         }
  1256         buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
  1257         buf = EnsureStreamBufferSize(stream, workbuflen);
  1258         SDL_assert(buf != NULL);  /* shouldn't be growing, just aligning. */
  1259     }
  1260 
  1261     if (stream->cvt_after_resampling.needed) {
  1262         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1263         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1264         if (workbuf == NULL) {
  1265             return -1;  /* probably out of memory. */
  1266         }
  1267         if (buf == origbuf) {  /* copy if we haven't before. */
  1268             SDL_memcpy(workbuf, buf, buflen);
  1269         }
  1270         stream->cvt_after_resampling.buf = workbuf;
  1271         stream->cvt_after_resampling.len = buflen;
  1272         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1273             return -1;   /* uhoh! */
  1274         }
  1275         buf = workbuf;
  1276         buflen = stream->cvt_after_resampling.len_cvt;
  1277     }
  1278 
  1279     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1280 }
  1281 
  1282 void
  1283 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1284 {
  1285     if (!stream) {
  1286         SDL_InvalidParamError("stream");
  1287     } else {
  1288         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1289         if (stream->reset_resampler_func) {
  1290             stream->reset_resampler_func(stream);
  1291         }
  1292     }
  1293 }
  1294 
  1295 
  1296 /* get converted/resampled data from the stream */
  1297 int
  1298 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1299 {
  1300     if (!stream) {
  1301         return SDL_InvalidParamError("stream");
  1302     } else if (!buf) {
  1303         return SDL_InvalidParamError("buf");
  1304     } else if (len == 0) {
  1305         return 0;  /* nothing to do. */
  1306     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1307         return SDL_SetError("Can't request partial sample frames");
  1308     }
  1309 
  1310     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1311 }
  1312 
  1313 /* number of converted/resampled bytes available */
  1314 int
  1315 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1316 {
  1317     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1318 }
  1319 
  1320 /* dispose of a stream */
  1321 void
  1322 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1323 {
  1324     if (stream) {
  1325         if (stream->cleanup_resampler_func) {
  1326             stream->cleanup_resampler_func(stream);
  1327         }
  1328         SDL_FreeDataQueue(stream->queue);
  1329         SDL_free(stream->work_buffer_base);
  1330         SDL_free(stream);
  1331     }
  1332 }
  1333 
  1334 /* vi: set ts=4 sw=4 expandtab: */
  1335