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