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