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