src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 10 Oct 2017 16:12:56 -0400
changeset 11583 c48ab2c208a2
parent 11541 433786fcf04a
child 11585 9b646e8f4622
permissions -rw-r--r--
audio: reworked audio streams to have right-hand resampling padding available.

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