src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 22 Sep 2017 07:42:24 -0400
changeset 11517 beb96c015b30
parent 11508 a8382e3d0b54
child 11519 535b0c8ba4ce
permissions -rw-r--r--
audio: Stream resampling now saves some samples from previous run for padding.

Previously, the padding was silence, which was a problem when streaming since
you would sample a little bit of this silence between each buffer.

We still need a means to get padding data for the right hand side, but this
patch makes the resampler output more correct.
     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.h"
    26 #include "SDL_audio.h"
    27 #include "SDL_audio_c.h"
    28 
    29 #include "SDL_loadso.h"
    30 #include "SDL_assert.h"
    31 #include "../SDL_dataqueue.h"
    32 #include "SDL_cpuinfo.h"
    33 
    34 #ifdef __SSE3__
    35 #define HAVE_SSE3_INTRINSICS 1
    36 #endif
    37 
    38 #if HAVE_SSE3_INTRINSICS
    39 /* Convert from stereo to mono. Average left and right. */
    40 static void SDLCALL
    41 SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    42 {
    43     float *dst = (float *) cvt->buf;
    44     const float *src = dst;
    45     int i = cvt->len_cvt / 8;
    46 
    47     LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
    48     SDL_assert(format == AUDIO_F32SYS);
    49 
    50     /* We can only do this if dst is aligned to 16 bytes; since src is the
    51        same pointer and it moves by 2, it can't be forcibly aligned. */
    52     if ((((size_t) dst) & 15) == 0) {
    53         /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
    54         const __m128 divby2 = _mm_set1_ps(0.5f);
    55         while (i >= 4) {   /* 4 * float32 */
    56             _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
    57             i -= 4; src += 8; dst += 4;
    58         }
    59     }
    60 
    61     /* Finish off any leftovers with scalar operations. */
    62     while (i) {
    63         *dst = (src[0] + src[1]) * 0.5f;
    64         dst++; i--; src += 2;
    65     }
    66 
    67     cvt->len_cvt /= 2;
    68     if (cvt->filters[++cvt->filter_index]) {
    69         cvt->filters[cvt->filter_index] (cvt, format);
    70     }
    71 }
    72 #endif
    73 
    74 /* Convert from stereo to mono. Average left and right. */
    75 static void SDLCALL
    76 SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    77 {
    78     float *dst = (float *) cvt->buf;
    79     const float *src = dst;
    80     int i;
    81 
    82     LOG_DEBUG_CONVERT("stereo", "mono");
    83     SDL_assert(format == AUDIO_F32SYS);
    84 
    85     for (i = cvt->len_cvt / 8; i; --i, src += 2) {
    86         *(dst++) = (src[0] + src[1]) * 0.5f;
    87     }
    88 
    89     cvt->len_cvt /= 2;
    90     if (cvt->filters[++cvt->filter_index]) {
    91         cvt->filters[cvt->filter_index] (cvt, format);
    92     }
    93 }
    94 
    95 
    96 /* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
    97 static void SDLCALL
    98 SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    99 {
   100     float *dst = (float *) cvt->buf;
   101     const float *src = dst;
   102     int i;
   103 
   104     LOG_DEBUG_CONVERT("5.1", "stereo");
   105     SDL_assert(format == AUDIO_F32SYS);
   106 
   107     /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
   108     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
   109         const float front_center_distributed = src[2] * 0.5f;
   110         dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f;  /* left */
   111         dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f;  /* right */
   112     }
   113 
   114     cvt->len_cvt /= 3;
   115     if (cvt->filters[++cvt->filter_index]) {
   116         cvt->filters[cvt->filter_index] (cvt, format);
   117     }
   118 }
   119 
   120 
   121 /* Convert from quad to stereo. Average left and right. */
   122 static void SDLCALL
   123 SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   124 {
   125     float *dst = (float *) cvt->buf;
   126     const float *src = dst;
   127     int i;
   128 
   129     LOG_DEBUG_CONVERT("quad", "stereo");
   130     SDL_assert(format == AUDIO_F32SYS);
   131 
   132     for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
   133         dst[0] = (src[0] + src[2]) * 0.5f; /* left */
   134         dst[1] = (src[1] + src[3]) * 0.5f; /* right */
   135     }
   136 
   137     cvt->len_cvt /= 3;
   138     if (cvt->filters[++cvt->filter_index]) {
   139         cvt->filters[cvt->filter_index] (cvt, format);
   140     }
   141 }
   142 
   143 
   144 /* Convert from 7.1 to 5.1. Distribute sides across front and back. */
   145 static void SDLCALL
   146 SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   147 {
   148     float *dst = (float *) cvt->buf;
   149     const float *src = dst;
   150     int i;
   151 
   152     LOG_DEBUG_CONVERT("7.1", "5.1");
   153     SDL_assert(format == AUDIO_F32SYS);
   154 
   155     for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
   156         const float surround_left_distributed = src[6] * 0.5f;
   157         const float surround_right_distributed = src[7] * 0.5f;
   158         dst[0] = (src[0] + surround_left_distributed) / 1.5f;  /* FL */
   159         dst[1] = (src[1] + surround_right_distributed) / 1.5f;  /* FR */
   160         dst[2] = src[2] / 1.5f; /* CC */
   161         dst[3] = src[3] / 1.5f; /* LFE */
   162         dst[4] = (src[4] + surround_left_distributed) / 1.5f;  /* BL */
   163         dst[5] = (src[5] + surround_right_distributed) / 1.5f;  /* BR */
   164     }
   165 
   166     cvt->len_cvt /= 8;
   167     cvt->len_cvt *= 6;
   168     if (cvt->filters[++cvt->filter_index]) {
   169         cvt->filters[cvt->filter_index] (cvt, format);
   170     }
   171 }
   172 
   173 
   174 /* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
   175 static void SDLCALL
   176 SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   177 {
   178     float *dst = (float *) cvt->buf;
   179     const float *src = dst;
   180     int i;
   181 
   182     LOG_DEBUG_CONVERT("5.1", "quad");
   183     SDL_assert(format == AUDIO_F32SYS);
   184 
   185     /* SDL's 4.0 layout: FL+FR+BL+BR */
   186     /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
   187     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
   188         const float front_center_distributed = src[2] * 0.5f;
   189         dst[0] = (src[0] + front_center_distributed) / 1.5f;  /* FL */
   190         dst[1] = (src[1] + front_center_distributed) / 1.5f;  /* FR */
   191         dst[2] = src[4] / 1.5f;  /* BL */
   192         dst[3] = src[5] / 1.5f;  /* BR */
   193     }
   194 
   195     cvt->len_cvt /= 6;
   196     cvt->len_cvt *= 4;
   197     if (cvt->filters[++cvt->filter_index]) {
   198         cvt->filters[cvt->filter_index] (cvt, format);
   199     }
   200 }
   201 
   202 
   203 /* Upmix mono to stereo (by duplication) */
   204 static void SDLCALL
   205 SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   206 {
   207     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   208     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   209     int i;
   210 
   211     LOG_DEBUG_CONVERT("mono", "stereo");
   212     SDL_assert(format == AUDIO_F32SYS);
   213 
   214     for (i = cvt->len_cvt / sizeof (float); i; --i) {
   215         src--;
   216         dst -= 2;
   217         dst[0] = dst[1] = *src;
   218     }
   219 
   220     cvt->len_cvt *= 2;
   221     if (cvt->filters[++cvt->filter_index]) {
   222         cvt->filters[cvt->filter_index] (cvt, format);
   223     }
   224 }
   225 
   226 
   227 /* Upmix stereo to a pseudo-5.1 stream */
   228 static void SDLCALL
   229 SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   230 {
   231     int i;
   232     float lf, rf, ce;
   233     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   234     float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
   235 
   236     LOG_DEBUG_CONVERT("stereo", "5.1");
   237     SDL_assert(format == AUDIO_F32SYS);
   238 
   239     for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
   240         dst -= 6;
   241         src -= 2;
   242         lf = src[0];
   243         rf = src[1];
   244         ce = (lf + rf) * 0.5f;
   245         /* !!! FIXME: FL and FR may clip */
   246         dst[0] = lf + (lf - ce);  /* FL */
   247         dst[1] = rf + (rf - ce);  /* FR */
   248         dst[2] = ce;  /* FC */
   249         dst[3] = 0;   /* LFE (only meant for special LFE effects) */
   250         dst[4] = lf;  /* BL */
   251         dst[5] = rf;  /* BR */
   252     }
   253 
   254     cvt->len_cvt *= 3;
   255     if (cvt->filters[++cvt->filter_index]) {
   256         cvt->filters[cvt->filter_index] (cvt, format);
   257     }
   258 }
   259 
   260 
   261 /* Upmix quad to a pseudo-5.1 stream */
   262 static void SDLCALL
   263 SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   264 {
   265     int i;
   266     float lf, rf, lb, rb, ce;
   267     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   268     float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
   269 
   270     LOG_DEBUG_CONVERT("quad", "5.1");
   271     SDL_assert(format == AUDIO_F32SYS);
   272     SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
   273 
   274     for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
   275         dst -= 6;
   276         src -= 4;
   277         lf = src[0];
   278         rf = src[1];
   279         lb = src[2];
   280         rb = src[3];
   281         ce = (lf + rf) * 0.5f;
   282         /* !!! FIXME: FL and FR may clip */
   283         dst[0] = lf + (lf - ce);  /* FL */
   284         dst[1] = rf + (rf - ce);  /* FR */
   285         dst[2] = ce;  /* FC */
   286         dst[3] = 0;   /* LFE (only meant for special LFE effects) */
   287         dst[4] = lb;  /* BL */
   288         dst[5] = rb;  /* BR */
   289     }
   290 
   291     cvt->len_cvt = cvt->len_cvt * 3 / 2;
   292     if (cvt->filters[++cvt->filter_index]) {
   293         cvt->filters[cvt->filter_index] (cvt, format);
   294     }
   295 }
   296 
   297 
   298 /* Upmix stereo to a pseudo-4.0 stream (by duplication) */
   299 static void SDLCALL
   300 SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   301 {
   302     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   303     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   304     float lf, rf;
   305     int i;
   306 
   307     LOG_DEBUG_CONVERT("stereo", "quad");
   308     SDL_assert(format == AUDIO_F32SYS);
   309 
   310     for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
   311         dst -= 4;
   312         src -= 2;
   313         lf = src[0];
   314         rf = src[1];
   315         dst[0] = lf;  /* FL */
   316         dst[1] = rf;  /* FR */
   317         dst[2] = lf;  /* BL */
   318         dst[3] = rf;  /* BR */
   319     }
   320 
   321     cvt->len_cvt *= 2;
   322     if (cvt->filters[++cvt->filter_index]) {
   323         cvt->filters[cvt->filter_index] (cvt, format);
   324     }
   325 }
   326 
   327 
   328 /* Upmix 5.1 to 7.1 */
   329 static void SDLCALL
   330 SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   331 {
   332     float lf, rf, lb, rb, ls, rs;
   333     int i;
   334     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   335     float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
   336 
   337     LOG_DEBUG_CONVERT("5.1", "7.1");
   338     SDL_assert(format == AUDIO_F32SYS);
   339     SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
   340 
   341     for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
   342         dst -= 8;
   343         src -= 6;
   344         lf = src[0];
   345         rf = src[1];
   346         lb = src[4];
   347         rb = src[5];
   348         ls = (lf + lb) * 0.5f;
   349         rs = (rf + rb) * 0.5f;
   350         /* !!! FIXME: these four may clip */
   351         lf += lf - ls;
   352         rf += rf - ls;
   353         lb += lb - ls;
   354         rb += rb - ls;
   355         dst[3] = src[3];  /* LFE */
   356         dst[2] = src[2];  /* FC */
   357         dst[7] = rs; /* SR */
   358         dst[6] = ls; /* SL */
   359         dst[5] = rb;  /* BR */
   360         dst[4] = lb;  /* BL */
   361         dst[1] = rf;  /* FR */
   362         dst[0] = lf;  /* FL */
   363     }
   364 
   365     cvt->len_cvt = cvt->len_cvt * 4 / 3;
   366 
   367     if (cvt->filters[++cvt->filter_index]) {
   368         cvt->filters[cvt->filter_index] (cvt, format);
   369     }
   370 }
   371 
   372 /* SDL's resampler uses a "bandlimited interpolation" algorithm:
   373      https://ccrma.stanford.edu/~jos/resample/ */
   374 
   375 #define RESAMPLER_ZERO_CROSSINGS 5
   376 #define RESAMPLER_BITS_PER_SAMPLE 16
   377 #define RESAMPLER_SAMPLES_PER_ZERO_CROSSING  (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
   378 #define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
   379 
   380 /* This is a "modified" bessel function, so you can't use POSIX j0() */
   381 static double
   382 bessel(const double x)
   383 {
   384     const double xdiv2 = x / 2.0;
   385     double i0 = 1.0f;
   386     double f = 1.0f;
   387     int i = 1;
   388 
   389     while (SDL_TRUE) {
   390         const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
   391         if (diff < 1.0e-21f) {
   392             break;
   393         }
   394         i0 += diff;
   395         i++;
   396         f *= (double) i;
   397     }
   398 
   399     return i0;
   400 }
   401 
   402 /* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
   403 static void
   404 kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
   405 {
   406     const int lenm1 = tablelen - 1;
   407     const int lenm1div2 = lenm1 / 2;
   408     int i;
   409 
   410     table[0] = 1.0f;
   411     for (i = 1; i < tablelen; i++) {
   412         const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
   413         table[tablelen - i] = (float) kaiser;
   414     }
   415 
   416     for (i = 1; i < tablelen; i++) {
   417         const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
   418         table[i] *= SDL_sinf(x) / x;
   419         diffs[i - 1] = table[i] - table[i - 1];
   420     }
   421     diffs[lenm1] = 0.0f;
   422 }
   423 
   424 
   425 static SDL_SpinLock ResampleFilterSpinlock = 0;
   426 static float *ResamplerFilter = NULL;
   427 static float *ResamplerFilterDifference = NULL;
   428 
   429 int
   430 SDL_PrepareResampleFilter(void)
   431 {
   432     SDL_AtomicLock(&ResampleFilterSpinlock);
   433     if (!ResamplerFilter) {
   434         /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
   435         const double dB = 80.0;
   436         const double beta = 0.1102 * (dB - 8.7);
   437         const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
   438 
   439         ResamplerFilter = (float *) SDL_malloc(alloclen);
   440         if (!ResamplerFilter) {
   441             SDL_AtomicUnlock(&ResampleFilterSpinlock);
   442             return SDL_OutOfMemory();
   443         }
   444 
   445         ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
   446         if (!ResamplerFilterDifference) {
   447             SDL_free(ResamplerFilter);
   448             ResamplerFilter = NULL;
   449             SDL_AtomicUnlock(&ResampleFilterSpinlock);
   450             return SDL_OutOfMemory();
   451         }
   452         kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
   453     }
   454     SDL_AtomicUnlock(&ResampleFilterSpinlock);
   455     return 0;
   456 }
   457 
   458 void
   459 SDL_FreeResampleFilter(void)
   460 {
   461     SDL_free(ResamplerFilter);
   462     SDL_free(ResamplerFilterDifference);
   463     ResamplerFilter = NULL;
   464     ResamplerFilterDifference = NULL;
   465 }
   466 
   467 static int
   468 ResamplerPadding(const int inrate, const int outrate)
   469 {
   470     return (inrate > outrate) ? (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
   471 }
   472 
   473 /* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
   474 static int
   475 SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
   476                         float *lpadding, float *rpadding, const float *inbuf,
   477                         const int inbuflen, float *outbuf, const int outbuflen)
   478 {
   479     const float outtimeincr = 1.0f / ((float) outrate);
   480     const float ratio = ((float) outrate) / ((float) inrate);
   481     const int paddinglen = ResamplerPadding(inrate, outrate);
   482     const int framelen = chans * (int)sizeof (float);
   483     const int inframes = inbuflen / framelen;
   484     const int wantedoutframes = (int) ((inbuflen / framelen) * ratio);  /* outbuflen isn't total to write, it's total available. */
   485     const int maxoutframes = outbuflen / framelen;
   486     const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes;
   487     float *dst = outbuf;
   488     float outtime = 0.0f;
   489     int i, j, chan;
   490 
   491     for (i = 0; i < outframes; i++) {
   492         const int srcindex = (int) (outtime * inrate);
   493         const float finrate = (float) inrate;
   494         const float intime = ((float) srcindex) / finrate;
   495         const float innexttime = ((float) (srcindex + 1)) / finrate;
   496 
   497         const float interpolation1 = 1.0f - (innexttime - outtime) / (innexttime - intime);
   498         const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
   499         const float interpolation2 = 1.0f - interpolation1;
   500         const int filterindex2 = interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
   501 
   502         for (chan = 0; chan < chans; chan++) {
   503             float outsample = 0.0f;
   504 
   505             /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
   506             /* !!! FIXME: do both wings in one loop */
   507             for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
   508                 const int srcframe = srcindex - j;
   509                 /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
   510                 const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
   511                 outsample += (insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
   512             }
   513 
   514             for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
   515                 const int srcframe = srcindex + 1 + j;
   516                 /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
   517                 const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
   518                 outsample += (insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
   519             }
   520             *(dst++) = outsample;
   521         }
   522 
   523         outtime += outtimeincr;
   524     }
   525 
   526     return outframes * chans * sizeof (float);
   527 }
   528 
   529 int
   530 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   531 {
   532     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   533     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   534 
   535     /* Make sure there's data to convert */
   536     if (cvt->buf == NULL) {
   537         return SDL_SetError("No buffer allocated for conversion");
   538     }
   539 
   540     /* Return okay if no conversion is necessary */
   541     cvt->len_cvt = cvt->len;
   542     if (cvt->filters[0] == NULL) {
   543         return 0;
   544     }
   545 
   546     /* Set up the conversion and go! */
   547     cvt->filter_index = 0;
   548     cvt->filters[0] (cvt, cvt->src_format);
   549     return 0;
   550 }
   551 
   552 static void SDLCALL
   553 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   554 {
   555 #if DEBUG_CONVERT
   556     printf("Converting byte order\n");
   557 #endif
   558 
   559     switch (SDL_AUDIO_BITSIZE(format)) {
   560         #define CASESWAP(b) \
   561             case b: { \
   562                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   563                 int i; \
   564                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   565                     *ptr = SDL_Swap##b(*ptr); \
   566                 } \
   567                 break; \
   568             }
   569 
   570         CASESWAP(16);
   571         CASESWAP(32);
   572         CASESWAP(64);
   573 
   574         #undef CASESWAP
   575 
   576         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   577     }
   578 
   579     if (cvt->filters[++cvt->filter_index]) {
   580         /* flip endian flag for data. */
   581         if (format & SDL_AUDIO_MASK_ENDIAN) {
   582             format &= ~SDL_AUDIO_MASK_ENDIAN;
   583         } else {
   584             format |= SDL_AUDIO_MASK_ENDIAN;
   585         }
   586         cvt->filters[cvt->filter_index](cvt, format);
   587     }
   588 }
   589 
   590 static int
   591 SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
   592 {
   593     if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
   594         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
   595     }
   596     if (filter == NULL) {
   597         return SDL_SetError("Audio filter pointer is NULL");
   598     }
   599     cvt->filters[cvt->filter_index++] = filter;
   600     cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
   601     return 0;
   602 }
   603 
   604 static int
   605 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   606 {
   607     int retval = 0;  /* 0 == no conversion necessary. */
   608 
   609     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   610         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   611             return -1;
   612         }
   613         retval = 1;  /* added a converter. */
   614     }
   615 
   616     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   617         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   618         const Uint16 dst_bitsize = 32;
   619         SDL_AudioFilter filter = NULL;
   620 
   621         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   622             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   623             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   624             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   625             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   626             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   627             default: SDL_assert(!"Unexpected audio format!"); break;
   628         }
   629 
   630         if (!filter) {
   631             return SDL_SetError("No conversion from source format to float available");
   632         }
   633 
   634         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   635             return -1;
   636         }
   637         if (src_bitsize < dst_bitsize) {
   638             const int mult = (dst_bitsize / src_bitsize);
   639             cvt->len_mult *= mult;
   640             cvt->len_ratio *= mult;
   641         } else if (src_bitsize > dst_bitsize) {
   642             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   643         }
   644 
   645         retval = 1;  /* added a converter. */
   646     }
   647 
   648     return retval;
   649 }
   650 
   651 static int
   652 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   653 {
   654     int retval = 0;  /* 0 == no conversion necessary. */
   655 
   656     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   657         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   658         const Uint16 src_bitsize = 32;
   659         SDL_AudioFilter filter = NULL;
   660         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   661             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   662             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   663             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   664             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   665             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   666             default: SDL_assert(!"Unexpected audio format!"); break;
   667         }
   668 
   669         if (!filter) {
   670             return SDL_SetError("No conversion from float to destination format available");
   671         }
   672 
   673         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   674             return -1;
   675         }
   676         if (src_bitsize < dst_bitsize) {
   677             const int mult = (dst_bitsize / src_bitsize);
   678             cvt->len_mult *= mult;
   679             cvt->len_ratio *= mult;
   680         } else if (src_bitsize > dst_bitsize) {
   681             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   682         }
   683         retval = 1;  /* added a converter. */
   684     }
   685 
   686     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   687         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   688             return -1;
   689         }
   690         retval = 1;  /* added a converter. */
   691     }
   692 
   693     return retval;
   694 }
   695 
   696 static void
   697 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   698 {
   699     /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
   700        !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
   701        !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
   702     const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
   703     const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
   704     const float *src = (const float *) cvt->buf;
   705     const int srclen = cvt->len_cvt;
   706     /*float *dst = (float *) cvt->buf;
   707     const int dstlen = (cvt->len * cvt->len_mult);*/
   708     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   709     float *dst = (float *) (cvt->buf + srclen);
   710     const int dstlen = (cvt->len * cvt->len_mult) - srclen;
   711     const int paddingsamples = (ResamplerPadding(inrate, outrate) * chans);
   712     float *padding = SDL_stack_alloc(float, paddingsamples);
   713 
   714     SDL_assert(format == AUDIO_F32SYS);
   715 
   716     /* we keep no streaming state here, so pad with silence on both ends. */
   717     SDL_memset(padding, '\0', paddingsamples * sizeof (float));
   718 
   719     cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
   720 
   721     SDL_memcpy(cvt->buf, dst, cvt->len_cvt);  /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   722 
   723     if (cvt->filters[++cvt->filter_index]) {
   724         cvt->filters[cvt->filter_index](cvt, format);
   725     }
   726 }
   727 
   728 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   729    !!! FIXME:  store channel info, so we have to have function entry
   730    !!! FIXME:  points for each supported channel count and multiple
   731    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   732 #define RESAMPLER_FUNCS(chans) \
   733     static void SDLCALL \
   734     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   735         SDL_ResampleCVT(cvt, chans, format); \
   736     }
   737 RESAMPLER_FUNCS(1)
   738 RESAMPLER_FUNCS(2)
   739 RESAMPLER_FUNCS(4)
   740 RESAMPLER_FUNCS(6)
   741 RESAMPLER_FUNCS(8)
   742 #undef RESAMPLER_FUNCS
   743 
   744 static SDL_AudioFilter
   745 ChooseCVTResampler(const int dst_channels)
   746 {
   747     switch (dst_channels) {
   748         case 1: return SDL_ResampleCVT_c1;
   749         case 2: return SDL_ResampleCVT_c2;
   750         case 4: return SDL_ResampleCVT_c4;
   751         case 6: return SDL_ResampleCVT_c6;
   752         case 8: return SDL_ResampleCVT_c8;
   753         default: break;
   754     }
   755 
   756     return NULL;
   757 }
   758 
   759 static int
   760 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   761                           const int src_rate, const int dst_rate)
   762 {
   763     SDL_AudioFilter filter;
   764 
   765     if (src_rate == dst_rate) {
   766         return 0;  /* no conversion necessary. */
   767     }
   768 
   769     filter = ChooseCVTResampler(dst_channels);
   770     if (filter == NULL) {
   771         return SDL_SetError("No conversion available for these rates");
   772     }
   773 
   774     if (SDL_PrepareResampleFilter() < 0) {
   775         return -1;
   776     }
   777 
   778     /* Update (cvt) with filter details... */
   779     if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   780         return -1;
   781     }
   782 
   783     /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
   784        !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
   785        !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
   786     if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
   787         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
   788     }
   789     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
   790     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
   791 
   792     if (src_rate < dst_rate) {
   793         const double mult = ((double) dst_rate) / ((double) src_rate);
   794         cvt->len_mult *= (int) SDL_ceil(mult);
   795         cvt->len_ratio *= mult;
   796     } else {
   797         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   798     }
   799 
   800     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   801     /* the buffer is big enough to hold the destination now, but
   802        we need it large enough to hold a separate scratch buffer. */
   803     cvt->len_mult *= 2;
   804 
   805     return 1;               /* added a converter. */
   806 }
   807 
   808 static SDL_bool
   809 SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
   810 {
   811     switch (fmt) {
   812         case AUDIO_U8:
   813         case AUDIO_S8:
   814         case AUDIO_U16LSB:
   815         case AUDIO_S16LSB:
   816         case AUDIO_U16MSB:
   817         case AUDIO_S16MSB:
   818         case AUDIO_S32LSB:
   819         case AUDIO_S32MSB:
   820         case AUDIO_F32LSB:
   821         case AUDIO_F32MSB:
   822             return SDL_TRUE;  /* supported. */
   823 
   824         default:
   825             break;
   826     }
   827 
   828     return SDL_FALSE;  /* unsupported. */
   829 }
   830 
   831 static SDL_bool
   832 SDL_SupportedChannelCount(const int channels)
   833 {
   834     switch (channels) {
   835         case 1:  /* mono */
   836         case 2:  /* stereo */
   837         case 4:  /* quad */
   838         case 6:  /* 5.1 */
   839         case 8:  /* 7.1 */
   840           return SDL_TRUE;  /* supported. */
   841 
   842         default:
   843             break;
   844     }
   845 
   846     return SDL_FALSE;  /* unsupported. */
   847 }
   848 
   849 
   850 /* Creates a set of audio filters to convert from one format to another.
   851    Returns 0 if no conversion is needed, 1 if the audio filter is set up,
   852    or -1 if an error like invalid parameter, unsupported format, etc. occurred.
   853 */
   854 
   855 int
   856 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   857                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   858                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   859 {
   860     /* Sanity check target pointer */
   861     if (cvt == NULL) {
   862         return SDL_InvalidParamError("cvt");
   863     }
   864 
   865     /* Make sure we zero out the audio conversion before error checking */
   866     SDL_zerop(cvt);
   867 
   868     if (!SDL_SupportedAudioFormat(src_fmt)) {
   869         return SDL_SetError("Invalid source format");
   870     } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
   871         return SDL_SetError("Invalid destination format");
   872     } else if (!SDL_SupportedChannelCount(src_channels)) {
   873         return SDL_SetError("Invalid source channels");
   874     } else if (!SDL_SupportedChannelCount(dst_channels)) {
   875         return SDL_SetError("Invalid destination channels");
   876     } else if (src_rate == 0) {
   877         return SDL_SetError("Source rate is zero");
   878     } else if (dst_rate == 0) {
   879         return SDL_SetError("Destination rate is zero");
   880     }
   881 
   882 #if DEBUG_CONVERT
   883     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   884            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   885 #endif
   886 
   887     /* Start off with no conversion necessary */
   888     cvt->src_format = src_fmt;
   889     cvt->dst_format = dst_fmt;
   890     cvt->needed = 0;
   891     cvt->filter_index = 0;
   892     SDL_zero(cvt->filters);
   893     cvt->len_mult = 1;
   894     cvt->len_ratio = 1.0;
   895     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   896 
   897     /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
   898     SDL_ChooseAudioConverters();
   899 
   900     /* Type conversion goes like this now:
   901         - byteswap to CPU native format first if necessary.
   902         - convert to native Float32 if necessary.
   903         - resample and change channel count if necessary.
   904         - convert back to native format.
   905         - byteswap back to foreign format if necessary.
   906 
   907        The expectation is we can process data faster in float32
   908        (possibly with SIMD), and making several passes over the same
   909        buffer is likely to be CPU cache-friendly, avoiding the
   910        biggest performance hit in modern times. Previously we had
   911        (script-generated) custom converters for every data type and
   912        it was a bloat on SDL compile times and final library size. */
   913 
   914     /* see if we can skip float conversion entirely. */
   915     if (src_rate == dst_rate && src_channels == dst_channels) {
   916         if (src_fmt == dst_fmt) {
   917             return 0;
   918         }
   919 
   920         /* just a byteswap needed? */
   921         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   922             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   923                 return -1;
   924             }
   925             cvt->needed = 1;
   926             return 1;
   927         }
   928     }
   929 
   930     /* Convert data types, if necessary. Updates (cvt). */
   931     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   932         return -1;              /* shouldn't happen, but just in case... */
   933     }
   934 
   935     /* Channel conversion */
   936     if (src_channels < dst_channels) {
   937         /* Upmixing */
   938         /* Mono -> Stereo [-> ...] */
   939         if ((src_channels == 1) && (dst_channels > 1)) {
   940             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
   941                 return -1;
   942             }
   943             cvt->len_mult *= 2;
   944             src_channels = 2;
   945             cvt->len_ratio *= 2;
   946         }
   947         /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
   948         if ((src_channels == 2) && (dst_channels >= 6)) {
   949             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
   950                 return -1;
   951             }
   952             src_channels = 6;
   953             cvt->len_mult *= 3;
   954             cvt->len_ratio *= 3;
   955         }
   956         /* Quad -> 5.1 [-> 7.1] */
   957         if ((src_channels == 4) && (dst_channels >= 6)) {
   958             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
   959                 return -1;
   960             }
   961             src_channels = 6;
   962             cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
   963             cvt->len_ratio *= 1.5;
   964         }
   965         /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
   966         if ((src_channels == 6) && (dst_channels == 8)) {
   967             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
   968                 return -1;
   969             }
   970             src_channels = 8;
   971             cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
   972             /* Should be numerically exact with every valid input to this
   973                function */
   974             cvt->len_ratio = cvt->len_ratio * 4 / 3;
   975         }
   976         /* [Mono ->] Stereo -> Quad */
   977         if ((src_channels == 2) && (dst_channels == 4)) {
   978             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
   979                 return -1;
   980             }
   981             src_channels = 4;
   982             cvt->len_mult *= 2;
   983             cvt->len_ratio *= 2;
   984         }
   985     } else if (src_channels > dst_channels) {
   986         /* Downmixing */
   987         /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
   988         /* 7.1 -> 5.1 [-> Quad] */
   989         if ((src_channels == 8) && (dst_channels <= 6)) {
   990             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
   991                 return -1;
   992             }
   993             src_channels = 6;
   994             cvt->len_ratio *= 0.75;
   995         }
   996         /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
   997         if ((src_channels == 6) && (dst_channels <= 2)) {
   998             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
   999                 return -1;
  1000             }
  1001             src_channels = 2;
  1002             cvt->len_ratio /= 3;
  1003         }
  1004         /* 5.1 -> Quad */
  1005         if ((src_channels == 6) && (dst_channels == 4)) {
  1006             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
  1007                 return -1;
  1008             }
  1009             src_channels = 4;
  1010             cvt->len_ratio = cvt->len_ratio * 2 / 3;
  1011         }
  1012         /* Quad -> Stereo [-> Mono] */
  1013         if ((src_channels == 4) && (dst_channels <= 2)) {
  1014             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
  1015                 return -1;
  1016             }
  1017             src_channels = 2;
  1018             cvt->len_ratio /= 2;
  1019         }
  1020         /* [... ->] Stereo -> Mono */
  1021         if ((src_channels == 2) && (dst_channels == 1)) {
  1022             SDL_AudioFilter filter = NULL;
  1023 
  1024             #if HAVE_SSE3_INTRINSICS
  1025             if (SDL_HasSSE3()) {
  1026                 filter = SDL_ConvertStereoToMono_SSE3;
  1027             }
  1028             #endif
  1029 
  1030             if (!filter) {
  1031                 filter = SDL_ConvertStereoToMono;
  1032             }
  1033 
  1034             if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
  1035                 return -1;
  1036             }
  1037 
  1038             src_channels = 1;
  1039             cvt->len_ratio /= 2;
  1040         }
  1041     }
  1042 
  1043     if (src_channels != dst_channels) {
  1044         /* All combinations of supported channel counts should have been
  1045            handled by now, but let's be defensive */
  1046       return SDL_SetError("Invalid channel combination");
  1047     }
  1048     
  1049     /* Do rate conversion, if necessary. Updates (cvt). */
  1050     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
  1051         return -1;              /* shouldn't happen, but just in case... */
  1052     }
  1053 
  1054     /* Move to final data type. */
  1055     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
  1056         return -1;              /* shouldn't happen, but just in case... */
  1057     }
  1058 
  1059     cvt->needed = (cvt->filter_index != 0);
  1060     return (cvt->needed);
  1061 }
  1062 
  1063 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
  1064 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1065 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1066 
  1067 struct SDL_AudioStream
  1068 {
  1069     SDL_AudioCVT cvt_before_resampling;
  1070     SDL_AudioCVT cvt_after_resampling;
  1071     SDL_DataQueue *queue;
  1072     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
  1073     int work_buffer_len;
  1074     int src_sample_frame_size;
  1075     SDL_AudioFormat src_format;
  1076     Uint8 src_channels;
  1077     int src_rate;
  1078     int dst_sample_frame_size;
  1079     SDL_AudioFormat dst_format;
  1080     Uint8 dst_channels;
  1081     int dst_rate;
  1082     double rate_incr;
  1083     Uint8 pre_resample_channels;
  1084     int packetlen;
  1085     void *resampler_state;
  1086     SDL_ResampleAudioStreamFunc resampler_func;
  1087     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
  1088     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
  1089 };
  1090 
  1091 static Uint8 *
  1092 EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
  1093 {
  1094     Uint8 *ptr;
  1095     size_t offset;
  1096 
  1097     if (stream->work_buffer_len >= newlen) {
  1098         ptr = stream->work_buffer_base;
  1099     } else {
  1100         ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
  1101         if (!ptr) {
  1102             SDL_OutOfMemory();
  1103             return NULL;
  1104         }
  1105         /* Make sure we're aligned to 16 bytes for SIMD code. */
  1106         stream->work_buffer_base = ptr;
  1107         stream->work_buffer_len = newlen;
  1108     }
  1109 
  1110     offset = ((size_t) ptr) & 15;
  1111     return offset ? ptr + (16 - offset) : ptr;
  1112 }
  1113 
  1114 #ifdef HAVE_LIBSAMPLERATE_H
  1115 static int
  1116 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1117 {
  1118     const float *inbuf = (const float *) _inbuf;
  1119     float *outbuf = (float *) _outbuf;
  1120     const int framelen = sizeof(float) * stream->pre_resample_channels;
  1121     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1122     SRC_DATA data;
  1123     int result;
  1124 
  1125     if (inbuf == ((const float *) outbuf)) {  /* libsamplerate can't work in-place. */
  1126         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1127         if (ptr == NULL) {
  1128             SDL_OutOfMemory();
  1129             return 0;
  1130         }
  1131         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1132         inbuf = (const float *) (ptr + outbuflen);
  1133         outbuf = (float *) ptr;
  1134     }
  1135 
  1136     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
  1137     data.input_frames = inbuflen / framelen;
  1138     data.input_frames_used = 0;
  1139 
  1140     data.data_out = outbuf;
  1141     data.output_frames = outbuflen / framelen;
  1142 
  1143     data.end_of_input = 0;
  1144     data.src_ratio = stream->rate_incr;
  1145 
  1146     result = SRC_src_process(state, &data);
  1147     if (result != 0) {
  1148         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
  1149         return 0;
  1150     }
  1151 
  1152     /* If this fails, we need to store them off somewhere */
  1153     SDL_assert(data.input_frames_used == data.input_frames);
  1154 
  1155     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
  1156 }
  1157 
  1158 static void
  1159 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1160 {
  1161     SRC_src_reset((SRC_STATE *)stream->resampler_state);
  1162 }
  1163 
  1164 static void
  1165 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1166 {
  1167     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1168     if (state) {
  1169         SRC_src_delete(state);
  1170     }
  1171 
  1172     stream->resampler_state = NULL;
  1173     stream->resampler_func = NULL;
  1174     stream->reset_resampler_func = NULL;
  1175     stream->cleanup_resampler_func = NULL;
  1176 }
  1177 
  1178 static SDL_bool
  1179 SetupLibSampleRateResampling(SDL_AudioStream *stream)
  1180 {
  1181     int result = 0;
  1182     SRC_STATE *state = NULL;
  1183 
  1184     if (SRC_available) {
  1185         state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
  1186         if (!state) {
  1187             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
  1188         }
  1189     }
  1190 
  1191     if (!state) {
  1192         SDL_CleanupAudioStreamResampler_SRC(stream);
  1193         return SDL_FALSE;
  1194     }
  1195 
  1196     stream->resampler_state = state;
  1197     stream->resampler_func = SDL_ResampleAudioStream_SRC;
  1198     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
  1199     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
  1200 
  1201     return SDL_TRUE;
  1202 }
  1203 #endif /* HAVE_LIBSAMPLERATE_H */
  1204 
  1205 
  1206 static int
  1207 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1208 {
  1209     const float *inbuf = (const float *) _inbuf;
  1210     float *outbuf = (float *) _outbuf;
  1211     const int chans = (int) stream->pre_resample_channels;
  1212     const int inrate = stream->src_rate;
  1213     const int outrate = stream->dst_rate;
  1214     const int paddingsamples = ResamplerPadding(inrate, outrate) * chans;
  1215     const int paddingbytes = paddingsamples * sizeof (float);
  1216     float *lpadding = (float *) stream->resampler_state;
  1217     float *rpadding = SDL_stack_alloc(float, paddingsamples);
  1218     int retval;
  1219 
  1220     if (inbuf == ((const float *) outbuf)) {  /* !!! FIXME can't work in-place (for now!). */
  1221         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1222         if (ptr == NULL) {
  1223             SDL_OutOfMemory();
  1224             return 0;
  1225         }
  1226         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1227         inbuf = (const float *) (ptr + outbuflen);
  1228         outbuf = (float *) ptr;
  1229     }
  1230 
  1231     /* !!! FIXME: streaming current resamples on Put, because of probably good reasons I can't remember right now, but if we resample on Get, we'd be able to access legit right padding values. */
  1232     SDL_memset(rpadding, '\0', paddingbytes);
  1233     retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
  1234 
  1235     /* update our left padding with end of current input, for next run. */
  1236     SDL_memcpy(lpadding, ((const Uint8 *) inbuf) + (inbuflen - paddingbytes), paddingbytes);
  1237 
  1238     return retval;
  1239 }
  1240 
  1241 static void
  1242 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1243 {
  1244     /* set all the left padding to silence. */
  1245     const int inrate = stream->src_rate;
  1246     const int outrate = stream->dst_rate;
  1247     const int chans = (int) stream->pre_resample_channels;
  1248     const int len = ResamplerPadding(inrate, outrate) * chans;
  1249     SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
  1250 }
  1251 
  1252 static void
  1253 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1254 {
  1255     SDL_free(stream->resampler_state);
  1256 }
  1257 
  1258 SDL_AudioStream *
  1259 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1260                    const Uint8 src_channels,
  1261                    const int src_rate,
  1262                    const SDL_AudioFormat dst_format,
  1263                    const Uint8 dst_channels,
  1264                    const int dst_rate)
  1265 {
  1266     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1267     Uint8 pre_resample_channels;
  1268     SDL_AudioStream *retval;
  1269 
  1270     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1271     if (!retval) {
  1272         return NULL;
  1273     }
  1274 
  1275     /* If increasing channels, do it after resampling, since we'd just
  1276        do more work to resample duplicate channels. If we're decreasing, do
  1277        it first so we resample the interpolated data instead of interpolating
  1278        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1279     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1280 
  1281     retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
  1282     retval->src_format = src_format;
  1283     retval->src_channels = src_channels;
  1284     retval->src_rate = src_rate;
  1285     retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
  1286     retval->dst_format = dst_format;
  1287     retval->dst_channels = dst_channels;
  1288     retval->dst_rate = dst_rate;
  1289     retval->pre_resample_channels = pre_resample_channels;
  1290     retval->packetlen = packetlen;
  1291     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1292 
  1293     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1294     if (src_rate == dst_rate) {
  1295         retval->cvt_before_resampling.needed = SDL_FALSE;
  1296         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1297             SDL_FreeAudioStream(retval);
  1298             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1299         }
  1300     } else {
  1301         /* Don't resample at first. Just get us to Float32 format. */
  1302         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1303         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1304             SDL_FreeAudioStream(retval);
  1305             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1306         }
  1307 
  1308 #ifdef HAVE_LIBSAMPLERATE_H
  1309         SetupLibSampleRateResampling(retval);
  1310 #endif
  1311 
  1312         if (!retval->resampler_func) {
  1313             const int chans = (int) pre_resample_channels;
  1314             const int len = ResamplerPadding(src_rate, dst_rate) * chans;
  1315             retval->resampler_state = SDL_calloc(len, sizeof (float));
  1316             if (!retval->resampler_state) {
  1317                 SDL_FreeAudioStream(retval);
  1318                 SDL_OutOfMemory();
  1319                 return NULL;
  1320             }
  1321 
  1322             if (SDL_PrepareResampleFilter() < 0) {
  1323                 SDL_free(retval->resampler_state);
  1324                 retval->resampler_state = NULL;
  1325                 SDL_FreeAudioStream(retval);
  1326                 return NULL;
  1327             }
  1328 
  1329             retval->resampler_func = SDL_ResampleAudioStream;
  1330             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1331             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1332         }
  1333 
  1334         /* Convert us to the final format after resampling. */
  1335         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1336             SDL_FreeAudioStream(retval);
  1337             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1338         }
  1339     }
  1340 
  1341     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1342     if (!retval->queue) {
  1343         SDL_FreeAudioStream(retval);
  1344         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1345     }
  1346 
  1347     return retval;
  1348 }
  1349 
  1350 int
  1351 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1352 {
  1353     int buflen = (int) _buflen;
  1354     const void *origbuf = buf;
  1355 
  1356     /* !!! FIXME: several converters can take advantage of SIMD, but only
  1357        !!! FIXME:  if the data is aligned to 16 bytes. EnsureStreamBufferSize()
  1358        !!! FIXME:  guarantees the buffer will align, but the
  1359        !!! FIXME:  converters will iterate over the data backwards if
  1360        !!! FIXME:  the output grows, and this means we won't align if buflen
  1361        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1362        !!! FIXME:  a few samples at the end and convert them separately. */
  1363 
  1364     if (!stream) {
  1365         return SDL_InvalidParamError("stream");
  1366     } else if (!buf) {
  1367         return SDL_InvalidParamError("buf");
  1368     } else if (buflen == 0) {
  1369         return 0;  /* nothing to do. */
  1370     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1371         return SDL_SetError("Can't add partial sample frames");
  1372     }
  1373 
  1374     if (stream->cvt_before_resampling.needed) {
  1375         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1376         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1377         if (workbuf == NULL) {
  1378             return -1;  /* probably out of memory. */
  1379         }
  1380         SDL_assert(buf == origbuf);
  1381         SDL_memcpy(workbuf, buf, buflen);
  1382         stream->cvt_before_resampling.buf = workbuf;
  1383         stream->cvt_before_resampling.len = buflen;
  1384         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1385             return -1;   /* uhoh! */
  1386         }
  1387         buf = workbuf;
  1388         buflen = stream->cvt_before_resampling.len_cvt;
  1389     }
  1390 
  1391     if (stream->dst_rate != stream->src_rate) {
  1392         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1393         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1394         if (workbuf == NULL) {
  1395             return -1;  /* probably out of memory. */
  1396         }
  1397         /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
  1398            libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
  1399         if (buf != origbuf) {
  1400             buf = workbuf;  /* in case we realloc()'d the pointer. */
  1401         }
  1402         buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
  1403         buf = EnsureStreamBufferSize(stream, workbuflen);
  1404         SDL_assert(buf != NULL);  /* shouldn't be growing, just aligning. */
  1405     }
  1406 
  1407     if (stream->cvt_after_resampling.needed) {
  1408         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1409         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1410         if (workbuf == NULL) {
  1411             return -1;  /* probably out of memory. */
  1412         }
  1413         if (buf == origbuf) {  /* copy if we haven't before. */
  1414             SDL_memcpy(workbuf, origbuf, buflen);
  1415         }
  1416         stream->cvt_after_resampling.buf = workbuf;
  1417         stream->cvt_after_resampling.len = buflen;
  1418         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1419             return -1;   /* uhoh! */
  1420         }
  1421         buf = workbuf;
  1422         buflen = stream->cvt_after_resampling.len_cvt;
  1423     }
  1424 
  1425     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1426 }
  1427 
  1428 void
  1429 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1430 {
  1431     if (!stream) {
  1432         SDL_InvalidParamError("stream");
  1433     } else {
  1434         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1435         if (stream->reset_resampler_func) {
  1436             stream->reset_resampler_func(stream);
  1437         }
  1438     }
  1439 }
  1440 
  1441 
  1442 /* get converted/resampled data from the stream */
  1443 int
  1444 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1445 {
  1446     if (!stream) {
  1447         return SDL_InvalidParamError("stream");
  1448     } else if (!buf) {
  1449         return SDL_InvalidParamError("buf");
  1450     } else if (len == 0) {
  1451         return 0;  /* nothing to do. */
  1452     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1453         return SDL_SetError("Can't request partial sample frames");
  1454     }
  1455 
  1456     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1457 }
  1458 
  1459 /* number of converted/resampled bytes available */
  1460 int
  1461 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1462 {
  1463     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1464 }
  1465 
  1466 /* dispose of a stream */
  1467 void
  1468 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1469 {
  1470     if (stream) {
  1471         if (stream->cleanup_resampler_func) {
  1472             stream->cleanup_resampler_func(stream);
  1473         }
  1474         SDL_FreeDataQueue(stream->queue);
  1475         SDL_free(stream->work_buffer_base);
  1476         SDL_free(stream);
  1477     }
  1478 }
  1479 
  1480 /* vi: set ts=4 sw=4 expandtab: */
  1481