src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 24 Jan 2017 00:08:24 -0500
changeset 10842 30b37eaf3b3c
parent 10841 b9d6a3d65394
child 10843 31c9dede7b9c
permissions -rw-r--r--
audio: allow stereo Sint16 resampling fast path in SDL_AudioStream.

This currently favors libsamplerate over the fast path (quality over speed),
but I'm not sure that's the correct approach, as there may be surprising
changes in performance metrics depending on what packages are available on
a user's system. That being said, currently, the only thing with access to
SDL_AudioStream is an SDL audio device's thread, and it might be mostly idle
otherwise, so maybe this is generally good.
     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] = { src[0], src[1] };
   443 
   444     SDL_assert(format == AUDIO_S16SYS);
   445 
   446     cvt->len_cvt = SDL_ResampleAudioSimple_si16_c2(cvt->rate_incr, state, src, srclen, dst, dstlen);
   447     if (cvt->filters[++cvt->filter_index]) {
   448         cvt->filters[cvt->filter_index](cvt, format);
   449     }
   450 }
   451 
   452 
   453 int
   454 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   455 {
   456     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   457     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   458 
   459     /* Make sure there's data to convert */
   460     if (cvt->buf == NULL) {
   461         return SDL_SetError("No buffer allocated for conversion");
   462     }
   463 
   464     /* Return okay if no conversion is necessary */
   465     cvt->len_cvt = cvt->len;
   466     if (cvt->filters[0] == NULL) {
   467         return 0;
   468     }
   469 
   470     /* Set up the conversion and go! */
   471     cvt->filter_index = 0;
   472     cvt->filters[0] (cvt, cvt->src_format);
   473     return 0;
   474 }
   475 
   476 static void SDLCALL
   477 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   478 {
   479 #if DEBUG_CONVERT
   480     printf("Converting byte order\n");
   481 #endif
   482 
   483     switch (SDL_AUDIO_BITSIZE(format)) {
   484         #define CASESWAP(b) \
   485             case b: { \
   486                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   487                 int i; \
   488                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   489                     *ptr = SDL_Swap##b(*ptr); \
   490                 } \
   491                 break; \
   492             }
   493 
   494         CASESWAP(16);
   495         CASESWAP(32);
   496         CASESWAP(64);
   497 
   498         #undef CASESWAP
   499 
   500         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   501     }
   502 
   503     if (cvt->filters[++cvt->filter_index]) {
   504         /* flip endian flag for data. */
   505         if (format & SDL_AUDIO_MASK_ENDIAN) {
   506             format &= ~SDL_AUDIO_MASK_ENDIAN;
   507         } else {
   508             format |= SDL_AUDIO_MASK_ENDIAN;
   509         }
   510         cvt->filters[cvt->filter_index](cvt, format);
   511     }
   512 }
   513 
   514 
   515 static int
   516 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   517 {
   518     int retval = 0;  /* 0 == no conversion necessary. */
   519 
   520     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   521         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   522         retval = 1;  /* added a converter. */
   523     }
   524 
   525     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   526         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   527         const Uint16 dst_bitsize = 32;
   528         SDL_AudioFilter filter = NULL;
   529 
   530         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   531             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   532             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   533             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   534             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   535             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   536             default: SDL_assert(!"Unexpected audio format!"); break;
   537         }
   538 
   539         if (!filter) {
   540             return SDL_SetError("No conversion available for these formats");
   541         }
   542 
   543         cvt->filters[cvt->filter_index++] = filter;
   544         if (src_bitsize < dst_bitsize) {
   545             const int mult = (dst_bitsize / src_bitsize);
   546             cvt->len_mult *= mult;
   547             cvt->len_ratio *= mult;
   548         } else if (src_bitsize > dst_bitsize) {
   549             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   550         }
   551 
   552         retval = 1;  /* added a converter. */
   553     }
   554 
   555     return retval;
   556 }
   557 
   558 static int
   559 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   560 {
   561     int retval = 0;  /* 0 == no conversion necessary. */
   562 
   563     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   564         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   565         const Uint16 src_bitsize = 32;
   566         SDL_AudioFilter filter = NULL;
   567         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   568             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   569             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   570             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   571             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   572             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   573             default: SDL_assert(!"Unexpected audio format!"); break;
   574         }
   575 
   576         if (!filter) {
   577             return SDL_SetError("No conversion available for these formats");
   578         }
   579 
   580         cvt->filters[cvt->filter_index++] = filter;
   581         if (src_bitsize < dst_bitsize) {
   582             const int mult = (dst_bitsize / src_bitsize);
   583             cvt->len_mult *= mult;
   584             cvt->len_ratio *= mult;
   585         } else if (src_bitsize > dst_bitsize) {
   586             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   587         }
   588         retval = 1;  /* added a converter. */
   589     }
   590 
   591     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   592         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   593         retval = 1;  /* added a converter. */
   594     }
   595 
   596     return retval;
   597 }
   598 
   599 static void
   600 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   601 {
   602     const float *src = (const float *) cvt->buf;
   603     const int srclen = cvt->len_cvt;
   604     float *dst = (float *) cvt->buf;
   605     const int dstlen = (cvt->len * cvt->len_mult);
   606     float state[8];
   607 
   608     SDL_assert(format == AUDIO_F32SYS);
   609 
   610     SDL_memcpy(state, src, chans*sizeof(*src));
   611 
   612     cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   613     if (cvt->filters[++cvt->filter_index]) {
   614         cvt->filters[cvt->filter_index](cvt, format);
   615     }
   616 }
   617 
   618 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   619    !!! FIXME:  store channel info, so we have to have function entry
   620    !!! FIXME:  points for each supported channel count and multiple
   621    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   622 #define RESAMPLER_FUNCS(chans) \
   623     static void SDLCALL \
   624     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   625         SDL_ResampleCVT(cvt, chans, format); \
   626     }
   627 RESAMPLER_FUNCS(1)
   628 RESAMPLER_FUNCS(2)
   629 RESAMPLER_FUNCS(4)
   630 RESAMPLER_FUNCS(6)
   631 RESAMPLER_FUNCS(8)
   632 #undef RESAMPLER_FUNCS
   633 
   634 static SDL_AudioFilter
   635 ChooseCVTResampler(const int dst_channels)
   636 {
   637     switch (dst_channels) {
   638         case 1: return SDL_ResampleCVT_c1;
   639         case 2: return SDL_ResampleCVT_c2;
   640         case 4: return SDL_ResampleCVT_c4;
   641         case 6: return SDL_ResampleCVT_c6;
   642         case 8: return SDL_ResampleCVT_c8;
   643         default: break;
   644     }
   645 
   646     return NULL;
   647 }
   648 
   649 static int
   650 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   651                           const int src_rate, const int dst_rate)
   652 {
   653     SDL_AudioFilter filter;
   654 
   655     if (src_rate == dst_rate) {
   656         return 0;  /* no conversion necessary. */
   657     }
   658 
   659     filter = ChooseCVTResampler(dst_channels);
   660     if (filter == NULL) {
   661         return SDL_SetError("No conversion available for these rates");
   662     }
   663 
   664     /* Update (cvt) with filter details... */
   665     cvt->filters[cvt->filter_index++] = filter;
   666     if (src_rate < dst_rate) {
   667         const double mult = ((double) dst_rate) / ((double) src_rate);
   668         cvt->len_mult *= (int) SDL_ceil(mult);
   669         cvt->len_ratio *= mult;
   670     } else {
   671         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   672     }
   673 
   674     return 1;               /* added a converter. */
   675 }
   676 
   677 
   678 /* Creates a set of audio filters to convert from one format to another.
   679    Returns -1 if the format conversion is not supported, 0 if there's
   680    no conversion needed, or 1 if the audio filter is set up.
   681 */
   682 
   683 int
   684 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   685                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   686                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   687 {
   688     /* Sanity check target pointer */
   689     if (cvt == NULL) {
   690         return SDL_InvalidParamError("cvt");
   691     }
   692 
   693     /* Make sure we zero out the audio conversion before error checking */
   694     SDL_zerop(cvt);
   695 
   696     /* there are no unsigned types over 16 bits, so catch this up front. */
   697     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
   698         return SDL_SetError("Invalid source format");
   699     }
   700     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
   701         return SDL_SetError("Invalid destination format");
   702     }
   703 
   704     /* prevent possible divisions by zero, etc. */
   705     if ((src_channels == 0) || (dst_channels == 0)) {
   706         return SDL_SetError("Source or destination channels is zero");
   707     }
   708     if ((src_rate == 0) || (dst_rate == 0)) {
   709         return SDL_SetError("Source or destination rate is zero");
   710     }
   711 #if DEBUG_CONVERT
   712     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   713            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   714 #endif
   715 
   716     /* Start off with no conversion necessary */
   717     cvt->src_format = src_fmt;
   718     cvt->dst_format = dst_fmt;
   719     cvt->needed = 0;
   720     cvt->filter_index = 0;
   721     cvt->filters[0] = NULL;
   722     cvt->len_mult = 1;
   723     cvt->len_ratio = 1.0;
   724     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   725 
   726     /* SDL now favors float32 as its preferred internal format, and considers
   727        everything else to be a degenerate case that we might have to make
   728        multiple passes over the data to convert to and from float32 as
   729        necessary. That being said, we keep one special case around for
   730        efficiency: stereo data in Sint16 format, in the native byte order,
   731        that only needs resampling. This is likely to be the most popular
   732        legacy format, that apps, hardware and the OS are likely to be able
   733        to process directly, so we handle this one case directly without
   734        unnecessary conversions. This means that apps on embedded devices
   735        without floating point hardware should consider aiming for this
   736        format as well. */
   737     if ((src_channels == 2) && (dst_channels == 2) && (src_fmt == AUDIO_S16SYS) && (dst_fmt == AUDIO_S16SYS) && (src_rate != dst_rate)) {
   738         cvt->needed = 1;
   739         cvt->filters[cvt->filter_index++] = SDL_ResampleCVT_si16_c2;
   740         if (src_rate < dst_rate) {
   741             const double mult = ((double) dst_rate) / ((double) src_rate);
   742             cvt->len_mult *= (int) SDL_ceil(mult);
   743             cvt->len_ratio *= mult;
   744         } else {
   745             cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   746         }
   747         return 1;
   748     }
   749 
   750     /* Type conversion goes like this now:
   751         - byteswap to CPU native format first if necessary.
   752         - convert to native Float32 if necessary.
   753         - resample and change channel count if necessary.
   754         - convert back to native format.
   755         - byteswap back to foreign format if necessary.
   756 
   757        The expectation is we can process data faster in float32
   758        (possibly with SIMD), and making several passes over the same
   759        buffer is likely to be CPU cache-friendly, avoiding the
   760        biggest performance hit in modern times. Previously we had
   761        (script-generated) custom converters for every data type and
   762        it was a bloat on SDL compile times and final library size. */
   763 
   764     /* see if we can skip float conversion entirely. */
   765     if (src_rate == dst_rate && src_channels == dst_channels) {
   766         if (src_fmt == dst_fmt) {
   767             return 0;
   768         }
   769 
   770         /* just a byteswap needed? */
   771         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   772             cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   773             cvt->needed = 1;
   774             return 1;
   775         }
   776     }
   777 
   778     /* Convert data types, if necessary. Updates (cvt). */
   779     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   780         return -1;              /* shouldn't happen, but just in case... */
   781     }
   782 
   783     /* Channel conversion */
   784     if (src_channels != dst_channels) {
   785         if ((src_channels == 1) && (dst_channels > 1)) {
   786             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   787             cvt->len_mult *= 2;
   788             src_channels = 2;
   789             cvt->len_ratio *= 2;
   790         }
   791         if ((src_channels == 2) && (dst_channels == 6)) {
   792             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
   793             src_channels = 6;
   794             cvt->len_mult *= 3;
   795             cvt->len_ratio *= 3;
   796         }
   797         if ((src_channels == 2) && (dst_channels == 4)) {
   798             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
   799             src_channels = 4;
   800             cvt->len_mult *= 2;
   801             cvt->len_ratio *= 2;
   802         }
   803         while ((src_channels * 2) <= dst_channels) {
   804             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   805             cvt->len_mult *= 2;
   806             src_channels *= 2;
   807             cvt->len_ratio *= 2;
   808         }
   809         if ((src_channels == 6) && (dst_channels <= 2)) {
   810             cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
   811             src_channels = 2;
   812             cvt->len_ratio /= 3;
   813         }
   814         if ((src_channels == 6) && (dst_channels == 4)) {
   815             cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
   816             src_channels = 4;
   817             cvt->len_ratio /= 2;
   818         }
   819         /* This assumes that 4 channel audio is in the format:
   820            Left {front/back} + Right {front/back}
   821            so converting to L/R stereo works properly.
   822          */
   823         while (((src_channels % 2) == 0) &&
   824                ((src_channels / 2) >= dst_channels)) {
   825             SDL_AudioFilter filter = NULL;
   826 
   827             #if HAVE_SSE3_INTRINSICS
   828             if (SDL_HasSSE3()) {
   829                 filter = SDL_ConvertStereoToMono_SSE3;
   830             }
   831             #endif
   832 
   833             if (!filter) {
   834                 filter = SDL_ConvertStereoToMono;
   835             }
   836 
   837             cvt->filters[cvt->filter_index++] = filter;
   838 
   839             src_channels /= 2;
   840             cvt->len_ratio /= 2;
   841         }
   842         if (src_channels != dst_channels) {
   843             /* Uh oh.. */ ;
   844         }
   845     }
   846 
   847     /* Do rate conversion, if necessary. Updates (cvt). */
   848     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
   849         return -1;              /* shouldn't happen, but just in case... */
   850     }
   851 
   852     /* Move to final data type. */
   853     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
   854         return -1;              /* shouldn't happen, but just in case... */
   855     }
   856 
   857     cvt->needed = (cvt->filter_index != 0);
   858     return (cvt->needed);
   859 }
   860 
   861 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
   862 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   863 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   864 
   865 struct SDL_AudioStream
   866 {
   867     SDL_AudioCVT cvt_before_resampling;
   868     SDL_AudioCVT cvt_after_resampling;
   869     SDL_DataQueue *queue;
   870     Uint8 *work_buffer;
   871     int work_buffer_len;
   872     Uint8 *resample_buffer;
   873     int resample_buffer_len;
   874     int src_sample_frame_size;
   875     SDL_AudioFormat src_format;
   876     Uint8 src_channels;
   877     int src_rate;
   878     int dst_sample_frame_size;
   879     SDL_AudioFormat dst_format;
   880     Uint8 dst_channels;
   881     int dst_rate;
   882     double rate_incr;
   883     Uint8 pre_resample_channels;
   884     int packetlen;
   885     void *resampler_state;
   886     SDL_ResampleAudioStreamFunc resampler_func;
   887     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   888     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   889 };
   890 
   891 #ifdef HAVE_LIBSAMPLERATE_H
   892 static int
   893 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
   894 {
   895     const float *inbuf = (const float *) _inbuf;
   896     float *outbuf = (float *) _outbuf;
   897     const int framelen = sizeof(float) * stream->pre_resample_channels;
   898     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   899     SRC_DATA data;
   900     int result;
   901 
   902     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   903     data.input_frames = inbuflen / framelen;
   904     data.input_frames_used = 0;
   905 
   906     data.data_out = outbuf;
   907     data.output_frames = outbuflen / framelen;
   908 
   909     data.end_of_input = 0;
   910     data.src_ratio = stream->rate_incr;
   911 
   912     result = SRC_src_process(state, &data);
   913     if (result != 0) {
   914         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   915         return 0;
   916     }
   917 
   918     /* If this fails, we need to store them off somewhere */
   919     SDL_assert(data.input_frames_used == data.input_frames);
   920 
   921     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   922 }
   923 
   924 static void
   925 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
   926 {
   927     SRC_src_reset((SRC_STATE *)stream->resampler_state);
   928 }
   929 
   930 static void
   931 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
   932 {
   933     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   934     if (state) {
   935         SRC_src_delete(state);
   936     }
   937 
   938     stream->resampler_state = NULL;
   939     stream->resampler_func = NULL;
   940     stream->reset_resampler_func = NULL;
   941     stream->cleanup_resampler_func = NULL;
   942 }
   943 
   944 static SDL_bool
   945 SetupLibSampleRateResampling(SDL_AudioStream *stream)
   946 {
   947     int result = 0;
   948     SRC_STATE *state = NULL;
   949 
   950     if (SRC_available) {
   951         state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
   952         if (!state) {
   953             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
   954         }
   955     }
   956 
   957     if (!state) {
   958         SDL_CleanupAudioStreamResampler_SRC(stream);
   959         return SDL_FALSE;
   960     }
   961 
   962     stream->resampler_state = state;
   963     stream->resampler_func = SDL_ResampleAudioStream_SRC;
   964     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
   965     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
   966 
   967     return SDL_TRUE;
   968 }
   969 #endif /* HAVE_LIBSAMPLERATE_H */
   970 
   971 
   972 typedef struct
   973 {
   974     SDL_bool resampler_seeded;
   975     union
   976     {
   977         float f[8];
   978         Sint16 si16[2];
   979     } resampler_state;
   980 } SDL_AudioStreamResamplerState;
   981 
   982 static int
   983 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
   984 {
   985     const float *inbuf = (const float *) _inbuf;
   986     float *outbuf = (float *) _outbuf;
   987     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   988     const int chans = (int)stream->pre_resample_channels;
   989 
   990     SDL_assert(chans <= SDL_arraysize(state->resampler_state.f));
   991 
   992     if (!state->resampler_seeded) {
   993         SDL_memcpy(state->resampler_state.f, inbuf, chans * sizeof (float));
   994         state->resampler_seeded = SDL_TRUE;
   995     }
   996 
   997     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
   998 }
   999 
  1000 static int
  1001 SDL_ResampleAudioStream_si16_c2(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1002 {
  1003     const Sint16 *inbuf = (const Sint16 *) _inbuf;
  1004     Sint16 *outbuf = (Sint16 *) _outbuf;
  1005     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1006     const int chans = (int)stream->pre_resample_channels;
  1007 
  1008     SDL_assert(chans <= SDL_arraysize(state->resampler_state.si16));
  1009 
  1010     if (!state->resampler_seeded) {
  1011         state->resampler_state.si16[0] = inbuf[0];
  1012         state->resampler_state.si16[1] = inbuf[1];
  1013         state->resampler_seeded = SDL_TRUE;
  1014     }
  1015 
  1016     return SDL_ResampleAudioSimple_si16_c2(stream->rate_incr, state->resampler_state.si16, inbuf, inbuflen, outbuf, outbuflen);
  1017 }
  1018 
  1019 static void
  1020 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1021 {
  1022     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1023     state->resampler_seeded = SDL_FALSE;
  1024 }
  1025 
  1026 static void
  1027 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1028 {
  1029     SDL_free(stream->resampler_state);
  1030 }
  1031 
  1032 SDL_AudioStream *
  1033 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1034                    const Uint8 src_channels,
  1035                    const int src_rate,
  1036                    const SDL_AudioFormat dst_format,
  1037                    const Uint8 dst_channels,
  1038                    const int dst_rate)
  1039 {
  1040     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1041     Uint8 pre_resample_channels;
  1042     SDL_AudioStream *retval;
  1043 #ifndef HAVE_LIBSAMPLERATE_H
  1044     const SDL_bool SRC_available = SDL_FALSE;
  1045 #endif
  1046 
  1047     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1048     if (!retval) {
  1049         return NULL;
  1050     }
  1051 
  1052     /* If increasing channels, do it after resampling, since we'd just
  1053        do more work to resample duplicate channels. If we're decreasing, do
  1054        it first so we resample the interpolated data instead of interpolating
  1055        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1056     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1057 
  1058     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
  1059     retval->src_format = src_format;
  1060     retval->src_channels = src_channels;
  1061     retval->src_rate = src_rate;
  1062     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
  1063     retval->dst_format = dst_format;
  1064     retval->dst_channels = dst_channels;
  1065     retval->dst_rate = dst_rate;
  1066     retval->pre_resample_channels = pre_resample_channels;
  1067     retval->packetlen = packetlen;
  1068     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1069 
  1070     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1071     if (src_rate == dst_rate) {
  1072         retval->cvt_before_resampling.needed = SDL_FALSE;
  1073         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1074             SDL_FreeAudioStream(retval);
  1075             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1076         }
  1077     /* fast path special case for stereo Sint16 data that just needs resampling. */
  1078     } else if ((!SRC_available) && (src_channels == 2) && (dst_channels == 2) && (src_format == AUDIO_S16SYS) && (dst_format == AUDIO_S16SYS)) {
  1079         SDL_assert(src_rate != dst_rate);
  1080         retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1081         if (!retval->resampler_state) {
  1082             SDL_FreeAudioStream(retval);
  1083             SDL_OutOfMemory();
  1084             return NULL;
  1085         }
  1086         retval->resampler_func = SDL_ResampleAudioStream_si16_c2;
  1087         retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1088         retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1089     } else {
  1090         /* Don't resample at first. Just get us to Float32 format. */
  1091         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1092         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1093             SDL_FreeAudioStream(retval);
  1094             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1095         }
  1096 
  1097 #ifdef HAVE_LIBSAMPLERATE_H
  1098         SetupLibSampleRateResampling(retval);
  1099 #endif
  1100 
  1101         if (!retval->resampler_func) {
  1102             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1103             if (!retval->resampler_state) {
  1104                 SDL_FreeAudioStream(retval);
  1105                 SDL_OutOfMemory();
  1106                 return NULL;
  1107             }
  1108             retval->resampler_func = SDL_ResampleAudioStream;
  1109             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1110             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1111         }
  1112 
  1113         /* Convert us to the final format after resampling. */
  1114         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1115             SDL_FreeAudioStream(retval);
  1116             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1117         }
  1118     }
  1119 
  1120     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1121     if (!retval->queue) {
  1122         SDL_FreeAudioStream(retval);
  1123         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1124     }
  1125 
  1126     return retval;
  1127 }
  1128 
  1129 static Uint8 *
  1130 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
  1131 {
  1132     if (*len < newlen) {
  1133         void *ptr = SDL_realloc(*buf, newlen);
  1134         if (!ptr) {
  1135             SDL_OutOfMemory();
  1136             return NULL;
  1137         }
  1138         *buf = (Uint8 *) ptr;
  1139         *len = newlen;
  1140     }
  1141     return *buf;
  1142 }
  1143 
  1144 int
  1145 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1146 {
  1147     int buflen = (int) _buflen;
  1148 
  1149     if (!stream) {
  1150         return SDL_InvalidParamError("stream");
  1151     } else if (!buf) {
  1152         return SDL_InvalidParamError("buf");
  1153     } else if (buflen == 0) {
  1154         return 0;  /* nothing to do. */
  1155     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1156         return SDL_SetError("Can't add partial sample frames");
  1157     }
  1158 
  1159     if (stream->cvt_before_resampling.needed) {
  1160         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1161         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1162         if (workbuf == NULL) {
  1163             return -1;  /* probably out of memory. */
  1164         }
  1165         SDL_memcpy(workbuf, buf, buflen);
  1166         stream->cvt_before_resampling.buf = workbuf;
  1167         stream->cvt_before_resampling.len = buflen;
  1168         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1169             return -1;   /* uhoh! */
  1170         }
  1171         buf = workbuf;
  1172         buflen = stream->cvt_before_resampling.len_cvt;
  1173     }
  1174 
  1175     if (stream->dst_rate != stream->src_rate) {
  1176         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1177         void *workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
  1178         if (workbuf == NULL) {
  1179             return -1;  /* probably out of memory. */
  1180         }
  1181         buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
  1182         buf = workbuf;
  1183     }
  1184 
  1185     if (stream->cvt_after_resampling.needed) {
  1186         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1187         Uint8 *workbuf;
  1188 
  1189         if (buf == stream->resample_buffer) {
  1190             workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
  1191         } else {
  1192             const int inplace = (buf == stream->work_buffer);
  1193             workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1194             if (workbuf && !inplace) {
  1195                 SDL_memcpy(workbuf, buf, buflen);
  1196             }
  1197         }
  1198 
  1199         if (workbuf == NULL) {
  1200             return -1;  /* probably out of memory. */
  1201         }
  1202 
  1203         stream->cvt_after_resampling.buf = workbuf;
  1204         stream->cvt_after_resampling.len = buflen;
  1205         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1206             return -1;   /* uhoh! */
  1207         }
  1208         buf = workbuf;
  1209         buflen = stream->cvt_after_resampling.len_cvt;
  1210     }
  1211 
  1212     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1213 }
  1214 
  1215 void
  1216 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1217 {
  1218     if (!stream) {
  1219         SDL_InvalidParamError("stream");
  1220     } else {
  1221         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1222         if (stream->reset_resampler_func) {
  1223             stream->reset_resampler_func(stream);
  1224         }
  1225     }
  1226 }
  1227 
  1228 
  1229 /* get converted/resampled data from the stream */
  1230 int
  1231 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1232 {
  1233     if (!stream) {
  1234         return SDL_InvalidParamError("stream");
  1235     } else if (!buf) {
  1236         return SDL_InvalidParamError("buf");
  1237     } else if (len == 0) {
  1238         return 0;  /* nothing to do. */
  1239     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1240         return SDL_SetError("Can't request partial sample frames");
  1241     }
  1242 
  1243     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1244 }
  1245 
  1246 /* number of converted/resampled bytes available */
  1247 int
  1248 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1249 {
  1250     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1251 }
  1252 
  1253 /* dispose of a stream */
  1254 void
  1255 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1256 {
  1257     if (stream) {
  1258         if (stream->cleanup_resampler_func) {
  1259             stream->cleanup_resampler_func(stream);
  1260         }
  1261         SDL_FreeDataQueue(stream->queue);
  1262         SDL_free(stream->work_buffer);
  1263         SDL_free(stream->resample_buffer);
  1264         SDL_free(stream);
  1265     }
  1266 }
  1267 
  1268 /* vi: set ts=4 sw=4 expandtab: */
  1269