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