src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 22 Jan 2017 23:48:15 -0500
changeset 10833 86f6353f1aae
parent 10832 189266031c6f
child 10834 336efe4fc373
permissions -rw-r--r--
audio: Make the simple resampler operate in-place.

This allows us to avoid an extra copy, allocate less memory and reduce cache
pressure. On the downside: we have to do a lot of tapdancing to resample the
buffer in reverse when the output is growing.
     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 
    32 /* !!! FIXME: wire this up to the configure script, etc. */
    33 #include "SDL_cpuinfo.h"
    34 #define HAVE_SSE3_INTRINSICS 0
    35 
    36 #if HAVE_SSE3_INTRINSICS
    37 #include <pmmintrin.h>
    38 #endif
    39 
    40 #if HAVE_SSE3_INTRINSICS
    41 /* Effectively mix right and left channels into a single channel */
    42 static void SDLCALL
    43 SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    44 {
    45     float *dst = (float *) cvt->buf;
    46     const float *src = dst;
    47     int i = cvt->len_cvt / 8;
    48 
    49     LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
    50     SDL_assert(format == AUDIO_F32SYS);
    51 
    52     /* We can only do this if dst is aligned to 16 bytes; since src is the
    53        same pointer and it moves by 2, it can't be forcibly aligned. */
    54     if ((((size_t) dst) & 15) == 0) {
    55         /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
    56         const __m128 divby2 = _mm_set1_ps(0.5f);
    57         while (i >= 4) {   /* 4 * float32 */
    58             _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
    59             i -= 4; src += 8; dst += 4;
    60         }
    61     }
    62 
    63     /* Finish off any leftovers with scalar operations. */
    64     while (i) {
    65         *dst = (src[0] + src[1]) * 0.5f;
    66         dst++; i--; src += 2;
    67     }
    68 
    69     cvt->len_cvt /= 2;
    70     if (cvt->filters[++cvt->filter_index]) {
    71         cvt->filters[cvt->filter_index] (cvt, format);
    72     }
    73 }
    74 #endif
    75 
    76 /* Effectively mix right and left channels into a single channel */
    77 static void SDLCALL
    78 SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    79 {
    80     float *dst = (float *) cvt->buf;
    81     const float *src = dst;
    82     int i;
    83 
    84     LOG_DEBUG_CONVERT("stereo", "mono");
    85     SDL_assert(format == AUDIO_F32SYS);
    86 
    87     for (i = cvt->len_cvt / 8; i; --i, src += 2) {
    88         *(dst++) = (src[0] + src[1]) * 0.5f;
    89     }
    90 
    91     cvt->len_cvt /= 2;
    92     if (cvt->filters[++cvt->filter_index]) {
    93         cvt->filters[cvt->filter_index] (cvt, format);
    94     }
    95 }
    96 
    97 
    98 /* Convert from 5.1 to stereo. Average left and right, discard subwoofer. */
    99 static void SDLCALL
   100 SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   101 {
   102     float *dst = (float *) cvt->buf;
   103     const float *src = dst;
   104     int i;
   105 
   106     LOG_DEBUG_CONVERT("5.1", "stereo");
   107     SDL_assert(format == AUDIO_F32SYS);
   108 
   109     /* this assumes FL+FR+FC+subwoof+BL+BR layout. */
   110     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
   111         const double front_center = (double) src[2];
   112         dst[0] = (float) ((src[0] + front_center + src[4]) / 3.0);  /* left */
   113         dst[1] = (float) ((src[1] + front_center + src[5]) / 3.0);  /* right */
   114     }
   115 
   116     cvt->len_cvt /= 3;
   117     if (cvt->filters[++cvt->filter_index]) {
   118         cvt->filters[cvt->filter_index] (cvt, format);
   119     }
   120 }
   121 
   122 
   123 /* Convert from 5.1 to quad */
   124 static void SDLCALL
   125 SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   126 {
   127     float *dst = (float *) cvt->buf;
   128     const float *src = dst;
   129     int i;
   130 
   131     LOG_DEBUG_CONVERT("5.1", "quad");
   132     SDL_assert(format == AUDIO_F32SYS);
   133 
   134     /* assumes quad is FL+FR+BL+BR layout and 5.1 is FL+FR+FC+subwoof+BL+BR */
   135     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
   136         /* FIXME: this is a good candidate for SIMD. */
   137         const double front_center = (double) src[2];
   138         dst[0] = (float) ((src[0] + front_center) * 0.5);  /* FL */
   139         dst[1] = (float) ((src[1] + front_center) * 0.5);  /* FR */
   140         dst[2] = (float) ((src[4] + front_center) * 0.5);  /* BL */
   141         dst[3] = (float) ((src[5] + front_center) * 0.5);  /* BR */
   142     }
   143 
   144     cvt->len_cvt /= 6;
   145     cvt->len_cvt *= 4;
   146     if (cvt->filters[++cvt->filter_index]) {
   147         cvt->filters[cvt->filter_index] (cvt, format);
   148     }
   149 }
   150 
   151 
   152 /* Duplicate a mono channel to both stereo channels */
   153 static void SDLCALL
   154 SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   155 {
   156     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   157     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   158     int i;
   159 
   160     LOG_DEBUG_CONVERT("mono", "stereo");
   161     SDL_assert(format == AUDIO_F32SYS);
   162 
   163     for (i = cvt->len_cvt / sizeof (float); i; --i) {
   164         src--;
   165         dst -= 2;
   166         dst[0] = dst[1] = *src;
   167     }
   168 
   169     cvt->len_cvt *= 2;
   170     if (cvt->filters[++cvt->filter_index]) {
   171         cvt->filters[cvt->filter_index] (cvt, format);
   172     }
   173 }
   174 
   175 
   176 /* Duplicate a stereo channel to a pseudo-5.1 stream */
   177 static void SDLCALL
   178 SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   179 {
   180     int i;
   181     float lf, rf, ce;
   182     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   183     float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
   184 
   185     LOG_DEBUG_CONVERT("stereo", "5.1");
   186     SDL_assert(format == AUDIO_F32SYS);
   187 
   188     for (i = cvt->len_cvt / 8; i; --i) {
   189         dst -= 6;
   190         src -= 2;
   191         lf = src[0];
   192         rf = src[1];
   193         ce = (lf + rf) * 0.5f;
   194         dst[0] = lf + (lf - ce);  /* FL */
   195         dst[1] = rf + (rf - ce);  /* FR */
   196         dst[2] = ce;  /* FC */
   197         dst[3] = ce;  /* !!! FIXME: wrong! This is the subwoofer. */
   198         dst[4] = lf;  /* BL */
   199         dst[5] = rf;  /* BR */
   200     }
   201 
   202     cvt->len_cvt *= 3;
   203     if (cvt->filters[++cvt->filter_index]) {
   204         cvt->filters[cvt->filter_index] (cvt, format);
   205     }
   206 }
   207 
   208 
   209 /* Duplicate a stereo channel to a pseudo-4.0 stream */
   210 static void SDLCALL
   211 SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   212 {
   213     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   214     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   215     float lf, rf;
   216     int i;
   217 
   218     LOG_DEBUG_CONVERT("stereo", "quad");
   219     SDL_assert(format == AUDIO_F32SYS);
   220 
   221     for (i = cvt->len_cvt / 8; i; --i) {
   222         dst -= 4;
   223         src -= 2;
   224         lf = src[0];
   225         rf = src[1];
   226         dst[0] = lf;  /* FL */
   227         dst[1] = rf;  /* FR */
   228         dst[2] = lf;  /* BL */
   229         dst[3] = rf;  /* BR */
   230     }
   231 
   232     cvt->len_cvt *= 2;
   233     if (cvt->filters[++cvt->filter_index]) {
   234         cvt->filters[cvt->filter_index] (cvt, format);
   235     }
   236 }
   237 
   238 static int
   239 SDL_ResampleAudioSimple(const int chans, const double rate_incr,
   240                         float *last_sample, const float *inbuf,
   241                         const int inbuflen, float *outbuf, const int outbuflen)
   242 {
   243     const int framelen = chans * (int)sizeof (float);
   244     const int total = (inbuflen / framelen);
   245     const int finalpos = (total * chans) - chans;
   246     const int dest_samples = (int)(((double)total) * rate_incr);
   247     const double src_incr = 1.0 / rate_incr;
   248     float *dst;
   249     double idx;
   250     int i;
   251 
   252     SDL_assert((dest_samples * framelen) <= outbuflen);
   253     SDL_assert((inbuflen % framelen) == 0);
   254 
   255     if (rate_incr > 1.0) {
   256         float *target = (outbuf + chans);
   257         const float *earlier_sample = &inbuf[finalpos];
   258         float final_sample[8];
   259         dst = outbuf + (dest_samples * chans);
   260         idx = (double) total;
   261 
   262         /* save this off so we can correctly maintain state between runs. */
   263         SDL_memcpy(final_sample, &inbuf[finalpos], framelen);
   264 
   265         while (dst > target) {
   266             const int pos = ((int) idx) * chans;
   267             const float *src = &inbuf[pos];
   268             SDL_assert(pos >= 0.0);
   269             for (i = chans - 1; i >= 0; i--) {
   270                 const float val = *(--src);
   271                 *(--dst) = (val + earlier_sample[i]) * 0.5f;
   272             }
   273             earlier_sample = src;
   274             idx -= src_incr;
   275         }
   276 
   277         /* do last sample, interpolated against previous run's state. */
   278         for (i = chans - 1; i >= 0; i--) {
   279             const float val = inbuf[i];
   280             *(--dst) = (val + last_sample[i]) * 0.5f;
   281         }
   282         SDL_memcpy(last_sample, final_sample, framelen);
   283         dst = (outbuf + (dest_samples * chans)) - 1;
   284     } else {
   285         float *target = (outbuf + (dest_samples * chans));
   286         dst = outbuf;
   287         idx = 0.0;
   288         while (dst < target) {
   289             const int pos = ((int) idx) * chans;
   290             const float *src = &inbuf[pos];
   291             SDL_assert(pos <= finalpos);
   292             for (i = 0; i < chans; i++) {
   293                 const float val = *(src++);
   294                 *(dst++) = (val + last_sample[i]) * 0.5f;
   295                 last_sample[i] = val;
   296             }
   297             idx += src_incr;
   298         }
   299     }
   300 
   301     return (int) ((dst - outbuf) * ((int) sizeof (float)));
   302 }
   303 
   304 
   305 int
   306 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   307 {
   308     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   309     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   310 
   311     /* Make sure there's data to convert */
   312     if (cvt->buf == NULL) {
   313         return SDL_SetError("No buffer allocated for conversion");
   314     }
   315 
   316     /* Return okay if no conversion is necessary */
   317     cvt->len_cvt = cvt->len;
   318     if (cvt->filters[0] == NULL) {
   319         return 0;
   320     }
   321 
   322     /* Set up the conversion and go! */
   323     cvt->filter_index = 0;
   324     cvt->filters[0] (cvt, cvt->src_format);
   325     return 0;
   326 }
   327 
   328 static void SDLCALL
   329 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   330 {
   331 #if DEBUG_CONVERT
   332     printf("Converting byte order\n");
   333 #endif
   334 
   335     switch (SDL_AUDIO_BITSIZE(format)) {
   336         #define CASESWAP(b) \
   337             case b: { \
   338                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   339                 int i; \
   340                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   341                     *ptr = SDL_Swap##b(*ptr); \
   342                 } \
   343                 break; \
   344             }
   345 
   346         CASESWAP(16);
   347         CASESWAP(32);
   348         CASESWAP(64);
   349 
   350         #undef CASESWAP
   351 
   352         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   353     }
   354 
   355     if (cvt->filters[++cvt->filter_index]) {
   356         /* flip endian flag for data. */
   357         if (format & SDL_AUDIO_MASK_ENDIAN) {
   358             format &= ~SDL_AUDIO_MASK_ENDIAN;
   359         } else {
   360             format |= SDL_AUDIO_MASK_ENDIAN;
   361         }
   362         cvt->filters[cvt->filter_index](cvt, format);
   363     }
   364 }
   365 
   366 
   367 static int
   368 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   369 {
   370     int retval = 0;  /* 0 == no conversion necessary. */
   371 
   372     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   373         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   374         retval = 1;  /* added a converter. */
   375     }
   376 
   377     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   378         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   379         const Uint16 dst_bitsize = 32;
   380         SDL_AudioFilter filter = NULL;
   381 
   382         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   383             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   384             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   385             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   386             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   387             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   388             default: SDL_assert(!"Unexpected audio format!"); break;
   389         }
   390 
   391         if (!filter) {
   392             return SDL_SetError("No conversion available for these formats");
   393         }
   394 
   395         cvt->filters[cvt->filter_index++] = filter;
   396         if (src_bitsize < dst_bitsize) {
   397             const int mult = (dst_bitsize / src_bitsize);
   398             cvt->len_mult *= mult;
   399             cvt->len_ratio *= mult;
   400         } else if (src_bitsize > dst_bitsize) {
   401             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   402         }
   403 
   404         retval = 1;  /* added a converter. */
   405     }
   406 
   407     return retval;
   408 }
   409 
   410 static int
   411 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   412 {
   413     int retval = 0;  /* 0 == no conversion necessary. */
   414 
   415     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   416         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   417         const Uint16 src_bitsize = 32;
   418         SDL_AudioFilter filter = NULL;
   419         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   420             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   421             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   422             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   423             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   424             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   425             default: SDL_assert(!"Unexpected audio format!"); break;
   426         }
   427 
   428         if (!filter) {
   429             return SDL_SetError("No conversion available for these formats");
   430         }
   431 
   432         cvt->filters[cvt->filter_index++] = filter;
   433         if (src_bitsize < dst_bitsize) {
   434             const int mult = (dst_bitsize / src_bitsize);
   435             cvt->len_mult *= mult;
   436             cvt->len_ratio *= mult;
   437         } else if (src_bitsize > dst_bitsize) {
   438             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   439         }
   440         retval = 1;  /* added a converter. */
   441     }
   442 
   443     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   444         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   445         retval = 1;  /* added a converter. */
   446     }
   447 
   448     return retval;
   449 }
   450 
   451 static void
   452 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   453 {
   454     const float *src = (const float *) cvt->buf;
   455     const int srclen = cvt->len_cvt;
   456     float *dst = (float *) cvt->buf;
   457     const int dstlen = (cvt->len * cvt->len_mult);
   458     float state[8];
   459 
   460     SDL_assert(format == AUDIO_F32SYS);
   461 
   462     SDL_memcpy(state, src, chans*sizeof(*src));
   463 
   464     cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   465     if (cvt->filters[++cvt->filter_index]) {
   466         cvt->filters[cvt->filter_index](cvt, format);
   467     }
   468 }
   469 
   470 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   471    !!! FIXME:  store channel info, so we have to have function entry
   472    !!! FIXME:  points for each supported channel count and multiple
   473    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   474 #define RESAMPLER_FUNCS(chans) \
   475     static void SDLCALL \
   476     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   477         SDL_ResampleCVT(cvt, chans, format); \
   478     }
   479 RESAMPLER_FUNCS(1)
   480 RESAMPLER_FUNCS(2)
   481 RESAMPLER_FUNCS(4)
   482 RESAMPLER_FUNCS(6)
   483 RESAMPLER_FUNCS(8)
   484 #undef RESAMPLER_FUNCS
   485 
   486 static SDL_AudioFilter
   487 ChooseCVTResampler(const int dst_channels)
   488 {
   489     switch (dst_channels) {
   490         case 1: return SDL_ResampleCVT_c1;
   491         case 2: return SDL_ResampleCVT_c2;
   492         case 4: return SDL_ResampleCVT_c4;
   493         case 6: return SDL_ResampleCVT_c6;
   494         case 8: return SDL_ResampleCVT_c8;
   495         default: break;
   496     }
   497 
   498     return NULL;
   499 }
   500 
   501 static int
   502 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   503                           const int src_rate, const int dst_rate)
   504 {
   505     SDL_AudioFilter filter;
   506 
   507     if (src_rate == dst_rate) {
   508         return 0;  /* no conversion necessary. */
   509     }
   510 
   511     filter = ChooseCVTResampler(dst_channels);
   512     if (filter == NULL) {
   513         return SDL_SetError("No conversion available for these rates");
   514     }
   515 
   516     /* Update (cvt) with filter details... */
   517     cvt->filters[cvt->filter_index++] = filter;
   518     if (src_rate < dst_rate) {
   519         const double mult = ((double) dst_rate) / ((double) src_rate);
   520         cvt->len_mult *= (int) SDL_ceil(mult);
   521         cvt->len_ratio *= mult;
   522     } else {
   523         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   524     }
   525 
   526     return 1;               /* added a converter. */
   527 }
   528 
   529 
   530 /* Creates a set of audio filters to convert from one format to another.
   531    Returns -1 if the format conversion is not supported, 0 if there's
   532    no conversion needed, or 1 if the audio filter is set up.
   533 */
   534 
   535 int
   536 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   537                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   538                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   539 {
   540     /* Sanity check target pointer */
   541     if (cvt == NULL) {
   542         return SDL_InvalidParamError("cvt");
   543     }
   544 
   545     /* Make sure we zero out the audio conversion before error checking */
   546     SDL_zerop(cvt);
   547 
   548     /* there are no unsigned types over 16 bits, so catch this up front. */
   549     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
   550         return SDL_SetError("Invalid source format");
   551     }
   552     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
   553         return SDL_SetError("Invalid destination format");
   554     }
   555 
   556     /* prevent possible divisions by zero, etc. */
   557     if ((src_channels == 0) || (dst_channels == 0)) {
   558         return SDL_SetError("Source or destination channels is zero");
   559     }
   560     if ((src_rate == 0) || (dst_rate == 0)) {
   561         return SDL_SetError("Source or destination rate is zero");
   562     }
   563 #if DEBUG_CONVERT
   564     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   565            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   566 #endif
   567 
   568     /* Start off with no conversion necessary */
   569     cvt->src_format = src_fmt;
   570     cvt->dst_format = dst_fmt;
   571     cvt->needed = 0;
   572     cvt->filter_index = 0;
   573     cvt->filters[0] = NULL;
   574     cvt->len_mult = 1;
   575     cvt->len_ratio = 1.0;
   576     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   577 
   578     /* Type conversion goes like this now:
   579         - byteswap to CPU native format first if necessary.
   580         - convert to native Float32 if necessary.
   581         - resample and change channel count if necessary.
   582         - convert back to native format.
   583         - byteswap back to foreign format if necessary.
   584 
   585        The expectation is we can process data faster in float32
   586        (possibly with SIMD), and making several passes over the same
   587        buffer is likely to be CPU cache-friendly, avoiding the
   588        biggest performance hit in modern times. Previously we had
   589        (script-generated) custom converters for every data type and
   590        it was a bloat on SDL compile times and final library size. */
   591 
   592     /* see if we can skip float conversion entirely. */
   593     if (src_rate == dst_rate && src_channels == dst_channels) {
   594         if (src_fmt == dst_fmt) {
   595             return 0;
   596         }
   597 
   598         /* just a byteswap needed? */
   599         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   600             cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   601             cvt->needed = 1;
   602             return 1;
   603         }
   604     }
   605 
   606     /* Convert data types, if necessary. Updates (cvt). */
   607     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   608         return -1;              /* shouldn't happen, but just in case... */
   609     }
   610 
   611     /* Channel conversion */
   612     if (src_channels != dst_channels) {
   613         if ((src_channels == 1) && (dst_channels > 1)) {
   614             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   615             cvt->len_mult *= 2;
   616             src_channels = 2;
   617             cvt->len_ratio *= 2;
   618         }
   619         if ((src_channels == 2) && (dst_channels == 6)) {
   620             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
   621             src_channels = 6;
   622             cvt->len_mult *= 3;
   623             cvt->len_ratio *= 3;
   624         }
   625         if ((src_channels == 2) && (dst_channels == 4)) {
   626             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
   627             src_channels = 4;
   628             cvt->len_mult *= 2;
   629             cvt->len_ratio *= 2;
   630         }
   631         while ((src_channels * 2) <= dst_channels) {
   632             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   633             cvt->len_mult *= 2;
   634             src_channels *= 2;
   635             cvt->len_ratio *= 2;
   636         }
   637         if ((src_channels == 6) && (dst_channels <= 2)) {
   638             cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
   639             src_channels = 2;
   640             cvt->len_ratio /= 3;
   641         }
   642         if ((src_channels == 6) && (dst_channels == 4)) {
   643             cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
   644             src_channels = 4;
   645             cvt->len_ratio /= 2;
   646         }
   647         /* This assumes that 4 channel audio is in the format:
   648            Left {front/back} + Right {front/back}
   649            so converting to L/R stereo works properly.
   650          */
   651         while (((src_channels % 2) == 0) &&
   652                ((src_channels / 2) >= dst_channels)) {
   653             SDL_AudioFilter filter = NULL;
   654 
   655             #if HAVE_SSE3_INTRINSICS
   656             if (SDL_HasSSE3()) {
   657                 filter = SDL_ConvertStereoToMono_SSE3;
   658             }
   659             #endif
   660 
   661             if (!filter) {
   662                 filter = SDL_ConvertStereoToMono;
   663             }
   664 
   665             cvt->filters[cvt->filter_index++] = filter;
   666 
   667             src_channels /= 2;
   668             cvt->len_ratio /= 2;
   669         }
   670         if (src_channels != dst_channels) {
   671             /* Uh oh.. */ ;
   672         }
   673     }
   674 
   675     /* Do rate conversion, if necessary. Updates (cvt). */
   676     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
   677         return -1;              /* shouldn't happen, but just in case... */
   678     }
   679 
   680     /* Move to final data type. */
   681     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
   682         return -1;              /* shouldn't happen, but just in case... */
   683     }
   684 
   685     cvt->needed = (cvt->filter_index != 0);
   686     return (cvt->needed);
   687 }
   688 
   689 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen);
   690 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   691 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   692 
   693 struct SDL_AudioStream
   694 {
   695     SDL_AudioCVT cvt_before_resampling;
   696     SDL_AudioCVT cvt_after_resampling;
   697     SDL_DataQueue *queue;
   698     Uint8 *work_buffer;
   699     int work_buffer_len;
   700     Uint8 *resample_buffer;
   701     int resample_buffer_len;
   702     int src_sample_frame_size;
   703     SDL_AudioFormat src_format;
   704     Uint8 src_channels;
   705     int src_rate;
   706     int dst_sample_frame_size;
   707     SDL_AudioFormat dst_format;
   708     Uint8 dst_channels;
   709     int dst_rate;
   710     double rate_incr;
   711     Uint8 pre_resample_channels;
   712     int packetlen;
   713     void *resampler_state;
   714     SDL_ResampleAudioStreamFunc resampler_func;
   715     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   716     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   717 };
   718 
   719 #ifdef HAVE_LIBSAMPLERATE_H
   720 static int
   721 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   722 {
   723     const int framelen = sizeof(float) * stream->pre_resample_channels;
   724     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   725     SRC_DATA data;
   726     int result;
   727 
   728     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   729     data.input_frames = inbuflen / framelen;
   730     data.input_frames_used = 0;
   731 
   732     data.data_out = outbuf;
   733     data.output_frames = outbuflen / framelen;
   734 
   735     data.end_of_input = 0;
   736     data.src_ratio = stream->rate_incr;
   737 
   738     result = SRC_src_process(state, &data);
   739     if (result != 0) {
   740         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   741         return 0;
   742     }
   743 
   744     /* If this fails, we need to store them off somewhere */
   745     SDL_assert(data.input_frames_used == data.input_frames);
   746 
   747     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   748 }
   749 
   750 static void
   751 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
   752 {
   753     SRC_src_reset((SRC_STATE *)stream->resampler_state);
   754 }
   755 
   756 static void
   757 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
   758 {
   759     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   760     if (state) {
   761         SRC_src_delete(state);
   762     }
   763 
   764     stream->resampler_state = NULL;
   765     stream->resampler_func = NULL;
   766     stream->reset_resampler_func = NULL;
   767     stream->cleanup_resampler_func = NULL;
   768 }
   769 
   770 static SDL_bool
   771 SetupLibSampleRateResampling(SDL_AudioStream *stream)
   772 {
   773     int result = 0;
   774     SRC_STATE *state = NULL;
   775 
   776     if (SRC_available) {
   777         state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
   778         if (!state) {
   779             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
   780         }
   781     }
   782 
   783     if (!state) {
   784         SDL_CleanupAudioStreamResampler_SRC(stream);
   785         return SDL_FALSE;
   786     }
   787 
   788     stream->resampler_state = state;
   789     stream->resampler_func = SDL_ResampleAudioStream_SRC;
   790     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
   791     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
   792 
   793     return SDL_TRUE;
   794 }
   795 #endif /* HAVE_LIBSAMPLERATE_H */
   796 
   797 
   798 typedef struct
   799 {
   800     SDL_bool resampler_seeded;
   801     float resampler_state[8];
   802 } SDL_AudioStreamResamplerState;
   803 
   804 static int
   805 SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   806 {
   807     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   808     const int chans = (int)stream->pre_resample_channels;
   809 
   810     SDL_assert(chans <= SDL_arraysize(state->resampler_state));
   811 
   812     if (!state->resampler_seeded) {
   813         int i;
   814         for (i = 0; i < chans; i++) {
   815             state->resampler_state[i] = inbuf[i];
   816         }
   817         state->resampler_seeded = SDL_TRUE;
   818     }
   819 
   820     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
   821 }
   822 
   823 static void
   824 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
   825 {
   826     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   827     state->resampler_seeded = SDL_FALSE;
   828 }
   829 
   830 static void
   831 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
   832 {
   833     SDL_free(stream->resampler_state);
   834 }
   835 
   836 SDL_AudioStream *
   837 SDL_NewAudioStream(const SDL_AudioFormat src_format,
   838                    const Uint8 src_channels,
   839                    const int src_rate,
   840                    const SDL_AudioFormat dst_format,
   841                    const Uint8 dst_channels,
   842                    const int dst_rate)
   843 {
   844     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
   845     Uint8 pre_resample_channels;
   846     SDL_AudioStream *retval;
   847 
   848     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
   849     if (!retval) {
   850         return NULL;
   851     }
   852 
   853     /* If increasing channels, do it after resampling, since we'd just
   854        do more work to resample duplicate channels. If we're decreasing, do
   855        it first so we resample the interpolated data instead of interpolating
   856        the resampled data (!!! FIXME: decide if that works in practice, though!). */
   857     pre_resample_channels = SDL_min(src_channels, dst_channels);
   858 
   859     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
   860     retval->src_format = src_format;
   861     retval->src_channels = src_channels;
   862     retval->src_rate = src_rate;
   863     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
   864     retval->dst_format = dst_format;
   865     retval->dst_channels = dst_channels;
   866     retval->dst_rate = dst_rate;
   867     retval->pre_resample_channels = pre_resample_channels;
   868     retval->packetlen = packetlen;
   869     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
   870 
   871     /* Not resampling? It's an easy conversion (and maybe not even that!). */
   872     if (src_rate == dst_rate) {
   873         retval->cvt_before_resampling.needed = SDL_FALSE;
   874         retval->cvt_before_resampling.len_mult = 1;
   875         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   876             SDL_FreeAudioStream(retval);
   877             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   878         }
   879     } else {
   880         /* Don't resample at first. Just get us to Float32 format. */
   881         /* !!! FIXME: convert to int32 on devices without hardware float. */
   882         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
   883             SDL_FreeAudioStream(retval);
   884             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   885         }
   886 
   887 #ifdef HAVE_LIBSAMPLERATE_H
   888         SetupLibSampleRateResampling(retval);
   889 #endif
   890 
   891         if (!retval->resampler_func) {
   892             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
   893             if (!retval->resampler_state) {
   894                 SDL_FreeAudioStream(retval);
   895                 SDL_OutOfMemory();
   896                 return NULL;
   897             }
   898             retval->resampler_func = SDL_ResampleAudioStream;
   899             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
   900             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
   901         }
   902 
   903         /* Convert us to the final format after resampling. */
   904         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   905             SDL_FreeAudioStream(retval);
   906             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   907         }
   908     }
   909 
   910     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
   911     if (!retval->queue) {
   912         SDL_FreeAudioStream(retval);
   913         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
   914     }
   915 
   916     return retval;
   917 }
   918 
   919 static Uint8 *
   920 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
   921 {
   922     if (*len < newlen) {
   923         void *ptr = SDL_realloc(*buf, newlen);
   924         if (!ptr) {
   925             SDL_OutOfMemory();
   926             return NULL;
   927         }
   928         *buf = (Uint8 *) ptr;
   929         *len = newlen;
   930     }
   931     return *buf;
   932 }
   933 
   934 int
   935 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
   936 {
   937     int buflen = (int) _buflen;
   938 
   939     if (!stream) {
   940         return SDL_InvalidParamError("stream");
   941     } else if (!buf) {
   942         return SDL_InvalidParamError("buf");
   943     } else if (buflen == 0) {
   944         return 0;  /* nothing to do. */
   945     } else if ((buflen % stream->src_sample_frame_size) != 0) {
   946         return SDL_SetError("Can't add partial sample frames");
   947     }
   948 
   949     if (stream->cvt_before_resampling.needed) {
   950         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   951         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   952         if (workbuf == NULL) {
   953             return -1;  /* probably out of memory. */
   954         }
   955         SDL_memcpy(workbuf, buf, buflen);
   956         stream->cvt_before_resampling.buf = workbuf;
   957         stream->cvt_before_resampling.len = buflen;
   958         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
   959             return -1;   /* uhoh! */
   960         }
   961         buf = workbuf;
   962         buflen = stream->cvt_before_resampling.len_cvt;
   963     }
   964 
   965     if (stream->dst_rate != stream->src_rate) {
   966         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
   967         float *workbuf = (float *) EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   968         if (workbuf == NULL) {
   969             return -1;  /* probably out of memory. */
   970         }
   971         buflen = stream->resampler_func(stream, (float *) buf, buflen, workbuf, workbuflen);
   972         buf = workbuf;
   973     }
   974 
   975     if (stream->cvt_after_resampling.needed) {
   976         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   977         Uint8 *workbuf;
   978 
   979         if (buf == stream->resample_buffer) {
   980             workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   981         } else {
   982             const int inplace = (buf == stream->work_buffer);
   983             workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   984             if (workbuf && !inplace) {
   985                 SDL_memcpy(workbuf, buf, buflen);
   986             }
   987         }
   988 
   989         if (workbuf == NULL) {
   990             return -1;  /* probably out of memory. */
   991         }
   992 
   993         stream->cvt_after_resampling.buf = workbuf;
   994         stream->cvt_after_resampling.len = buflen;
   995         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
   996             return -1;   /* uhoh! */
   997         }
   998         buf = workbuf;
   999         buflen = stream->cvt_after_resampling.len_cvt;
  1000     }
  1001 
  1002     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1003 }
  1004 
  1005 void
  1006 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1007 {
  1008     if (!stream) {
  1009         SDL_InvalidParamError("stream");
  1010     } else {
  1011         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1012         if (stream->reset_resampler_func) {
  1013             stream->reset_resampler_func(stream);
  1014         }
  1015     }
  1016 }
  1017 
  1018 
  1019 /* get converted/resampled data from the stream */
  1020 int
  1021 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1022 {
  1023     if (!stream) {
  1024         return SDL_InvalidParamError("stream");
  1025     } else if (!buf) {
  1026         return SDL_InvalidParamError("buf");
  1027     } else if (len == 0) {
  1028         return 0;  /* nothing to do. */
  1029     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1030         return SDL_SetError("Can't request partial sample frames");
  1031     }
  1032 
  1033     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1034 }
  1035 
  1036 /* number of converted/resampled bytes available */
  1037 int
  1038 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1039 {
  1040     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1041 }
  1042 
  1043 /* dispose of a stream */
  1044 void
  1045 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1046 {
  1047     if (stream) {
  1048         if (stream->cleanup_resampler_func) {
  1049             stream->cleanup_resampler_func(stream);
  1050         }
  1051         SDL_FreeDataQueue(stream->queue);
  1052         SDL_free(stream->work_buffer);
  1053         SDL_free(stream->resample_buffer);
  1054         SDL_free(stream);
  1055     }
  1056 }
  1057 
  1058 /* vi: set ts=4 sw=4 expandtab: */
  1059