src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 23 Jan 2017 00:57:19 -0500
changeset 10832 189266031c6f
parent 10831 fcbb4d7f2344
child 10833 86f6353f1aae
permissions -rw-r--r--
audio: Added SSE3 implementation of SDL_ConvertStereoToMono().
     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 = outbuf;
   249     float *target = (dst + (dest_samples * chans));
   250     double idx = 0.0;
   251     int i;
   252 
   253     SDL_assert((dest_samples * framelen) <= outbuflen);
   254     SDL_assert((inbuflen % framelen) == 0);
   255 
   256     while (dst < target) {
   257         const int pos = ((int)idx) * chans;
   258         const float *src = &inbuf[pos];
   259         SDL_assert(pos <= finalpos);
   260         for (i = 0; i < chans; i++) {
   261             const float val = *(src++);
   262             *(dst++) = (val + last_sample[i]) * 0.5f;
   263             last_sample[i] = val;
   264         }
   265         idx += src_incr;
   266     }
   267 
   268     return (int) ((dst - outbuf) * (int)sizeof(float));
   269 }
   270 
   271 
   272 int
   273 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   274 {
   275     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   276     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   277 
   278     /* Make sure there's data to convert */
   279     if (cvt->buf == NULL) {
   280         return SDL_SetError("No buffer allocated for conversion");
   281     }
   282 
   283     /* Return okay if no conversion is necessary */
   284     cvt->len_cvt = cvt->len;
   285     if (cvt->filters[0] == NULL) {
   286         return 0;
   287     }
   288 
   289     /* Set up the conversion and go! */
   290     cvt->filter_index = 0;
   291     cvt->filters[0] (cvt, cvt->src_format);
   292     return 0;
   293 }
   294 
   295 static void SDLCALL
   296 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   297 {
   298 #if DEBUG_CONVERT
   299     printf("Converting byte order\n");
   300 #endif
   301 
   302     switch (SDL_AUDIO_BITSIZE(format)) {
   303         #define CASESWAP(b) \
   304             case b: { \
   305                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   306                 int i; \
   307                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   308                     *ptr = SDL_Swap##b(*ptr); \
   309                 } \
   310                 break; \
   311             }
   312 
   313         CASESWAP(16);
   314         CASESWAP(32);
   315         CASESWAP(64);
   316 
   317         #undef CASESWAP
   318 
   319         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   320     }
   321 
   322     if (cvt->filters[++cvt->filter_index]) {
   323         /* flip endian flag for data. */
   324         if (format & SDL_AUDIO_MASK_ENDIAN) {
   325             format &= ~SDL_AUDIO_MASK_ENDIAN;
   326         } else {
   327             format |= SDL_AUDIO_MASK_ENDIAN;
   328         }
   329         cvt->filters[cvt->filter_index](cvt, format);
   330     }
   331 }
   332 
   333 
   334 static int
   335 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   336 {
   337     int retval = 0;  /* 0 == no conversion necessary. */
   338 
   339     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   340         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   341         retval = 1;  /* added a converter. */
   342     }
   343 
   344     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   345         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   346         const Uint16 dst_bitsize = 32;
   347         SDL_AudioFilter filter = NULL;
   348 
   349         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   350             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   351             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   352             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   353             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   354             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   355             default: SDL_assert(!"Unexpected audio format!"); break;
   356         }
   357 
   358         if (!filter) {
   359             return SDL_SetError("No conversion available for these formats");
   360         }
   361 
   362         cvt->filters[cvt->filter_index++] = filter;
   363         if (src_bitsize < dst_bitsize) {
   364             const int mult = (dst_bitsize / src_bitsize);
   365             cvt->len_mult *= mult;
   366             cvt->len_ratio *= mult;
   367         } else if (src_bitsize > dst_bitsize) {
   368             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   369         }
   370 
   371         retval = 1;  /* added a converter. */
   372     }
   373 
   374     return retval;
   375 }
   376 
   377 static int
   378 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   379 {
   380     int retval = 0;  /* 0 == no conversion necessary. */
   381 
   382     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   383         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   384         const Uint16 src_bitsize = 32;
   385         SDL_AudioFilter filter = NULL;
   386         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   387             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   388             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   389             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   390             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   391             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   392             default: SDL_assert(!"Unexpected audio format!"); break;
   393         }
   394 
   395         if (!filter) {
   396             return SDL_SetError("No conversion available for these formats");
   397         }
   398 
   399         cvt->filters[cvt->filter_index++] = filter;
   400         if (src_bitsize < dst_bitsize) {
   401             const int mult = (dst_bitsize / src_bitsize);
   402             cvt->len_mult *= mult;
   403             cvt->len_ratio *= mult;
   404         } else if (src_bitsize > dst_bitsize) {
   405             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   406         }
   407         retval = 1;  /* added a converter. */
   408     }
   409 
   410     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   411         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   412         retval = 1;  /* added a converter. */
   413     }
   414 
   415     return retval;
   416 }
   417 
   418 static void
   419 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   420 {
   421     const float *src = (const float *) cvt->buf;
   422     const int srclen = cvt->len_cvt;
   423     float *dst = (float *) (cvt->buf + srclen);
   424     const int dstlen = (cvt->len * cvt->len_mult) - srclen;
   425     float state[8];
   426 
   427     SDL_assert(format == AUDIO_F32SYS);
   428 
   429     SDL_memcpy(state, src, chans*sizeof(*src));
   430 
   431     cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   432 
   433     SDL_memcpy(cvt->buf, dst, cvt->len_cvt);
   434     if (cvt->filters[++cvt->filter_index]) {
   435         cvt->filters[cvt->filter_index](cvt, format);
   436     }
   437 }
   438 
   439 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   440    !!! FIXME:  store channel info, so we have to have function entry
   441    !!! FIXME:  points for each supported channel count and multiple
   442    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   443 #define RESAMPLER_FUNCS(chans) \
   444     static void SDLCALL \
   445     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   446         SDL_ResampleCVT(cvt, chans, format); \
   447     }
   448 RESAMPLER_FUNCS(1)
   449 RESAMPLER_FUNCS(2)
   450 RESAMPLER_FUNCS(4)
   451 RESAMPLER_FUNCS(6)
   452 RESAMPLER_FUNCS(8)
   453 #undef RESAMPLER_FUNCS
   454 
   455 static SDL_AudioFilter
   456 ChooseCVTResampler(const int dst_channels)
   457 {
   458     switch (dst_channels) {
   459         case 1: return SDL_ResampleCVT_c1;
   460         case 2: return SDL_ResampleCVT_c2;
   461         case 4: return SDL_ResampleCVT_c4;
   462         case 6: return SDL_ResampleCVT_c6;
   463         case 8: return SDL_ResampleCVT_c8;
   464         default: break;
   465     }
   466 
   467     return NULL;
   468 }
   469 
   470 static int
   471 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   472                           const int src_rate, const int dst_rate)
   473 {
   474     SDL_AudioFilter filter;
   475 
   476     if (src_rate == dst_rate) {
   477         return 0;  /* no conversion necessary. */
   478     }
   479 
   480     filter = ChooseCVTResampler(dst_channels);
   481     if (filter == NULL) {
   482         return SDL_SetError("No conversion available for these rates");
   483     }
   484 
   485     /* Update (cvt) with filter details... */
   486     cvt->filters[cvt->filter_index++] = filter;
   487     if (src_rate < dst_rate) {
   488         const double mult = ((double) dst_rate) / ((double) src_rate);
   489         cvt->len_mult *= (int) SDL_ceil(mult);
   490         cvt->len_ratio *= mult;
   491     } else {
   492         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   493     }
   494 
   495     /* the buffer is big enough to hold the destination now, but
   496        we need it large enough to hold a separate scratch buffer. */
   497     cvt->len_mult *= 2;
   498 
   499     return 1;               /* added a converter. */
   500 }
   501 
   502 
   503 /* Creates a set of audio filters to convert from one format to another.
   504    Returns -1 if the format conversion is not supported, 0 if there's
   505    no conversion needed, or 1 if the audio filter is set up.
   506 */
   507 
   508 int
   509 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   510                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   511                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   512 {
   513     /* Sanity check target pointer */
   514     if (cvt == NULL) {
   515         return SDL_InvalidParamError("cvt");
   516     }
   517 
   518     /* Make sure we zero out the audio conversion before error checking */
   519     SDL_zerop(cvt);
   520 
   521     /* there are no unsigned types over 16 bits, so catch this up front. */
   522     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
   523         return SDL_SetError("Invalid source format");
   524     }
   525     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
   526         return SDL_SetError("Invalid destination format");
   527     }
   528 
   529     /* prevent possible divisions by zero, etc. */
   530     if ((src_channels == 0) || (dst_channels == 0)) {
   531         return SDL_SetError("Source or destination channels is zero");
   532     }
   533     if ((src_rate == 0) || (dst_rate == 0)) {
   534         return SDL_SetError("Source or destination rate is zero");
   535     }
   536 #if DEBUG_CONVERT
   537     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   538            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   539 #endif
   540 
   541     /* Start off with no conversion necessary */
   542     cvt->src_format = src_fmt;
   543     cvt->dst_format = dst_fmt;
   544     cvt->needed = 0;
   545     cvt->filter_index = 0;
   546     cvt->filters[0] = NULL;
   547     cvt->len_mult = 1;
   548     cvt->len_ratio = 1.0;
   549     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   550 
   551     /* Type conversion goes like this now:
   552         - byteswap to CPU native format first if necessary.
   553         - convert to native Float32 if necessary.
   554         - resample and change channel count if necessary.
   555         - convert back to native format.
   556         - byteswap back to foreign format if necessary.
   557 
   558        The expectation is we can process data faster in float32
   559        (possibly with SIMD), and making several passes over the same
   560        buffer is likely to be CPU cache-friendly, avoiding the
   561        biggest performance hit in modern times. Previously we had
   562        (script-generated) custom converters for every data type and
   563        it was a bloat on SDL compile times and final library size. */
   564 
   565     /* see if we can skip float conversion entirely. */
   566     if (src_rate == dst_rate && src_channels == dst_channels) {
   567         if (src_fmt == dst_fmt) {
   568             return 0;
   569         }
   570 
   571         /* just a byteswap needed? */
   572         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   573             cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   574             cvt->needed = 1;
   575             return 1;
   576         }
   577     }
   578 
   579     /* Convert data types, if necessary. Updates (cvt). */
   580     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   581         return -1;              /* shouldn't happen, but just in case... */
   582     }
   583 
   584     /* Channel conversion */
   585     if (src_channels != dst_channels) {
   586         if ((src_channels == 1) && (dst_channels > 1)) {
   587             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   588             cvt->len_mult *= 2;
   589             src_channels = 2;
   590             cvt->len_ratio *= 2;
   591         }
   592         if ((src_channels == 2) && (dst_channels == 6)) {
   593             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
   594             src_channels = 6;
   595             cvt->len_mult *= 3;
   596             cvt->len_ratio *= 3;
   597         }
   598         if ((src_channels == 2) && (dst_channels == 4)) {
   599             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
   600             src_channels = 4;
   601             cvt->len_mult *= 2;
   602             cvt->len_ratio *= 2;
   603         }
   604         while ((src_channels * 2) <= dst_channels) {
   605             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   606             cvt->len_mult *= 2;
   607             src_channels *= 2;
   608             cvt->len_ratio *= 2;
   609         }
   610         if ((src_channels == 6) && (dst_channels <= 2)) {
   611             cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
   612             src_channels = 2;
   613             cvt->len_ratio /= 3;
   614         }
   615         if ((src_channels == 6) && (dst_channels == 4)) {
   616             cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
   617             src_channels = 4;
   618             cvt->len_ratio /= 2;
   619         }
   620         /* This assumes that 4 channel audio is in the format:
   621            Left {front/back} + Right {front/back}
   622            so converting to L/R stereo works properly.
   623          */
   624         while (((src_channels % 2) == 0) &&
   625                ((src_channels / 2) >= dst_channels)) {
   626             SDL_AudioFilter filter = NULL;
   627 
   628             #if HAVE_SSE3_INTRINSICS
   629             if (SDL_HasSSE3()) {
   630                 filter = SDL_ConvertStereoToMono_SSE3;
   631             }
   632             #endif
   633 
   634             if (!filter) {
   635                 filter = SDL_ConvertStereoToMono;
   636             }
   637 
   638             cvt->filters[cvt->filter_index++] = filter;
   639 
   640             src_channels /= 2;
   641             cvt->len_ratio /= 2;
   642         }
   643         if (src_channels != dst_channels) {
   644             /* Uh oh.. */ ;
   645         }
   646     }
   647 
   648     /* Do rate conversion, if necessary. Updates (cvt). */
   649     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
   650         return -1;              /* shouldn't happen, but just in case... */
   651     }
   652 
   653     /* Move to final data type. */
   654     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
   655         return -1;              /* shouldn't happen, but just in case... */
   656     }
   657 
   658     cvt->needed = (cvt->filter_index != 0);
   659     return (cvt->needed);
   660 }
   661 
   662 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen);
   663 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   664 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   665 
   666 struct SDL_AudioStream
   667 {
   668     SDL_AudioCVT cvt_before_resampling;
   669     SDL_AudioCVT cvt_after_resampling;
   670     SDL_DataQueue *queue;
   671     Uint8 *work_buffer;
   672     int work_buffer_len;
   673     Uint8 *resample_buffer;
   674     int resample_buffer_len;
   675     int src_sample_frame_size;
   676     SDL_AudioFormat src_format;
   677     Uint8 src_channels;
   678     int src_rate;
   679     int dst_sample_frame_size;
   680     SDL_AudioFormat dst_format;
   681     Uint8 dst_channels;
   682     int dst_rate;
   683     double rate_incr;
   684     Uint8 pre_resample_channels;
   685     int packetlen;
   686     void *resampler_state;
   687     SDL_ResampleAudioStreamFunc resampler_func;
   688     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   689     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   690 };
   691 
   692 #ifdef HAVE_LIBSAMPLERATE_H
   693 static int
   694 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   695 {
   696     const int framelen = sizeof(float) * stream->pre_resample_channels;
   697     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   698     SRC_DATA data;
   699     int result;
   700 
   701     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   702     data.input_frames = inbuflen / framelen;
   703     data.input_frames_used = 0;
   704 
   705     data.data_out = outbuf;
   706     data.output_frames = outbuflen / framelen;
   707 
   708     data.end_of_input = 0;
   709     data.src_ratio = stream->rate_incr;
   710 
   711     result = SRC_src_process(state, &data);
   712     if (result != 0) {
   713         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   714         return 0;
   715     }
   716 
   717     /* If this fails, we need to store them off somewhere */
   718     SDL_assert(data.input_frames_used == data.input_frames);
   719 
   720     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   721 }
   722 
   723 static void
   724 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
   725 {
   726     SRC_src_reset((SRC_STATE *)stream->resampler_state);
   727 }
   728 
   729 static void
   730 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
   731 {
   732     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   733     if (state) {
   734         SRC_src_delete(state);
   735     }
   736 
   737     stream->resampler_state = NULL;
   738     stream->resampler_func = NULL;
   739     stream->reset_resampler_func = NULL;
   740     stream->cleanup_resampler_func = NULL;
   741 }
   742 
   743 static SDL_bool
   744 SetupLibSampleRateResampling(SDL_AudioStream *stream)
   745 {
   746     int result = 0;
   747     SRC_STATE *state = NULL;
   748 
   749     if (SRC_available) {
   750         state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
   751         if (!state) {
   752             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
   753         }
   754     }
   755 
   756     if (!state) {
   757         SDL_CleanupAudioStreamResampler_SRC(stream);
   758         return SDL_FALSE;
   759     }
   760 
   761     stream->resampler_state = state;
   762     stream->resampler_func = SDL_ResampleAudioStream_SRC;
   763     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
   764     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
   765 
   766     return SDL_TRUE;
   767 }
   768 #endif /* HAVE_LIBSAMPLERATE_H */
   769 
   770 
   771 typedef struct
   772 {
   773     SDL_bool resampler_seeded;
   774     float resampler_state[8];
   775 } SDL_AudioStreamResamplerState;
   776 
   777 static int
   778 SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   779 {
   780     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   781     const int chans = (int)stream->pre_resample_channels;
   782 
   783     SDL_assert(chans <= SDL_arraysize(state->resampler_state));
   784 
   785     if (!state->resampler_seeded) {
   786         int i;
   787         for (i = 0; i < chans; i++) {
   788             state->resampler_state[i] = inbuf[i];
   789         }
   790         state->resampler_seeded = SDL_TRUE;
   791     }
   792 
   793     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
   794 }
   795 
   796 static void
   797 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
   798 {
   799     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   800     state->resampler_seeded = SDL_FALSE;
   801 }
   802 
   803 static void
   804 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
   805 {
   806     SDL_free(stream->resampler_state);
   807 }
   808 
   809 SDL_AudioStream *
   810 SDL_NewAudioStream(const SDL_AudioFormat src_format,
   811                    const Uint8 src_channels,
   812                    const int src_rate,
   813                    const SDL_AudioFormat dst_format,
   814                    const Uint8 dst_channels,
   815                    const int dst_rate)
   816 {
   817     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
   818     Uint8 pre_resample_channels;
   819     SDL_AudioStream *retval;
   820 
   821     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
   822     if (!retval) {
   823         return NULL;
   824     }
   825 
   826     /* If increasing channels, do it after resampling, since we'd just
   827        do more work to resample duplicate channels. If we're decreasing, do
   828        it first so we resample the interpolated data instead of interpolating
   829        the resampled data (!!! FIXME: decide if that works in practice, though!). */
   830     pre_resample_channels = SDL_min(src_channels, dst_channels);
   831 
   832     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
   833     retval->src_format = src_format;
   834     retval->src_channels = src_channels;
   835     retval->src_rate = src_rate;
   836     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
   837     retval->dst_format = dst_format;
   838     retval->dst_channels = dst_channels;
   839     retval->dst_rate = dst_rate;
   840     retval->pre_resample_channels = pre_resample_channels;
   841     retval->packetlen = packetlen;
   842     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
   843 
   844     /* Not resampling? It's an easy conversion (and maybe not even that!). */
   845     if (src_rate == dst_rate) {
   846         retval->cvt_before_resampling.needed = SDL_FALSE;
   847         retval->cvt_before_resampling.len_mult = 1;
   848         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   849             SDL_FreeAudioStream(retval);
   850             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   851         }
   852     } else {
   853         /* Don't resample at first. Just get us to Float32 format. */
   854         /* !!! FIXME: convert to int32 on devices without hardware float. */
   855         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
   856             SDL_FreeAudioStream(retval);
   857             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   858         }
   859 
   860 #ifdef HAVE_LIBSAMPLERATE_H
   861         SetupLibSampleRateResampling(retval);
   862 #endif
   863 
   864         if (!retval->resampler_func) {
   865             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
   866             if (!retval->resampler_state) {
   867                 SDL_FreeAudioStream(retval);
   868                 SDL_OutOfMemory();
   869                 return NULL;
   870             }
   871             retval->resampler_func = SDL_ResampleAudioStream;
   872             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
   873             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
   874         }
   875 
   876         /* Convert us to the final format after resampling. */
   877         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   878             SDL_FreeAudioStream(retval);
   879             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   880         }
   881     }
   882 
   883     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
   884     if (!retval->queue) {
   885         SDL_FreeAudioStream(retval);
   886         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
   887     }
   888 
   889     return retval;
   890 }
   891 
   892 static Uint8 *
   893 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
   894 {
   895     if (*len < newlen) {
   896         void *ptr = SDL_realloc(*buf, newlen);
   897         if (!ptr) {
   898             SDL_OutOfMemory();
   899             return NULL;
   900         }
   901         *buf = (Uint8 *) ptr;
   902         *len = newlen;
   903     }
   904     return *buf;
   905 }
   906 
   907 int
   908 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
   909 {
   910     int buflen = (int) _buflen;
   911 
   912     if (!stream) {
   913         return SDL_InvalidParamError("stream");
   914     } else if (!buf) {
   915         return SDL_InvalidParamError("buf");
   916     } else if (buflen == 0) {
   917         return 0;  /* nothing to do. */
   918     } else if ((buflen % stream->src_sample_frame_size) != 0) {
   919         return SDL_SetError("Can't add partial sample frames");
   920     }
   921 
   922     if (stream->cvt_before_resampling.needed) {
   923         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   924         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   925         if (workbuf == NULL) {
   926             return -1;  /* probably out of memory. */
   927         }
   928         SDL_memcpy(workbuf, buf, buflen);
   929         stream->cvt_before_resampling.buf = workbuf;
   930         stream->cvt_before_resampling.len = buflen;
   931         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
   932             return -1;   /* uhoh! */
   933         }
   934         buf = workbuf;
   935         buflen = stream->cvt_before_resampling.len_cvt;
   936     }
   937 
   938     if (stream->dst_rate != stream->src_rate) {
   939         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
   940         float *workbuf = (float *) EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   941         if (workbuf == NULL) {
   942             return -1;  /* probably out of memory. */
   943         }
   944         buflen = stream->resampler_func(stream, (float *) buf, buflen, workbuf, workbuflen);
   945         buf = workbuf;
   946     }
   947 
   948     if (stream->cvt_after_resampling.needed) {
   949         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   950         Uint8 *workbuf;
   951 
   952         if (buf == stream->resample_buffer) {
   953             workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   954         } else {
   955             const int inplace = (buf == stream->work_buffer);
   956             workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   957             if (workbuf && !inplace) {
   958                 SDL_memcpy(workbuf, buf, buflen);
   959             }
   960         }
   961 
   962         if (workbuf == NULL) {
   963             return -1;  /* probably out of memory. */
   964         }
   965 
   966         stream->cvt_after_resampling.buf = workbuf;
   967         stream->cvt_after_resampling.len = buflen;
   968         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
   969             return -1;   /* uhoh! */
   970         }
   971         buf = workbuf;
   972         buflen = stream->cvt_after_resampling.len_cvt;
   973     }
   974 
   975     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
   976 }
   977 
   978 void
   979 SDL_AudioStreamClear(SDL_AudioStream *stream)
   980 {
   981     if (!stream) {
   982         SDL_InvalidParamError("stream");
   983     } else {
   984         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
   985         if (stream->reset_resampler_func) {
   986             stream->reset_resampler_func(stream);
   987         }
   988     }
   989 }
   990 
   991 
   992 /* get converted/resampled data from the stream */
   993 int
   994 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
   995 {
   996     if (!stream) {
   997         return SDL_InvalidParamError("stream");
   998     } else if (!buf) {
   999         return SDL_InvalidParamError("buf");
  1000     } else if (len == 0) {
  1001         return 0;  /* nothing to do. */
  1002     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1003         return SDL_SetError("Can't request partial sample frames");
  1004     }
  1005 
  1006     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1007 }
  1008 
  1009 /* number of converted/resampled bytes available */
  1010 int
  1011 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1012 {
  1013     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1014 }
  1015 
  1016 /* dispose of a stream */
  1017 void
  1018 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1019 {
  1020     if (stream) {
  1021         if (stream->cleanup_resampler_func) {
  1022             stream->cleanup_resampler_func(stream);
  1023         }
  1024         SDL_FreeDataQueue(stream->queue);
  1025         SDL_free(stream->work_buffer);
  1026         SDL_free(stream->resample_buffer);
  1027         SDL_free(stream);
  1028     }
  1029 }
  1030 
  1031 /* vi: set ts=4 sw=4 expandtab: */
  1032