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