sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_audiocvt.c (58724B)


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