src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 24 Jan 2017 00:51:33 -0500
changeset 10844 936e8095db14
parent 10843 31c9dede7b9c
child 10846 32efb3bc4db5
permissions -rw-r--r--
audio: Make sure SDL_AudioStream's work buffer is 16-byte aligned, for SIMD.

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