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