src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 22 Sep 2017 22:28:21 -0400
changeset 11541 433786fcf04a
parent 11519 535b0c8ba4ce
child 11583 c48ab2c208a2
permissions -rw-r--r--
audio: Fixed compiler warning on Visual Studio.
     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 = (int) (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;
   713 
   714     SDL_assert(format == AUDIO_F32SYS);
   715 
   716     /* we keep no streaming state here, so pad with silence on both ends. */
   717     padding = SDL_stack_alloc(float, paddingsamples);
   718     if (!padding) {
   719         SDL_OutOfMemory();
   720         return;
   721     }
   722     SDL_memset(padding, '\0', paddingsamples * sizeof (float));
   723 
   724     cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
   725 
   726     SDL_stack_free(padding);
   727 
   728     SDL_memcpy(cvt->buf, dst, cvt->len_cvt);  /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   729 
   730     if (cvt->filters[++cvt->filter_index]) {
   731         cvt->filters[cvt->filter_index](cvt, format);
   732     }
   733 }
   734 
   735 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   736    !!! FIXME:  store channel info, so we have to have function entry
   737    !!! FIXME:  points for each supported channel count and multiple
   738    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   739 #define RESAMPLER_FUNCS(chans) \
   740     static void SDLCALL \
   741     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   742         SDL_ResampleCVT(cvt, chans, format); \
   743     }
   744 RESAMPLER_FUNCS(1)
   745 RESAMPLER_FUNCS(2)
   746 RESAMPLER_FUNCS(4)
   747 RESAMPLER_FUNCS(6)
   748 RESAMPLER_FUNCS(8)
   749 #undef RESAMPLER_FUNCS
   750 
   751 static SDL_AudioFilter
   752 ChooseCVTResampler(const int dst_channels)
   753 {
   754     switch (dst_channels) {
   755         case 1: return SDL_ResampleCVT_c1;
   756         case 2: return SDL_ResampleCVT_c2;
   757         case 4: return SDL_ResampleCVT_c4;
   758         case 6: return SDL_ResampleCVT_c6;
   759         case 8: return SDL_ResampleCVT_c8;
   760         default: break;
   761     }
   762 
   763     return NULL;
   764 }
   765 
   766 static int
   767 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   768                           const int src_rate, const int dst_rate)
   769 {
   770     SDL_AudioFilter filter;
   771 
   772     if (src_rate == dst_rate) {
   773         return 0;  /* no conversion necessary. */
   774     }
   775 
   776     filter = ChooseCVTResampler(dst_channels);
   777     if (filter == NULL) {
   778         return SDL_SetError("No conversion available for these rates");
   779     }
   780 
   781     if (SDL_PrepareResampleFilter() < 0) {
   782         return -1;
   783     }
   784 
   785     /* Update (cvt) with filter details... */
   786     if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
   787         return -1;
   788     }
   789 
   790     /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
   791        !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
   792        !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
   793     if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
   794         return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
   795     }
   796     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
   797     cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
   798 
   799     if (src_rate < dst_rate) {
   800         const double mult = ((double) dst_rate) / ((double) src_rate);
   801         cvt->len_mult *= (int) SDL_ceil(mult);
   802         cvt->len_ratio *= mult;
   803     } else {
   804         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   805     }
   806 
   807     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
   808     /* the buffer is big enough to hold the destination now, but
   809        we need it large enough to hold a separate scratch buffer. */
   810     cvt->len_mult *= 2;
   811 
   812     return 1;               /* added a converter. */
   813 }
   814 
   815 static SDL_bool
   816 SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
   817 {
   818     switch (fmt) {
   819         case AUDIO_U8:
   820         case AUDIO_S8:
   821         case AUDIO_U16LSB:
   822         case AUDIO_S16LSB:
   823         case AUDIO_U16MSB:
   824         case AUDIO_S16MSB:
   825         case AUDIO_S32LSB:
   826         case AUDIO_S32MSB:
   827         case AUDIO_F32LSB:
   828         case AUDIO_F32MSB:
   829             return SDL_TRUE;  /* supported. */
   830 
   831         default:
   832             break;
   833     }
   834 
   835     return SDL_FALSE;  /* unsupported. */
   836 }
   837 
   838 static SDL_bool
   839 SDL_SupportedChannelCount(const int channels)
   840 {
   841     switch (channels) {
   842         case 1:  /* mono */
   843         case 2:  /* stereo */
   844         case 4:  /* quad */
   845         case 6:  /* 5.1 */
   846         case 8:  /* 7.1 */
   847           return SDL_TRUE;  /* supported. */
   848 
   849         default:
   850             break;
   851     }
   852 
   853     return SDL_FALSE;  /* unsupported. */
   854 }
   855 
   856 
   857 /* Creates a set of audio filters to convert from one format to another.
   858    Returns 0 if no conversion is needed, 1 if the audio filter is set up,
   859    or -1 if an error like invalid parameter, unsupported format, etc. occurred.
   860 */
   861 
   862 int
   863 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   864                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   865                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   866 {
   867     /* Sanity check target pointer */
   868     if (cvt == NULL) {
   869         return SDL_InvalidParamError("cvt");
   870     }
   871 
   872     /* Make sure we zero out the audio conversion before error checking */
   873     SDL_zerop(cvt);
   874 
   875     if (!SDL_SupportedAudioFormat(src_fmt)) {
   876         return SDL_SetError("Invalid source format");
   877     } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
   878         return SDL_SetError("Invalid destination format");
   879     } else if (!SDL_SupportedChannelCount(src_channels)) {
   880         return SDL_SetError("Invalid source channels");
   881     } else if (!SDL_SupportedChannelCount(dst_channels)) {
   882         return SDL_SetError("Invalid destination channels");
   883     } else if (src_rate == 0) {
   884         return SDL_SetError("Source rate is zero");
   885     } else if (dst_rate == 0) {
   886         return SDL_SetError("Destination rate is zero");
   887     }
   888 
   889 #if DEBUG_CONVERT
   890     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   891            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   892 #endif
   893 
   894     /* Start off with no conversion necessary */
   895     cvt->src_format = src_fmt;
   896     cvt->dst_format = dst_fmt;
   897     cvt->needed = 0;
   898     cvt->filter_index = 0;
   899     SDL_zero(cvt->filters);
   900     cvt->len_mult = 1;
   901     cvt->len_ratio = 1.0;
   902     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   903 
   904     /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
   905     SDL_ChooseAudioConverters();
   906 
   907     /* Type conversion goes like this now:
   908         - byteswap to CPU native format first if necessary.
   909         - convert to native Float32 if necessary.
   910         - resample and change channel count if necessary.
   911         - convert back to native format.
   912         - byteswap back to foreign format if necessary.
   913 
   914        The expectation is we can process data faster in float32
   915        (possibly with SIMD), and making several passes over the same
   916        buffer is likely to be CPU cache-friendly, avoiding the
   917        biggest performance hit in modern times. Previously we had
   918        (script-generated) custom converters for every data type and
   919        it was a bloat on SDL compile times and final library size. */
   920 
   921     /* see if we can skip float conversion entirely. */
   922     if (src_rate == dst_rate && src_channels == dst_channels) {
   923         if (src_fmt == dst_fmt) {
   924             return 0;
   925         }
   926 
   927         /* just a byteswap needed? */
   928         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   929             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
   930                 return -1;
   931             }
   932             cvt->needed = 1;
   933             return 1;
   934         }
   935     }
   936 
   937     /* Convert data types, if necessary. Updates (cvt). */
   938     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   939         return -1;              /* shouldn't happen, but just in case... */
   940     }
   941 
   942     /* Channel conversion */
   943     if (src_channels < dst_channels) {
   944         /* Upmixing */
   945         /* Mono -> Stereo [-> ...] */
   946         if ((src_channels == 1) && (dst_channels > 1)) {
   947             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
   948                 return -1;
   949             }
   950             cvt->len_mult *= 2;
   951             src_channels = 2;
   952             cvt->len_ratio *= 2;
   953         }
   954         /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
   955         if ((src_channels == 2) && (dst_channels >= 6)) {
   956             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
   957                 return -1;
   958             }
   959             src_channels = 6;
   960             cvt->len_mult *= 3;
   961             cvt->len_ratio *= 3;
   962         }
   963         /* Quad -> 5.1 [-> 7.1] */
   964         if ((src_channels == 4) && (dst_channels >= 6)) {
   965             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
   966                 return -1;
   967             }
   968             src_channels = 6;
   969             cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
   970             cvt->len_ratio *= 1.5;
   971         }
   972         /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
   973         if ((src_channels == 6) && (dst_channels == 8)) {
   974             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
   975                 return -1;
   976             }
   977             src_channels = 8;
   978             cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
   979             /* Should be numerically exact with every valid input to this
   980                function */
   981             cvt->len_ratio = cvt->len_ratio * 4 / 3;
   982         }
   983         /* [Mono ->] Stereo -> Quad */
   984         if ((src_channels == 2) && (dst_channels == 4)) {
   985             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
   986                 return -1;
   987             }
   988             src_channels = 4;
   989             cvt->len_mult *= 2;
   990             cvt->len_ratio *= 2;
   991         }
   992     } else if (src_channels > dst_channels) {
   993         /* Downmixing */
   994         /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
   995         /* 7.1 -> 5.1 [-> Quad] */
   996         if ((src_channels == 8) && (dst_channels <= 6)) {
   997             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
   998                 return -1;
   999             }
  1000             src_channels = 6;
  1001             cvt->len_ratio *= 0.75;
  1002         }
  1003         /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
  1004         if ((src_channels == 6) && (dst_channels <= 2)) {
  1005             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
  1006                 return -1;
  1007             }
  1008             src_channels = 2;
  1009             cvt->len_ratio /= 3;
  1010         }
  1011         /* 5.1 -> Quad */
  1012         if ((src_channels == 6) && (dst_channels == 4)) {
  1013             if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
  1014                 return -1;
  1015             }
  1016             src_channels = 4;
  1017             cvt->len_ratio = cvt->len_ratio * 2 / 3;
  1018         }
  1019         /* Quad -> Stereo [-> Mono] */
  1020         if ((src_channels == 4) && (dst_channels <= 2)) {
  1021             if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
  1022                 return -1;
  1023             }
  1024             src_channels = 2;
  1025             cvt->len_ratio /= 2;
  1026         }
  1027         /* [... ->] Stereo -> Mono */
  1028         if ((src_channels == 2) && (dst_channels == 1)) {
  1029             SDL_AudioFilter filter = NULL;
  1030 
  1031             #if HAVE_SSE3_INTRINSICS
  1032             if (SDL_HasSSE3()) {
  1033                 filter = SDL_ConvertStereoToMono_SSE3;
  1034             }
  1035             #endif
  1036 
  1037             if (!filter) {
  1038                 filter = SDL_ConvertStereoToMono;
  1039             }
  1040 
  1041             if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
  1042                 return -1;
  1043             }
  1044 
  1045             src_channels = 1;
  1046             cvt->len_ratio /= 2;
  1047         }
  1048     }
  1049 
  1050     if (src_channels != dst_channels) {
  1051         /* All combinations of supported channel counts should have been
  1052            handled by now, but let's be defensive */
  1053       return SDL_SetError("Invalid channel combination");
  1054     }
  1055     
  1056     /* Do rate conversion, if necessary. Updates (cvt). */
  1057     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
  1058         return -1;              /* shouldn't happen, but just in case... */
  1059     }
  1060 
  1061     /* Move to final data type. */
  1062     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
  1063         return -1;              /* shouldn't happen, but just in case... */
  1064     }
  1065 
  1066     cvt->needed = (cvt->filter_index != 0);
  1067     return (cvt->needed);
  1068 }
  1069 
  1070 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
  1071 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1072 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
  1073 
  1074 struct SDL_AudioStream
  1075 {
  1076     SDL_AudioCVT cvt_before_resampling;
  1077     SDL_AudioCVT cvt_after_resampling;
  1078     SDL_DataQueue *queue;
  1079     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
  1080     int work_buffer_len;
  1081     int src_sample_frame_size;
  1082     SDL_AudioFormat src_format;
  1083     Uint8 src_channels;
  1084     int src_rate;
  1085     int dst_sample_frame_size;
  1086     SDL_AudioFormat dst_format;
  1087     Uint8 dst_channels;
  1088     int dst_rate;
  1089     double rate_incr;
  1090     Uint8 pre_resample_channels;
  1091     int packetlen;
  1092     void *resampler_state;
  1093     SDL_ResampleAudioStreamFunc resampler_func;
  1094     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
  1095     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
  1096 };
  1097 
  1098 static Uint8 *
  1099 EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
  1100 {
  1101     Uint8 *ptr;
  1102     size_t offset;
  1103 
  1104     if (stream->work_buffer_len >= newlen) {
  1105         ptr = stream->work_buffer_base;
  1106     } else {
  1107         ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
  1108         if (!ptr) {
  1109             SDL_OutOfMemory();
  1110             return NULL;
  1111         }
  1112         /* Make sure we're aligned to 16 bytes for SIMD code. */
  1113         stream->work_buffer_base = ptr;
  1114         stream->work_buffer_len = newlen;
  1115     }
  1116 
  1117     offset = ((size_t) ptr) & 15;
  1118     return offset ? ptr + (16 - offset) : ptr;
  1119 }
  1120 
  1121 #ifdef HAVE_LIBSAMPLERATE_H
  1122 static int
  1123 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1124 {
  1125     const float *inbuf = (const float *) _inbuf;
  1126     float *outbuf = (float *) _outbuf;
  1127     const int framelen = sizeof(float) * stream->pre_resample_channels;
  1128     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1129     SRC_DATA data;
  1130     int result;
  1131 
  1132     if (inbuf == ((const float *) outbuf)) {  /* libsamplerate can't work in-place. */
  1133         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1134         if (ptr == NULL) {
  1135             SDL_OutOfMemory();
  1136             return 0;
  1137         }
  1138         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1139         inbuf = (const float *) (ptr + outbuflen);
  1140         outbuf = (float *) ptr;
  1141     }
  1142 
  1143     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
  1144     data.input_frames = inbuflen / framelen;
  1145     data.input_frames_used = 0;
  1146 
  1147     data.data_out = outbuf;
  1148     data.output_frames = outbuflen / framelen;
  1149 
  1150     data.end_of_input = 0;
  1151     data.src_ratio = stream->rate_incr;
  1152 
  1153     result = SRC_src_process(state, &data);
  1154     if (result != 0) {
  1155         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
  1156         return 0;
  1157     }
  1158 
  1159     /* If this fails, we need to store them off somewhere */
  1160     SDL_assert(data.input_frames_used == data.input_frames);
  1161 
  1162     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
  1163 }
  1164 
  1165 static void
  1166 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1167 {
  1168     SRC_src_reset((SRC_STATE *)stream->resampler_state);
  1169 }
  1170 
  1171 static void
  1172 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
  1173 {
  1174     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
  1175     if (state) {
  1176         SRC_src_delete(state);
  1177     }
  1178 
  1179     stream->resampler_state = NULL;
  1180     stream->resampler_func = NULL;
  1181     stream->reset_resampler_func = NULL;
  1182     stream->cleanup_resampler_func = NULL;
  1183 }
  1184 
  1185 static SDL_bool
  1186 SetupLibSampleRateResampling(SDL_AudioStream *stream)
  1187 {
  1188     int result = 0;
  1189     SRC_STATE *state = NULL;
  1190 
  1191     if (SRC_available) {
  1192         state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
  1193         if (!state) {
  1194             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
  1195         }
  1196     }
  1197 
  1198     if (!state) {
  1199         SDL_CleanupAudioStreamResampler_SRC(stream);
  1200         return SDL_FALSE;
  1201     }
  1202 
  1203     stream->resampler_state = state;
  1204     stream->resampler_func = SDL_ResampleAudioStream_SRC;
  1205     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
  1206     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
  1207 
  1208     return SDL_TRUE;
  1209 }
  1210 #endif /* HAVE_LIBSAMPLERATE_H */
  1211 
  1212 
  1213 static int
  1214 SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
  1215 {
  1216     const float *inbuf = (const float *) _inbuf;
  1217     float *outbuf = (float *) _outbuf;
  1218     const int chans = (int) stream->pre_resample_channels;
  1219     const int inrate = stream->src_rate;
  1220     const int outrate = stream->dst_rate;
  1221     const int paddingsamples = ResamplerPadding(inrate, outrate) * chans;
  1222     const int paddingbytes = paddingsamples * sizeof (float);
  1223     float *lpadding = (float *) stream->resampler_state;
  1224     float *rpadding;
  1225     int retval;
  1226 
  1227     if (inbuf == ((const float *) outbuf)) {  /* !!! FIXME can't work in-place (for now!). */
  1228         Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
  1229         if (ptr == NULL) {
  1230             SDL_OutOfMemory();
  1231             return 0;
  1232         }
  1233         SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
  1234         inbuf = (const float *) (ptr + outbuflen);
  1235         outbuf = (float *) ptr;
  1236     }
  1237 
  1238     /* !!! 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. */
  1239     rpadding = SDL_stack_alloc(float, paddingsamples);
  1240     if (!rpadding) {
  1241         SDL_OutOfMemory();
  1242         return 0;
  1243     }
  1244     SDL_memset(rpadding, '\0', paddingbytes);
  1245 
  1246     retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
  1247 
  1248     SDL_stack_free(rpadding);
  1249 
  1250     /* update our left padding with end of current input, for next run. */
  1251     SDL_memcpy(lpadding, ((const Uint8 *) inbuf) + (inbuflen - paddingbytes), paddingbytes);
  1252 
  1253     return retval;
  1254 }
  1255 
  1256 static void
  1257 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
  1258 {
  1259     /* set all the left padding to silence. */
  1260     const int inrate = stream->src_rate;
  1261     const int outrate = stream->dst_rate;
  1262     const int chans = (int) stream->pre_resample_channels;
  1263     const int len = ResamplerPadding(inrate, outrate) * chans;
  1264     SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
  1265 }
  1266 
  1267 static void
  1268 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
  1269 {
  1270     SDL_free(stream->resampler_state);
  1271 }
  1272 
  1273 SDL_AudioStream *
  1274 SDL_NewAudioStream(const SDL_AudioFormat src_format,
  1275                    const Uint8 src_channels,
  1276                    const int src_rate,
  1277                    const SDL_AudioFormat dst_format,
  1278                    const Uint8 dst_channels,
  1279                    const int dst_rate)
  1280 {
  1281     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
  1282     Uint8 pre_resample_channels;
  1283     SDL_AudioStream *retval;
  1284 
  1285     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
  1286     if (!retval) {
  1287         return NULL;
  1288     }
  1289 
  1290     /* If increasing channels, do it after resampling, since we'd just
  1291        do more work to resample duplicate channels. If we're decreasing, do
  1292        it first so we resample the interpolated data instead of interpolating
  1293        the resampled data (!!! FIXME: decide if that works in practice, though!). */
  1294     pre_resample_channels = SDL_min(src_channels, dst_channels);
  1295 
  1296     retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
  1297     retval->src_format = src_format;
  1298     retval->src_channels = src_channels;
  1299     retval->src_rate = src_rate;
  1300     retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
  1301     retval->dst_format = dst_format;
  1302     retval->dst_channels = dst_channels;
  1303     retval->dst_rate = dst_rate;
  1304     retval->pre_resample_channels = pre_resample_channels;
  1305     retval->packetlen = packetlen;
  1306     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1307 
  1308     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1309     if (src_rate == dst_rate) {
  1310         retval->cvt_before_resampling.needed = SDL_FALSE;
  1311         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1312             SDL_FreeAudioStream(retval);
  1313             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1314         }
  1315     } else {
  1316         /* Don't resample at first. Just get us to Float32 format. */
  1317         /* !!! FIXME: convert to int32 on devices without hardware float. */
  1318         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
  1319             SDL_FreeAudioStream(retval);
  1320             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1321         }
  1322 
  1323 #ifdef HAVE_LIBSAMPLERATE_H
  1324         SetupLibSampleRateResampling(retval);
  1325 #endif
  1326 
  1327         if (!retval->resampler_func) {
  1328             const int chans = (int) pre_resample_channels;
  1329             const int len = ResamplerPadding(src_rate, dst_rate) * chans;
  1330             retval->resampler_state = SDL_calloc(len, sizeof (float));
  1331             if (!retval->resampler_state) {
  1332                 SDL_FreeAudioStream(retval);
  1333                 SDL_OutOfMemory();
  1334                 return NULL;
  1335             }
  1336 
  1337             if (SDL_PrepareResampleFilter() < 0) {
  1338                 SDL_free(retval->resampler_state);
  1339                 retval->resampler_state = NULL;
  1340                 SDL_FreeAudioStream(retval);
  1341                 return NULL;
  1342             }
  1343 
  1344             retval->resampler_func = SDL_ResampleAudioStream;
  1345             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
  1346             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
  1347         }
  1348 
  1349         /* Convert us to the final format after resampling. */
  1350         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1351             SDL_FreeAudioStream(retval);
  1352             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1353         }
  1354     }
  1355 
  1356     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
  1357     if (!retval->queue) {
  1358         SDL_FreeAudioStream(retval);
  1359         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
  1360     }
  1361 
  1362     return retval;
  1363 }
  1364 
  1365 int
  1366 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
  1367 {
  1368     int buflen = (int) _buflen;
  1369     const void *origbuf = buf;
  1370 
  1371     /* !!! FIXME: several converters can take advantage of SIMD, but only
  1372        !!! FIXME:  if the data is aligned to 16 bytes. EnsureStreamBufferSize()
  1373        !!! FIXME:  guarantees the buffer will align, but the
  1374        !!! FIXME:  converters will iterate over the data backwards if
  1375        !!! FIXME:  the output grows, and this means we won't align if buflen
  1376        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1377        !!! FIXME:  a few samples at the end and convert them separately. */
  1378 
  1379     if (!stream) {
  1380         return SDL_InvalidParamError("stream");
  1381     } else if (!buf) {
  1382         return SDL_InvalidParamError("buf");
  1383     } else if (buflen == 0) {
  1384         return 0;  /* nothing to do. */
  1385     } else if ((buflen % stream->src_sample_frame_size) != 0) {
  1386         return SDL_SetError("Can't add partial sample frames");
  1387     }
  1388 
  1389     if (stream->cvt_before_resampling.needed) {
  1390         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
  1391         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1392         if (workbuf == NULL) {
  1393             return -1;  /* probably out of memory. */
  1394         }
  1395         SDL_assert(buf == origbuf);
  1396         SDL_memcpy(workbuf, buf, buflen);
  1397         stream->cvt_before_resampling.buf = workbuf;
  1398         stream->cvt_before_resampling.len = buflen;
  1399         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
  1400             return -1;   /* uhoh! */
  1401         }
  1402         buf = workbuf;
  1403         buflen = stream->cvt_before_resampling.len_cvt;
  1404     }
  1405 
  1406     if (stream->dst_rate != stream->src_rate) {
  1407         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
  1408         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1409         if (workbuf == NULL) {
  1410             return -1;  /* probably out of memory. */
  1411         }
  1412         /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
  1413            libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
  1414         if (buf != origbuf) {
  1415             buf = workbuf;  /* in case we realloc()'d the pointer. */
  1416         }
  1417         buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
  1418         buf = EnsureStreamBufferSize(stream, workbuflen);
  1419         SDL_assert(buf != NULL);  /* shouldn't be growing, just aligning. */
  1420     }
  1421 
  1422     if (stream->cvt_after_resampling.needed) {
  1423         const int workbuflen = buflen * stream->cvt_after_resampling.len_mult;  /* will be "* 1" if not needed */
  1424         Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
  1425         if (workbuf == NULL) {
  1426             return -1;  /* probably out of memory. */
  1427         }
  1428         if (buf == origbuf) {  /* copy if we haven't before. */
  1429             SDL_memcpy(workbuf, origbuf, buflen);
  1430         }
  1431         stream->cvt_after_resampling.buf = workbuf;
  1432         stream->cvt_after_resampling.len = buflen;
  1433         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
  1434             return -1;   /* uhoh! */
  1435         }
  1436         buf = workbuf;
  1437         buflen = stream->cvt_after_resampling.len_cvt;
  1438     }
  1439 
  1440     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
  1441 }
  1442 
  1443 void
  1444 SDL_AudioStreamClear(SDL_AudioStream *stream)
  1445 {
  1446     if (!stream) {
  1447         SDL_InvalidParamError("stream");
  1448     } else {
  1449         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
  1450         if (stream->reset_resampler_func) {
  1451             stream->reset_resampler_func(stream);
  1452         }
  1453     }
  1454 }
  1455 
  1456 
  1457 /* get converted/resampled data from the stream */
  1458 int
  1459 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
  1460 {
  1461     if (!stream) {
  1462         return SDL_InvalidParamError("stream");
  1463     } else if (!buf) {
  1464         return SDL_InvalidParamError("buf");
  1465     } else if (len == 0) {
  1466         return 0;  /* nothing to do. */
  1467     } else if ((len % stream->dst_sample_frame_size) != 0) {
  1468         return SDL_SetError("Can't request partial sample frames");
  1469     }
  1470 
  1471     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
  1472 }
  1473 
  1474 /* number of converted/resampled bytes available */
  1475 int
  1476 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
  1477 {
  1478     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
  1479 }
  1480 
  1481 /* dispose of a stream */
  1482 void
  1483 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1484 {
  1485     if (stream) {
  1486         if (stream->cleanup_resampler_func) {
  1487             stream->cleanup_resampler_func(stream);
  1488         }
  1489         SDL_FreeDataQueue(stream->queue);
  1490         SDL_free(stream->work_buffer_base);
  1491         SDL_free(stream);
  1492     }
  1493 }
  1494 
  1495 /* vi: set ts=4 sw=4 expandtab: */
  1496