src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 29 Aug 2017 00:41:45 -0400
changeset 11405 4e12f78c2b0e
parent 11319 86b1fde471c6
child 11406 f40c2dedaded
permissions -rw-r--r--
audio: A whole bunch of improvements to audio conversion (thanks, Solra!).

"Major changes, roughly in order of appearance:

- Use float math everywhere, instead of promoting to double and casting back
all the time.
- Conserve sound energy when downmixing any channel into two other channels.
- Add a QuadToStereo filter. (The previous technique of reusing StereoToMono
never worked, since it assumed an incorrect channel layout for 4.0.)
- Add a 71to51 filter. This removes just under half of the cases the previous
code would silently break in.
- Add a QuadTo51 filter. More silent breakage fixed.
- Add a 51to71 filter, removing another almost-half of the silently broken
cases.
- Add 8 to the list of values SDL_SupportedChannelCount will accept.
- Change SDL_BuildAudioCVT's channel-related logic to handle every case, and
to actually fail if it fails instead of silently corrupting sound data and/or
crashing down the road."

(Note that SDL doesn't otherwise support 7.1 audio yet, but hopefully it will
soon and the 7.1 converters are an important piece of that. --ryan.)

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