src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Jan 2017 16:31:57 -0500
changeset 10804 1502bb751ca4
parent 10799 234f71894a52
child 10805 30a00d960dc9
permissions -rw-r--r--
audio: Don't ever use libsamplerate in the SDL_AudioCVT codepath.

It causes audio pops if you're converting in chunks (and needs to
allocate/initialize/free on each convert). We'll either adjust this interface
when we break ABI for 2.1 to make this usable, or publish the SDL_AudioStream
API for those that want a streaming solution.

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