src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 18 Aug 2017 16:52:19 -0400
changeset 11319 86b1fde471c6
parent 11128 9dda3f3e9794
child 11405 4e12f78c2b0e
permissions -rw-r--r--
audio: better docs on conversion APIs, error if not init'd (thanks, Simon!).

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