src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 10 Oct 2017 22:31:02 -0400
changeset 11586 f882930f174f
parent 11585 9b646e8f4622
child 11590 ca6aa7f5488d
permissions -rw-r--r--
audio: SDL_ResampleCVT() should use memmove instead of memcpy.

This copy can overlap.

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