src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 24 Jan 2017 00:17:40 -0500
changeset 10843 31c9dede7b9c
parent 10842 30b37eaf3b3c
child 10844 936e8095db14
permissions -rw-r--r--
audio: Streams now resample in-place. Removed second allocated buffer.
     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     int src_sample_frame_size;
   873     SDL_AudioFormat src_format;
   874     Uint8 src_channels;
   875     int src_rate;
   876     int dst_sample_frame_size;
   877     SDL_AudioFormat dst_format;
   878     Uint8 dst_channels;
   879     int dst_rate;
   880     double rate_incr;
   881     Uint8 pre_resample_channels;
   882     int packetlen;
   883     void *resampler_state;
   884     SDL_ResampleAudioStreamFunc resampler_func;
   885     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   886     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   887 };
   888 
   889 #ifdef HAVE_LIBSAMPLERATE_H
   890 static int
   891 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
   892 {
   893     const float *inbuf = (const float *) _inbuf;
   894     float *outbuf = (float *) _outbuf;
   895     const int framelen = sizeof(float) * stream->pre_resample_channels;
   896     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   897     SRC_DATA data;
   898     int result;
   899 
   900     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   901     data.input_frames = inbuflen / framelen;
   902     data.input_frames_used = 0;
   903 
   904     data.data_out = outbuf;
   905     data.output_frames = outbuflen / framelen;
   906 
   907     data.end_of_input = 0;
   908     data.src_ratio = stream->rate_incr;
   909 
   910     result = SRC_src_process(state, &data);
   911     if (result != 0) {
   912         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   913         return 0;
   914     }
   915 
   916     /* If this fails, we need to store them off somewhere */
   917     SDL_assert(data.input_frames_used == data.input_frames);
   918 
   919     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   920 }
   921 
   922 static void
   923 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
   924 {
   925     SRC_src_reset((SRC_STATE *)stream->resampler_state);
   926 }
   927 
   928 static void
   929 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
   930 {
   931     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   932     if (state) {
   933         SRC_src_delete(state);
   934     }
   935 
   936     stream->resampler_state = NULL;
   937     stream->resampler_func = NULL;
   938     stream->reset_resampler_func = NULL;
   939     stream->cleanup_resampler_func = NULL;
   940 }
   941 
   942 static SDL_bool
   943 SetupLibSampleRateResampling(SDL_AudioStream *stream)
   944 {
   945     int result = 0;
   946     SRC_STATE *state = NULL;
   947 
   948     if (SRC_available) {
   949         state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
   950         if (!state) {
   951             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
   952         }
   953     }
   954 
   955     if (!state) {
   956         SDL_CleanupAudioStreamResampler_SRC(stream);
   957         return SDL_FALSE;
   958     }
   959 
   960     stream->resampler_state = state;
   961     stream->resampler_func = SDL_ResampleAudioStream_SRC;
   962     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
   963     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
   964 
   965     return SDL_TRUE;
   966 }
   967 #endif /* HAVE_LIBSAMPLERATE_H */
   968 
   969 
   970 typedef struct
   971 {
   972     SDL_bool resampler_seeded;
   973     union
   974     {
   975         float f[8];
   976         Sint16 si16[2];
   977     } resampler_state;
   978 } SDL_AudioStreamResamplerState;
   979 
   980 static int
   981 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
   982 {
   983     const float *inbuf = (const float *) _inbuf;
   984     float *outbuf = (float *) _outbuf;
   985     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   986     const int chans = (int)stream->pre_resample_channels;
   987 
   988     SDL_assert(chans <= SDL_arraysize(state->resampler_state.f));
   989 
   990     if (!state->resampler_seeded) {
   991         SDL_memcpy(state->resampler_state.f, inbuf, chans * sizeof (float));
   992         state->resampler_seeded = SDL_TRUE;
   993     }
   994 
   995     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
   996 }
   997 
   998 static int
   999 SDL_ResampleAudioStream_si16_c2(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1000 {
  1001     const Sint16 *inbuf = (const Sint16 *) _inbuf;
  1002     Sint16 *outbuf = (Sint16 *) _outbuf;
  1003     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1004     const int chans = (int)stream->pre_resample_channels;
  1005 
  1006     SDL_assert(chans <= SDL_arraysize(state->resampler_state.si16));
  1007 
  1008     if (!state->resampler_seeded) {
  1009         state->resampler_state.si16[0] = inbuf[0];
  1010         state->resampler_state.si16[1] = inbuf[1];
  1011         state->resampler_seeded = SDL_TRUE;
  1012     }
  1013 
  1014     return SDL_ResampleAudioSimple_si16_c2(stream->rate_incr, state->resampler_state.si16, inbuf, inbuflen, outbuf, outbuflen);
  1015 }
  1016 
  1017 static void
  1018 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1019 {
  1020     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1021     state->resampler_seeded = SDL_FALSE;
  1022 }
  1023 
  1024 static void
  1025 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1026 {
  1027     SDL_free(stream->resampler_state);
  1028 }
  1029 
  1030 SDL_AudioStream *
  1031 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1032                    const Uint8 src_channels,
  1033                    const int src_rate,
  1034                    const SDL_AudioFormat dst_format,
  1035                    const Uint8 dst_channels,
  1036                    const int dst_rate)
  1037 {
  1038     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1039     Uint8 pre_resample_channels;
  1040     SDL_AudioStream *retval;
  1041 #ifndef HAVE_LIBSAMPLERATE_H
  1042     const SDL_bool SRC_available = SDL_FALSE;
  1043 #endif
  1044 
  1045     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1046     if (!retval) {
  1047         return NULL;
  1048     }
  1049 
  1050     /* If increasing channels, do it after resampling, since we'd just
  1051        do more work to resample duplicate channels. If we're decreasing, do
  1052        it first so we resample the interpolated data instead of interpolating
  1053        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1054     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1055 
  1056     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
  1057     retval->src_format = src_format;
  1058     retval->src_channels = src_channels;
  1059     retval->src_rate = src_rate;
  1060     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
  1061     retval->dst_format = dst_format;
  1062     retval->dst_channels = dst_channels;
  1063     retval->dst_rate = dst_rate;
  1064     retval->pre_resample_channels = pre_resample_channels;
  1065     retval->packetlen = packetlen;
  1066     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1067 
  1068     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1069     if (src_rate == dst_rate) {
  1070         retval->cvt_before_resampling.needed = SDL_FALSE;
  1071         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1072             SDL_FreeAudioStream(retval);
  1073             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1074         }
  1075     /* fast path special case for stereo Sint16 data that just needs resampling. */
  1076     } else if ((!SRC_available) && (src_channels == 2) && (dst_channels == 2) && (src_format == AUDIO_S16SYS) && (dst_format == AUDIO_S16SYS)) {
  1077         SDL_assert(src_rate != dst_rate);
  1078         retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1079         if (!retval->resampler_state) {
  1080             SDL_FreeAudioStream(retval);
  1081             SDL_OutOfMemory();
  1082             return NULL;
  1083         }
  1084         retval->resampler_func = SDL_ResampleAudioStream_si16_c2;
  1085         retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1086         retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1087     } else {
  1088         /* Don't resample at first. Just get us to Float32 format. */
  1089         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1090         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1091             SDL_FreeAudioStream(retval);
  1092             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1093         }
  1094 
  1095 #ifdef HAVE_LIBSAMPLERATE_H
  1096         SetupLibSampleRateResampling(retval);
  1097 #endif
  1098 
  1099         if (!retval->resampler_func) {
  1100             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1101             if (!retval->resampler_state) {
  1102                 SDL_FreeAudioStream(retval);
  1103                 SDL_OutOfMemory();
  1104                 return NULL;
  1105             }
  1106             retval->resampler_func = SDL_ResampleAudioStream;
  1107             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1108             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1109         }
  1110 
  1111         /* Convert us to the final format after resampling. */
  1112         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1113             SDL_FreeAudioStream(retval);
  1114             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1115         }
  1116     }
  1117 
  1118     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1119     if (!retval->queue) {
  1120         SDL_FreeAudioStream(retval);
  1121         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1122     }
  1123 
  1124     return retval;
  1125 }
  1126 
  1127 static Uint8 *
  1128 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
  1129 {
  1130     if (*len < newlen) {
  1131         void *ptr = SDL_realloc(*buf, newlen);
  1132         if (!ptr) {
  1133             SDL_OutOfMemory();
  1134             return NULL;
  1135         }
  1136         *buf = (Uint8 *) ptr;
  1137         *len = newlen;
  1138     }
  1139     return *buf;
  1140 }
  1141 
  1142 int
  1143 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1144 {
  1145     int buflen = (int) _buflen;
  1146     SDL_bool copied = SDL_FALSE;
  1147 
  1148     if (!stream) {
  1149         return SDL_InvalidParamError("stream");
  1150     } else if (!buf) {
  1151         return SDL_InvalidParamError("buf");
  1152     } else if (buflen == 0) {
  1153         return 0;  /* nothing to do. */
  1154     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1155         return SDL_SetError("Can't add partial sample frames");
  1156     }
  1157 
  1158     if (stream->cvt_before_resampling.needed) {
  1159         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1160         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1161         if (workbuf == NULL) {
  1162             return -1;  /* probably out of memory. */
  1163         }
  1164         copied = SDL_TRUE;
  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->work_buffer, &stream->work_buffer_len, workbuflen);
  1178         if (workbuf == NULL) {
  1179             return -1;  /* probably out of memory. */
  1180         }
  1181         if (!copied) {
  1182             SDL_memcpy(workbuf, buf, buflen);
  1183             copied = SDL_TRUE;
  1184         }
  1185         buflen = stream->resampler_func(stream, workbuf, buflen, workbuf, workbuflen);
  1186         buf = workbuf;
  1187     }
  1188 
  1189     if (stream->cvt_after_resampling.needed) {
  1190         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1191         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1192         if (workbuf == NULL) {
  1193             return -1;  /* probably out of memory. */
  1194         }
  1195         if (!copied) {
  1196             SDL_memcpy(workbuf, buf, buflen);
  1197             copied = SDL_TRUE;
  1198         }
  1199 
  1200         stream->cvt_after_resampling.buf = workbuf;
  1201         stream->cvt_after_resampling.len = buflen;
  1202         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1203             return -1;   /* uhoh! */
  1204         }
  1205         buf = workbuf;
  1206         buflen = stream->cvt_after_resampling.len_cvt;
  1207     }
  1208 
  1209     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1210 }
  1211 
  1212 void
  1213 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1214 {
  1215     if (!stream) {
  1216         SDL_InvalidParamError("stream");
  1217     } else {
  1218         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1219         if (stream->reset_resampler_func) {
  1220             stream->reset_resampler_func(stream);
  1221         }
  1222     }
  1223 }
  1224 
  1225 
  1226 /* get converted/resampled data from the stream */
  1227 int
  1228 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1229 {
  1230     if (!stream) {
  1231         return SDL_InvalidParamError("stream");
  1232     } else if (!buf) {
  1233         return SDL_InvalidParamError("buf");
  1234     } else if (len == 0) {
  1235         return 0;  /* nothing to do. */
  1236     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1237         return SDL_SetError("Can't request partial sample frames");
  1238     }
  1239 
  1240     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1241 }
  1242 
  1243 /* number of converted/resampled bytes available */
  1244 int
  1245 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1246 {
  1247     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1248 }
  1249 
  1250 /* dispose of a stream */
  1251 void
  1252 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1253 {
  1254     if (stream) {
  1255         if (stream->cleanup_resampler_func) {
  1256             stream->cleanup_resampler_func(stream);
  1257         }
  1258         SDL_FreeDataQueue(stream->queue);
  1259         SDL_free(stream->work_buffer);
  1260         SDL_free(stream);
  1261     }
  1262 }
  1263 
  1264 /* vi: set ts=4 sw=4 expandtab: */
  1265