src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 24 Jan 2017 00:03:36 -0500
changeset 10841 b9d6a3d65394
parent 10840 3c3708a0b217
child 10842 30b37eaf3b3c
permissions -rw-r--r--
audio: Fixed off-by-one error in upsampling.
     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 float *inbuf, const int inbuflen, float *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 float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   894 {
   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     float resampler_state[8];
   974 } SDL_AudioStreamResamplerState;
   975 
   976 static int
   977 SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   978 {
   979     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   980     const int chans = (int)stream->pre_resample_channels;
   981 
   982     SDL_assert(chans <= SDL_arraysize(state->resampler_state));
   983 
   984     if (!state->resampler_seeded) {
   985         int i;
   986         for (i = 0; i < chans; i++) {
   987             state->resampler_state[i] = inbuf[i];
   988         }
   989         state->resampler_seeded = SDL_TRUE;
   990     }
   991 
   992     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
   993 }
   994 
   995 static void
   996 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
   997 {
   998     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   999     state->resampler_seeded = SDL_FALSE;
  1000 }
  1001 
  1002 static void
  1003 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1004 {
  1005     SDL_free(stream->resampler_state);
  1006 }
  1007 
  1008 SDL_AudioStream *
  1009 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1010                    const Uint8 src_channels,
  1011                    const int src_rate,
  1012                    const SDL_AudioFormat dst_format,
  1013                    const Uint8 dst_channels,
  1014                    const int dst_rate)
  1015 {
  1016     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1017     Uint8 pre_resample_channels;
  1018     SDL_AudioStream *retval;
  1019 
  1020     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1021     if (!retval) {
  1022         return NULL;
  1023     }
  1024 
  1025     /* If increasing channels, do it after resampling, since we'd just
  1026        do more work to resample duplicate channels. If we're decreasing, do
  1027        it first so we resample the interpolated data instead of interpolating
  1028        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1029     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1030 
  1031     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
  1032     retval->src_format = src_format;
  1033     retval->src_channels = src_channels;
  1034     retval->src_rate = src_rate;
  1035     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
  1036     retval->dst_format = dst_format;
  1037     retval->dst_channels = dst_channels;
  1038     retval->dst_rate = dst_rate;
  1039     retval->pre_resample_channels = pre_resample_channels;
  1040     retval->packetlen = packetlen;
  1041     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1042 
  1043     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1044     if (src_rate == dst_rate) {
  1045         retval->cvt_before_resampling.needed = SDL_FALSE;
  1046         retval->cvt_before_resampling.len_mult = 1;
  1047         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1048             SDL_FreeAudioStream(retval);
  1049             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1050         }
  1051     } else {
  1052         /* Don't resample at first. Just get us to Float32 format. */
  1053         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1054         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1055             SDL_FreeAudioStream(retval);
  1056             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1057         }
  1058 
  1059 #ifdef HAVE_LIBSAMPLERATE_H
  1060         SetupLibSampleRateResampling(retval);
  1061 #endif
  1062 
  1063         if (!retval->resampler_func) {
  1064             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1065             if (!retval->resampler_state) {
  1066                 SDL_FreeAudioStream(retval);
  1067                 SDL_OutOfMemory();
  1068                 return NULL;
  1069             }
  1070             retval->resampler_func = SDL_ResampleAudioStream;
  1071             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1072             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1073         }
  1074 
  1075         /* Convert us to the final format after resampling. */
  1076         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1077             SDL_FreeAudioStream(retval);
  1078             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1079         }
  1080     }
  1081 
  1082     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1083     if (!retval->queue) {
  1084         SDL_FreeAudioStream(retval);
  1085         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1086     }
  1087 
  1088     return retval;
  1089 }
  1090 
  1091 static Uint8 *
  1092 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
  1093 {
  1094     if (*len < newlen) {
  1095         void *ptr = SDL_realloc(*buf, newlen);
  1096         if (!ptr) {
  1097             SDL_OutOfMemory();
  1098             return NULL;
  1099         }
  1100         *buf = (Uint8 *) ptr;
  1101         *len = newlen;
  1102     }
  1103     return *buf;
  1104 }
  1105 
  1106 int
  1107 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1108 {
  1109     int buflen = (int) _buflen;
  1110 
  1111     if (!stream) {
  1112         return SDL_InvalidParamError("stream");
  1113     } else if (!buf) {
  1114         return SDL_InvalidParamError("buf");
  1115     } else if (buflen == 0) {
  1116         return 0;  /* nothing to do. */
  1117     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1118         return SDL_SetError("Can't add partial sample frames");
  1119     }
  1120 
  1121     if (stream->cvt_before_resampling.needed) {
  1122         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1123         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1124         if (workbuf == NULL) {
  1125             return -1;  /* probably out of memory. */
  1126         }
  1127         SDL_memcpy(workbuf, buf, buflen);
  1128         stream->cvt_before_resampling.buf = workbuf;
  1129         stream->cvt_before_resampling.len = buflen;
  1130         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1131             return -1;   /* uhoh! */
  1132         }
  1133         buf = workbuf;
  1134         buflen = stream->cvt_before_resampling.len_cvt;
  1135     }
  1136 
  1137     if (stream->dst_rate != stream->src_rate) {
  1138         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1139         float *workbuf = (float *) EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
  1140         if (workbuf == NULL) {
  1141             return -1;  /* probably out of memory. */
  1142         }
  1143         buflen = stream->resampler_func(stream, (float *) buf, buflen, workbuf, workbuflen);
  1144         buf = workbuf;
  1145     }
  1146 
  1147     if (stream->cvt_after_resampling.needed) {
  1148         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1149         Uint8 *workbuf;
  1150 
  1151         if (buf == stream->resample_buffer) {
  1152             workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
  1153         } else {
  1154             const int inplace = (buf == stream->work_buffer);
  1155             workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
  1156             if (workbuf && !inplace) {
  1157                 SDL_memcpy(workbuf, buf, buflen);
  1158             }
  1159         }
  1160 
  1161         if (workbuf == NULL) {
  1162             return -1;  /* probably out of memory. */
  1163         }
  1164 
  1165         stream->cvt_after_resampling.buf = workbuf;
  1166         stream->cvt_after_resampling.len = buflen;
  1167         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1168             return -1;   /* uhoh! */
  1169         }
  1170         buf = workbuf;
  1171         buflen = stream->cvt_after_resampling.len_cvt;
  1172     }
  1173 
  1174     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1175 }
  1176 
  1177 void
  1178 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1179 {
  1180     if (!stream) {
  1181         SDL_InvalidParamError("stream");
  1182     } else {
  1183         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1184         if (stream->reset_resampler_func) {
  1185             stream->reset_resampler_func(stream);
  1186         }
  1187     }
  1188 }
  1189 
  1190 
  1191 /* get converted/resampled data from the stream */
  1192 int
  1193 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1194 {
  1195     if (!stream) {
  1196         return SDL_InvalidParamError("stream");
  1197     } else if (!buf) {
  1198         return SDL_InvalidParamError("buf");
  1199     } else if (len == 0) {
  1200         return 0;  /* nothing to do. */
  1201     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1202         return SDL_SetError("Can't request partial sample frames");
  1203     }
  1204 
  1205     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1206 }
  1207 
  1208 /* number of converted/resampled bytes available */
  1209 int
  1210 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1211 {
  1212     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1213 }
  1214 
  1215 /* dispose of a stream */
  1216 void
  1217 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1218 {
  1219     if (stream) {
  1220         if (stream->cleanup_resampler_func) {
  1221             stream->cleanup_resampler_func(stream);
  1222         }
  1223         SDL_FreeDataQueue(stream->queue);
  1224         SDL_free(stream->work_buffer);
  1225         SDL_free(stream->resample_buffer);
  1226         SDL_free(stream);
  1227     }
  1228 }
  1229 
  1230 /* vi: set ts=4 sw=4 expandtab: */
  1231