src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 21 Sep 2017 02:51:14 -0400
changeset 11508 a8382e3d0b54
parent 11406 f40c2dedaded
child 11517 beb96c015b30
permissions -rw-r--r--
audio: Replaced the resampler. Again.

This time it's using real math from a real whitepaper instead of my previous
amateur, fast-but-low-quality attempt. The new resampler does "bandlimited
interpolation," as described here: https://ccrma.stanford.edu/~jos/resample/

The output appears to sound cleaner, especially at high frequencies, and of
course works with non-power-of-two rate conversions.

There are some obvious optimizations to be done to this still, and there is
other fallout: this doesn't resample a buffer in-place, the 2-channels-Sint16
fast path is gone because this resampler does a _lot_ of floating point math.
There is a nasty hack to make it work with SDL_AudioCVT.

It's possible these issues are solvable, but they aren't solved as of yet.
Still, I hope this effort is slouching in the right direction.
     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 
   468 static int
   469 SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
   470                         float *last_sample, const float *inbuf,
   471                         const int inbuflen, float *outbuf, const int outbuflen)
   472 {
   473     const float outtimeincr = 1.0f / ((float) outrate);
   474     const float ratio = ((float) outrate) / ((float) inrate);
   475     /*const int padding_len = (ratio < 1.0f) ? (int) SDL_ceilf(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING;*/
   476     const int framelen = chans * (int)sizeof (float);
   477     const int inframes = inbuflen / framelen;
   478     const int wantedoutframes = (int) ((inbuflen / framelen) * ratio);  /* outbuflen isn't total to write, it's total available. */
   479     const int maxoutframes = outbuflen / framelen;
   480     const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes;
   481     float *dst = outbuf;
   482     float outtime = 0.0f;
   483     int i, j, chan;
   484 
   485     for (i = 0; i < outframes; i++) {
   486         const int srcindex = (int) (outtime * inrate);
   487         const float finrate = (float) inrate;
   488         const float intime = ((float) srcindex) / finrate;
   489         const float innexttime = ((float) (srcindex + 1)) / finrate;
   490 
   491         const float interpolation1 = 1.0f - (innexttime - outtime) / (innexttime - intime);
   492         const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
   493         const float interpolation2 = 1.0f - interpolation1;
   494         const int filterindex2 = interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
   495 
   496         for (chan = 0; chan < chans; chan++) {
   497             float outsample = 0.0f;
   498 
   499             /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
   500             /* !!! FIXME: do both wings in one loop */
   501             for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
   502                 /* !!! FIXME: insample uses zero for padding samples, but it should use prior state from last_sample. */
   503                 const int srcframe = srcindex - j;
   504                 const float insample = (srcframe < 0) ? 0.0f : inbuf[(srcframe * chans) + chan];  /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
   505                 outsample += (insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
   506             }
   507 
   508             for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
   509                 const int srcframe = srcindex + 1 + j;
   510                 /* !!! FIXME: insample uses zero for padding samples, but it should use prior state from last_sample. */
   511                 const float insample = (srcframe >= inframes) ? 0.0f : inbuf[(srcframe * chans) + chan];  /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
   512                 outsample += (insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
   513             }
   514             *(dst++) = outsample;
   515         }
   516 
   517         outtime += outtimeincr;
   518     }
   519 
   520     return outframes * chans * sizeof (float);
   521 }
   522 
   523 int
   524 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   525 {
   526     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   527     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   528 
   529     /* Make sure there's data to convert */
   530     if (cvt->buf == NULL) {
   531         return SDL_SetError("No buffer allocated for conversion");
   532     }
   533 
   534     /* Return okay if no conversion is necessary */
   535     cvt->len_cvt = cvt->len;
   536     if (cvt->filters[0] == NULL) {
   537         return 0;
   538     }
   539 
   540     /* Set up the conversion and go! */
   541     cvt->filter_index = 0;
   542     cvt->filters[0] (cvt, cvt->src_format);
   543     return 0;
   544 }
   545 
   546 static void SDLCALL
   547 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   548 {
   549 #if DEBUG_CONVERT
   550     printf("Converting byte order\n");
   551 #endif
   552 
   553     switch (SDL_AUDIO_BITSIZE(format)) {
   554         #define CASESWAP(b) \
   555             case b: { \
   556                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   557                 int i; \
   558                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   559                     *ptr = SDL_Swap##b(*ptr); \
   560                 } \
   561                 break; \
   562             }
   563 
   564         CASESWAP(16);
   565         CASESWAP(32);
   566         CASESWAP(64);
   567 
   568         #undef CASESWAP
   569 
   570         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   571     }
   572 
   573     if (cvt->filters[++cvt->filter_index]) {
   574         /* flip endian flag for data. */
   575         if (format & SDL_AUDIO_MASK_ENDIAN) {
   576             format &= ~SDL_AUDIO_MASK_ENDIAN;
   577         } else {
   578             format |= SDL_AUDIO_MASK_ENDIAN;
   579         }
   580         cvt->filters[cvt->filter_index](cvt, format);
   581     }
   582 }
   583 
   584 static int
   585 SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
   586 {
   587     if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
   588         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
   589     }
   590     if (filter == NULL) {
   591         return SDL_SetError("Audio filter pointer is NULL");
   592     }
   593     cvt->filters[cvt->filter_index++] = filter;
   594     cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
   595     return 0;
   596 }
   597 
   598 static int
   599 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   600 {
   601     int retval = 0;  /* 0 == no conversion necessary. */
   602 
   603     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   604         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   605             return -1;
   606         }
   607         retval = 1;  /* added a converter. */
   608     }
   609 
   610     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   611         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   612         const Uint16 dst_bitsize = 32;
   613         SDL_AudioFilter filter = NULL;
   614 
   615         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   616             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   617             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   618             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   619             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   620             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   621             default: SDL_assert(!"Unexpected audio format!"); break;
   622         }
   623 
   624         if (!filter) {
   625             return SDL_SetError("No conversion from source format to float available");
   626         }
   627 
   628         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   629             return -1;
   630         }
   631         if (src_bitsize < dst_bitsize) {
   632             const int mult = (dst_bitsize / src_bitsize);
   633             cvt->len_mult *= mult;
   634             cvt->len_ratio *= mult;
   635         } else if (src_bitsize > dst_bitsize) {
   636             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   637         }
   638 
   639         retval = 1;  /* added a converter. */
   640     }
   641 
   642     return retval;
   643 }
   644 
   645 static int
   646 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   647 {
   648     int retval = 0;  /* 0 == no conversion necessary. */
   649 
   650     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   651         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   652         const Uint16 src_bitsize = 32;
   653         SDL_AudioFilter filter = NULL;
   654         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   655             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   656             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   657             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   658             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   659             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   660             default: SDL_assert(!"Unexpected audio format!"); break;
   661         }
   662 
   663         if (!filter) {
   664             return SDL_SetError("No conversion from float to destination format available");
   665         }
   666 
   667         if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   668             return -1;
   669         }
   670         if (src_bitsize < dst_bitsize) {
   671             const int mult = (dst_bitsize / src_bitsize);
   672             cvt->len_mult *= mult;
   673             cvt->len_ratio *= mult;
   674         } else if (src_bitsize > dst_bitsize) {
   675             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   676         }
   677         retval = 1;  /* added a converter. */
   678     }
   679 
   680     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   681         if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   682             return -1;
   683         }
   684         retval = 1;  /* added a converter. */
   685     }
   686 
   687     return retval;
   688 }
   689 
   690 static void
   691 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   692 {
   693     /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
   694        !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
   695        !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
   696     const int srcrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
   697     const int dstrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
   698     const float *src = (const float *) cvt->buf;
   699     const int srclen = cvt->len_cvt;
   700     /*float *dst = (float *) cvt->buf;
   701     const int dstlen = (cvt->len * cvt->len_mult);*/
   702     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   703     float *dst = (float *) (cvt->buf + srclen);
   704     const int dstlen = (cvt->len * cvt->len_mult) - srclen;
   705     float state[8];
   706 
   707     SDL_assert(format == AUDIO_F32SYS);
   708 
   709     SDL_zero(state);
   710 
   711     cvt->len_cvt = SDL_ResampleAudio(chans, srcrate, dstrate, state, src, srclen, dst, dstlen);
   712 
   713     SDL_memcpy(cvt->buf, dst, cvt->len_cvt);  /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   714 
   715     if (cvt->filters[++cvt->filter_index]) {
   716         cvt->filters[cvt->filter_index](cvt, format);
   717     }
   718 }
   719 
   720 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   721    !!! FIXME:  store channel info, so we have to have function entry
   722    !!! FIXME:  points for each supported channel count and multiple
   723    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   724 #define RESAMPLER_FUNCS(chans) \
   725     static void SDLCALL \
   726     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   727         SDL_ResampleCVT(cvt, chans, format); \
   728     }
   729 RESAMPLER_FUNCS(1)
   730 RESAMPLER_FUNCS(2)
   731 RESAMPLER_FUNCS(4)
   732 RESAMPLER_FUNCS(6)
   733 RESAMPLER_FUNCS(8)
   734 #undef RESAMPLER_FUNCS
   735 
   736 static SDL_AudioFilter
   737 ChooseCVTResampler(const int dst_channels)
   738 {
   739     switch (dst_channels) {
   740         case 1: return SDL_ResampleCVT_c1;
   741         case 2: return SDL_ResampleCVT_c2;
   742         case 4: return SDL_ResampleCVT_c4;
   743         case 6: return SDL_ResampleCVT_c6;
   744         case 8: return SDL_ResampleCVT_c8;
   745         default: break;
   746     }
   747 
   748     return NULL;
   749 }
   750 
   751 static int
   752 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   753                           const int src_rate, const int dst_rate)
   754 {
   755     SDL_AudioFilter filter;
   756 
   757     if (src_rate == dst_rate) {
   758         return 0;  /* no conversion necessary. */
   759     }
   760 
   761     filter = ChooseCVTResampler(dst_channels);
   762     if (filter == NULL) {
   763         return SDL_SetError("No conversion available for these rates");
   764     }
   765 
   766     if (SDL_PrepareResampleFilter() < 0) {
   767         return -1;
   768     }
   769 
   770     /* Update (cvt) with filter details... */
   771     if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   772         return -1;
   773     }
   774 
   775     /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
   776        !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
   777        !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
   778     if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
   779         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
   780     }
   781     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
   782     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
   783 
   784     if (src_rate < dst_rate) {
   785         const double mult = ((double) dst_rate) / ((double) src_rate);
   786         cvt->len_mult *= (int) SDL_ceil(mult);
   787         cvt->len_ratio *= mult;
   788     } else {
   789         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   790     }
   791 
   792     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   793     /* the buffer is big enough to hold the destination now, but
   794        we need it large enough to hold a separate scratch buffer. */
   795     cvt->len_mult *= 2;
   796 
   797     return 1;               /* added a converter. */
   798 }
   799 
   800 static SDL_bool
   801 SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
   802 {
   803     switch (fmt) {
   804         case AUDIO_U8:
   805         case AUDIO_S8:
   806         case AUDIO_U16LSB:
   807         case AUDIO_S16LSB:
   808         case AUDIO_U16MSB:
   809         case AUDIO_S16MSB:
   810         case AUDIO_S32LSB:
   811         case AUDIO_S32MSB:
   812         case AUDIO_F32LSB:
   813         case AUDIO_F32MSB:
   814             return SDL_TRUE;  /* supported. */
   815 
   816         default:
   817             break;
   818     }
   819 
   820     return SDL_FALSE;  /* unsupported. */
   821 }
   822 
   823 static SDL_bool
   824 SDL_SupportedChannelCount(const int channels)
   825 {
   826     switch (channels) {
   827         case 1:  /* mono */
   828         case 2:  /* stereo */
   829         case 4:  /* quad */
   830         case 6:  /* 5.1 */
   831         case 8:  /* 7.1 */
   832           return SDL_TRUE;  /* supported. */
   833 
   834         default:
   835             break;
   836     }
   837 
   838     return SDL_FALSE;  /* unsupported. */
   839 }
   840 
   841 
   842 /* Creates a set of audio filters to convert from one format to another.
   843    Returns 0 if no conversion is needed, 1 if the audio filter is set up,
   844    or -1 if an error like invalid parameter, unsupported format, etc. occurred.
   845 */
   846 
   847 int
   848 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   849                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   850                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   851 {
   852     /* Sanity check target pointer */
   853     if (cvt == NULL) {
   854         return SDL_InvalidParamError("cvt");
   855     }
   856 
   857     /* Make sure we zero out the audio conversion before error checking */
   858     SDL_zerop(cvt);
   859 
   860     if (!SDL_SupportedAudioFormat(src_fmt)) {
   861         return SDL_SetError("Invalid source format");
   862     } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
   863         return SDL_SetError("Invalid destination format");
   864     } else if (!SDL_SupportedChannelCount(src_channels)) {
   865         return SDL_SetError("Invalid source channels");
   866     } else if (!SDL_SupportedChannelCount(dst_channels)) {
   867         return SDL_SetError("Invalid destination channels");
   868     } else if (src_rate == 0) {
   869         return SDL_SetError("Source rate is zero");
   870     } else if (dst_rate == 0) {
   871         return SDL_SetError("Destination rate is zero");
   872     }
   873 
   874 #if DEBUG_CONVERT
   875     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   876            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   877 #endif
   878 
   879     /* Start off with no conversion necessary */
   880     cvt->src_format = src_fmt;
   881     cvt->dst_format = dst_fmt;
   882     cvt->needed = 0;
   883     cvt->filter_index = 0;
   884     SDL_zero(cvt->filters);
   885     cvt->len_mult = 1;
   886     cvt->len_ratio = 1.0;
   887     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   888 
   889     /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
   890     SDL_ChooseAudioConverters();
   891 
   892     /* Type conversion goes like this now:
   893         - byteswap to CPU native format first if necessary.
   894         - convert to native Float32 if necessary.
   895         - resample and change channel count if necessary.
   896         - convert back to native format.
   897         - byteswap back to foreign format if necessary.
   898 
   899        The expectation is we can process data faster in float32
   900        (possibly with SIMD), and making several passes over the same
   901        buffer is likely to be CPU cache-friendly, avoiding the
   902        biggest performance hit in modern times. Previously we had
   903        (script-generated) custom converters for every data type and
   904        it was a bloat on SDL compile times and final library size. */
   905 
   906     /* see if we can skip float conversion entirely. */
   907     if (src_rate == dst_rate && src_channels == dst_channels) {
   908         if (src_fmt == dst_fmt) {
   909             return 0;
   910         }
   911 
   912         /* just a byteswap needed? */
   913         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   914             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   915                 return -1;
   916             }
   917             cvt->needed = 1;
   918             return 1;
   919         }
   920     }
   921 
   922     /* Convert data types, if necessary. Updates (cvt). */
   923     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   924         return -1;              /* shouldn't happen, but just in case... */
   925     }
   926 
   927     /* Channel conversion */
   928     if (src_channels < dst_channels) {
   929         /* Upmixing */
   930         /* Mono -> Stereo [-> ...] */
   931         if ((src_channels == 1) && (dst_channels > 1)) {
   932             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
   933                 return -1;
   934             }
   935             cvt->len_mult *= 2;
   936             src_channels = 2;
   937             cvt->len_ratio *= 2;
   938         }
   939         /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
   940         if ((src_channels == 2) && (dst_channels >= 6)) {
   941             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
   942                 return -1;
   943             }
   944             src_channels = 6;
   945             cvt->len_mult *= 3;
   946             cvt->len_ratio *= 3;
   947         }
   948         /* Quad -> 5.1 [-> 7.1] */
   949         if ((src_channels == 4) && (dst_channels >= 6)) {
   950             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
   951                 return -1;
   952             }
   953             src_channels = 6;
   954             cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
   955             cvt->len_ratio *= 1.5;
   956         }
   957         /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
   958         if ((src_channels == 6) && (dst_channels == 8)) {
   959             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
   960                 return -1;
   961             }
   962             src_channels = 8;
   963             cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
   964             /* Should be numerically exact with every valid input to this
   965                function */
   966             cvt->len_ratio = cvt->len_ratio * 4 / 3;
   967         }
   968         /* [Mono ->] Stereo -> Quad */
   969         if ((src_channels == 2) && (dst_channels == 4)) {
   970             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
   971                 return -1;
   972             }
   973             src_channels = 4;
   974             cvt->len_mult *= 2;
   975             cvt->len_ratio *= 2;
   976         }
   977     } else if (src_channels > dst_channels) {
   978         /* Downmixing */
   979         /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
   980         /* 7.1 -> 5.1 [-> Quad] */
   981         if ((src_channels == 8) && (dst_channels <= 6)) {
   982             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
   983                 return -1;
   984             }
   985             src_channels = 6;
   986             cvt->len_ratio *= 0.75;
   987         }
   988         /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
   989         if ((src_channels == 6) && (dst_channels <= 2)) {
   990             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
   991                 return -1;
   992             }
   993             src_channels = 2;
   994             cvt->len_ratio /= 3;
   995         }
   996         /* 5.1 -> Quad */
   997         if ((src_channels == 6) && (dst_channels == 4)) {
   998             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
   999                 return -1;
  1000             }
  1001             src_channels = 4;
  1002             cvt->len_ratio = cvt->len_ratio * 2 / 3;
  1003         }
  1004         /* Quad -> Stereo [-> Mono] */
  1005         if ((src_channels == 4) && (dst_channels <= 2)) {
  1006             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
  1007                 return -1;
  1008             }
  1009             src_channels = 2;
  1010             cvt->len_ratio /= 2;
  1011         }
  1012         /* [... ->] Stereo -> Mono */
  1013         if ((src_channels == 2) && (dst_channels == 1)) {
  1014             SDL_AudioFilter filter = NULL;
  1015 
  1016             #if HAVE_SSE3_INTRINSICS
  1017             if (SDL_HasSSE3()) {
  1018                 filter = SDL_ConvertStereoToMono_SSE3;
  1019             }
  1020             #endif
  1021 
  1022             if (!filter) {
  1023                 filter = SDL_ConvertStereoToMono;
  1024             }
  1025 
  1026             if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
  1027                 return -1;
  1028             }
  1029 
  1030             src_channels = 1;
  1031             cvt->len_ratio /= 2;
  1032         }
  1033     }
  1034 
  1035     if (src_channels != dst_channels) {
  1036         /* All combinations of supported channel counts should have been
  1037            handled by now, but let's be defensive */
  1038       return SDL_SetError("Invalid channel combination");
  1039     }
  1040     
  1041     /* Do rate conversion, if necessary. Updates (cvt). */
  1042     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
  1043         return -1;              /* shouldn't happen, but just in case... */
  1044     }
  1045 
  1046     /* Move to final data type. */
  1047     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
  1048         return -1;              /* shouldn't happen, but just in case... */
  1049     }
  1050 
  1051     cvt->needed = (cvt->filter_index != 0);
  1052     return (cvt->needed);
  1053 }
  1054 
  1055 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
  1056 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1057 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1058 
  1059 struct SDL_AudioStream
  1060 {
  1061     SDL_AudioCVT cvt_before_resampling;
  1062     SDL_AudioCVT cvt_after_resampling;
  1063     SDL_DataQueue *queue;
  1064     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
  1065     int work_buffer_len;
  1066     int src_sample_frame_size;
  1067     SDL_AudioFormat src_format;
  1068     Uint8 src_channels;
  1069     int src_rate;
  1070     int dst_sample_frame_size;
  1071     SDL_AudioFormat dst_format;
  1072     Uint8 dst_channels;
  1073     int dst_rate;
  1074     double rate_incr;
  1075     Uint8 pre_resample_channels;
  1076     int packetlen;
  1077     void *resampler_state;
  1078     SDL_ResampleAudioStreamFunc resampler_func;
  1079     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
  1080     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
  1081 };
  1082 
  1083 static Uint8 *
  1084 EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
  1085 {
  1086     Uint8 *ptr;
  1087     size_t offset;
  1088 
  1089     if (stream->work_buffer_len >= newlen) {
  1090         ptr = stream->work_buffer_base;
  1091     } else {
  1092         ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
  1093         if (!ptr) {
  1094             SDL_OutOfMemory();
  1095             return NULL;
  1096         }
  1097         /* Make sure we're aligned to 16 bytes for SIMD code. */
  1098         stream->work_buffer_base = ptr;
  1099         stream->work_buffer_len = newlen;
  1100     }
  1101 
  1102     offset = ((size_t) ptr) & 15;
  1103     return offset ? ptr + (16 - offset) : ptr;
  1104 }
  1105 
  1106 #ifdef HAVE_LIBSAMPLERATE_H
  1107 static int
  1108 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1109 {
  1110     const float *inbuf = (const float *) _inbuf;
  1111     float *outbuf = (float *) _outbuf;
  1112     const int framelen = sizeof(float) * stream->pre_resample_channels;
  1113     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1114     SRC_DATA data;
  1115     int result;
  1116 
  1117     if (inbuf == ((const float *) outbuf)) {  /* libsamplerate can't work in-place. */
  1118         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1119         if (ptr == NULL) {
  1120             SDL_OutOfMemory();
  1121             return 0;
  1122         }
  1123         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1124         inbuf = (const float *) (ptr + outbuflen);
  1125         outbuf = (float *) ptr;
  1126     }
  1127 
  1128     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
  1129     data.input_frames = inbuflen / framelen;
  1130     data.input_frames_used = 0;
  1131 
  1132     data.data_out = outbuf;
  1133     data.output_frames = outbuflen / framelen;
  1134 
  1135     data.end_of_input = 0;
  1136     data.src_ratio = stream->rate_incr;
  1137 
  1138     result = SRC_src_process(state, &data);
  1139     if (result != 0) {
  1140         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
  1141         return 0;
  1142     }
  1143 
  1144     /* If this fails, we need to store them off somewhere */
  1145     SDL_assert(data.input_frames_used == data.input_frames);
  1146 
  1147     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
  1148 }
  1149 
  1150 static void
  1151 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1152 {
  1153     SRC_src_reset((SRC_STATE *)stream->resampler_state);
  1154 }
  1155 
  1156 static void
  1157 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1158 {
  1159     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1160     if (state) {
  1161         SRC_src_delete(state);
  1162     }
  1163 
  1164     stream->resampler_state = NULL;
  1165     stream->resampler_func = NULL;
  1166     stream->reset_resampler_func = NULL;
  1167     stream->cleanup_resampler_func = NULL;
  1168 }
  1169 
  1170 static SDL_bool
  1171 SetupLibSampleRateResampling(SDL_AudioStream *stream)
  1172 {
  1173     int result = 0;
  1174     SRC_STATE *state = NULL;
  1175 
  1176     if (SRC_available) {
  1177         state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
  1178         if (!state) {
  1179             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
  1180         }
  1181     }
  1182 
  1183     if (!state) {
  1184         SDL_CleanupAudioStreamResampler_SRC(stream);
  1185         return SDL_FALSE;
  1186     }
  1187 
  1188     stream->resampler_state = state;
  1189     stream->resampler_func = SDL_ResampleAudioStream_SRC;
  1190     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
  1191     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
  1192 
  1193     return SDL_TRUE;
  1194 }
  1195 #endif /* HAVE_LIBSAMPLERATE_H */
  1196 
  1197 
  1198 typedef struct
  1199 {
  1200     SDL_bool resampler_seeded;
  1201     union
  1202     {
  1203         float f[8];
  1204         Sint16 si16[2];
  1205     } resampler_state;
  1206 } SDL_AudioStreamResamplerState;
  1207 
  1208 static int
  1209 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1210 {
  1211     const float *inbuf = (const float *) _inbuf;
  1212     float *outbuf = (float *) _outbuf;
  1213     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1214     const int chans = (int)stream->pre_resample_channels;
  1215 
  1216     SDL_assert(chans <= SDL_arraysize(state->resampler_state.f));
  1217 
  1218     if (inbuf == ((const float *) outbuf)) {  /* !!! FIXME can't work in-place (for now!). */
  1219         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1220         if (ptr == NULL) {
  1221             SDL_OutOfMemory();
  1222             return 0;
  1223         }
  1224         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1225         inbuf = (const float *) (ptr + outbuflen);
  1226         outbuf = (float *) ptr;
  1227     }
  1228 
  1229     if (!state->resampler_seeded) {
  1230         SDL_zero(state->resampler_state.f);
  1231         state->resampler_seeded = SDL_TRUE;
  1232     }
  1233 
  1234     return SDL_ResampleAudio(chans, stream->src_rate, stream->dst_rate, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
  1235 }
  1236 
  1237 static void
  1238 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1239 {
  1240     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
  1241     state->resampler_seeded = SDL_FALSE;
  1242 }
  1243 
  1244 static void
  1245 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1246 {
  1247     SDL_free(stream->resampler_state);
  1248 }
  1249 
  1250 SDL_AudioStream *
  1251 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1252                    const Uint8 src_channels,
  1253                    const int src_rate,
  1254                    const SDL_AudioFormat dst_format,
  1255                    const Uint8 dst_channels,
  1256                    const int dst_rate)
  1257 {
  1258     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1259     Uint8 pre_resample_channels;
  1260     SDL_AudioStream *retval;
  1261 
  1262     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1263     if (!retval) {
  1264         return NULL;
  1265     }
  1266 
  1267     /* If increasing channels, do it after resampling, since we'd just
  1268        do more work to resample duplicate channels. If we're decreasing, do
  1269        it first so we resample the interpolated data instead of interpolating
  1270        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1271     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1272 
  1273     retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
  1274     retval->src_format = src_format;
  1275     retval->src_channels = src_channels;
  1276     retval->src_rate = src_rate;
  1277     retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
  1278     retval->dst_format = dst_format;
  1279     retval->dst_channels = dst_channels;
  1280     retval->dst_rate = dst_rate;
  1281     retval->pre_resample_channels = pre_resample_channels;
  1282     retval->packetlen = packetlen;
  1283     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1284 
  1285     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1286     if (src_rate == dst_rate) {
  1287         retval->cvt_before_resampling.needed = SDL_FALSE;
  1288         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1289             SDL_FreeAudioStream(retval);
  1290             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1291         }
  1292     } else {
  1293         /* Don't resample at first. Just get us to Float32 format. */
  1294         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1295         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1296             SDL_FreeAudioStream(retval);
  1297             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1298         }
  1299 
  1300 #ifdef HAVE_LIBSAMPLERATE_H
  1301         SetupLibSampleRateResampling(retval);
  1302 #endif
  1303 
  1304         if (!retval->resampler_func) {
  1305             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
  1306             if (!retval->resampler_state) {
  1307                 SDL_FreeAudioStream(retval);
  1308                 SDL_OutOfMemory();
  1309                 return NULL;
  1310             }
  1311 
  1312             if (SDL_PrepareResampleFilter() < 0) {
  1313                 SDL_free(retval->resampler_state);
  1314                 retval->resampler_state = NULL;
  1315                 SDL_FreeAudioStream(retval);
  1316                 return NULL;
  1317             }
  1318 
  1319             retval->resampler_func = SDL_ResampleAudioStream;
  1320             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1321             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1322         }
  1323 
  1324         /* Convert us to the final format after resampling. */
  1325         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1326             SDL_FreeAudioStream(retval);
  1327             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1328         }
  1329     }
  1330 
  1331     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1332     if (!retval->queue) {
  1333         SDL_FreeAudioStream(retval);
  1334         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1335     }
  1336 
  1337     return retval;
  1338 }
  1339 
  1340 int
  1341 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1342 {
  1343     int buflen = (int) _buflen;
  1344     const void *origbuf = buf;
  1345 
  1346     /* !!! FIXME: several converters can take advantage of SIMD, but only
  1347        !!! FIXME:  if the data is aligned to 16 bytes. EnsureStreamBufferSize()
  1348        !!! FIXME:  guarantees the buffer will align, but the
  1349        !!! FIXME:  converters will iterate over the data backwards if
  1350        !!! FIXME:  the output grows, and this means we won't align if buflen
  1351        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1352        !!! FIXME:  a few samples at the end and convert them separately. */
  1353 
  1354     if (!stream) {
  1355         return SDL_InvalidParamError("stream");
  1356     } else if (!buf) {
  1357         return SDL_InvalidParamError("buf");
  1358     } else if (buflen == 0) {
  1359         return 0;  /* nothing to do. */
  1360     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1361         return SDL_SetError("Can't add partial sample frames");
  1362     }
  1363 
  1364     if (stream->cvt_before_resampling.needed) {
  1365         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1366         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1367         if (workbuf == NULL) {
  1368             return -1;  /* probably out of memory. */
  1369         }
  1370         SDL_assert(buf == origbuf);
  1371         SDL_memcpy(workbuf, buf, buflen);
  1372         stream->cvt_before_resampling.buf = workbuf;
  1373         stream->cvt_before_resampling.len = buflen;
  1374         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1375             return -1;   /* uhoh! */
  1376         }
  1377         buf = workbuf;
  1378         buflen = stream->cvt_before_resampling.len_cvt;
  1379     }
  1380 
  1381     if (stream->dst_rate != stream->src_rate) {
  1382         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1383         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1384         if (workbuf == NULL) {
  1385             return -1;  /* probably out of memory. */
  1386         }
  1387         /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
  1388            libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
  1389         if (buf != origbuf) {
  1390             buf = workbuf;  /* in case we realloc()'d the pointer. */
  1391         }
  1392         buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
  1393         buf = EnsureStreamBufferSize(stream, workbuflen);
  1394         SDL_assert(buf != NULL);  /* shouldn't be growing, just aligning. */
  1395     }
  1396 
  1397     if (stream->cvt_after_resampling.needed) {
  1398         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1399         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1400         if (workbuf == NULL) {
  1401             return -1;  /* probably out of memory. */
  1402         }
  1403         if (buf == origbuf) {  /* copy if we haven't before. */
  1404             SDL_memcpy(workbuf, origbuf, buflen);
  1405         }
  1406         stream->cvt_after_resampling.buf = workbuf;
  1407         stream->cvt_after_resampling.len = buflen;
  1408         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1409             return -1;   /* uhoh! */
  1410         }
  1411         buf = workbuf;
  1412         buflen = stream->cvt_after_resampling.len_cvt;
  1413     }
  1414 
  1415     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1416 }
  1417 
  1418 void
  1419 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1420 {
  1421     if (!stream) {
  1422         SDL_InvalidParamError("stream");
  1423     } else {
  1424         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1425         if (stream->reset_resampler_func) {
  1426             stream->reset_resampler_func(stream);
  1427         }
  1428     }
  1429 }
  1430 
  1431 
  1432 /* get converted/resampled data from the stream */
  1433 int
  1434 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1435 {
  1436     if (!stream) {
  1437         return SDL_InvalidParamError("stream");
  1438     } else if (!buf) {
  1439         return SDL_InvalidParamError("buf");
  1440     } else if (len == 0) {
  1441         return 0;  /* nothing to do. */
  1442     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1443         return SDL_SetError("Can't request partial sample frames");
  1444     }
  1445 
  1446     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1447 }
  1448 
  1449 /* number of converted/resampled bytes available */
  1450 int
  1451 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1452 {
  1453     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1454 }
  1455 
  1456 /* dispose of a stream */
  1457 void
  1458 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1459 {
  1460     if (stream) {
  1461         if (stream->cleanup_resampler_func) {
  1462             stream->cleanup_resampler_func(stream);
  1463         }
  1464         SDL_FreeDataQueue(stream->queue);
  1465         SDL_free(stream->work_buffer_base);
  1466         SDL_free(stream);
  1467     }
  1468 }
  1469 
  1470 /* vi: set ts=4 sw=4 expandtab: */
  1471