src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Jan 2017 06:00:58 -0500
changeset 10799 234f71894a52
parent 10793 7e657de3758d
child 10804 1502bb751ca4
permissions -rw-r--r--
audio: Replaced older resamplers in SDL_AudioCVT with the new ones.
     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 
    32 /* Effectively mix right and left channels into a single channel */
    33 static void SDLCALL
    34 SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    35 {
    36     float *dst = (float *) cvt->buf;
    37     const float *src = dst;
    38     int i;
    39 
    40     LOG_DEBUG_CONVERT("stereo", "mono");
    41     SDL_assert(format == AUDIO_F32SYS);
    42 
    43     for (i = cvt->len_cvt / 8; i; --i, src += 2) {
    44         *(dst++) = (float) ((((double) src[0]) + ((double) src[1])) * 0.5);
    45     }
    46 
    47     cvt->len_cvt /= 2;
    48     if (cvt->filters[++cvt->filter_index]) {
    49         cvt->filters[cvt->filter_index] (cvt, format);
    50     }
    51 }
    52 
    53 
    54 /* Convert from 5.1 to stereo. Average left and right, discard subwoofer. */
    55 static void SDLCALL
    56 SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    57 {
    58     float *dst = (float *) cvt->buf;
    59     const float *src = dst;
    60     int i;
    61 
    62     LOG_DEBUG_CONVERT("5.1", "stereo");
    63     SDL_assert(format == AUDIO_F32SYS);
    64 
    65     /* this assumes FL+FR+FC+subwoof+BL+BR layout. */
    66     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
    67         const double front_center = (double) src[2];
    68         dst[0] = (float) ((src[0] + front_center + src[4]) / 3.0);  /* left */
    69         dst[1] = (float) ((src[1] + front_center + src[5]) / 3.0);  /* right */
    70     }
    71 
    72     cvt->len_cvt /= 3;
    73     if (cvt->filters[++cvt->filter_index]) {
    74         cvt->filters[cvt->filter_index] (cvt, format);
    75     }
    76 }
    77 
    78 
    79 /* Convert from 5.1 to quad */
    80 static void SDLCALL
    81 SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    82 {
    83     float *dst = (float *) cvt->buf;
    84     const float *src = dst;
    85     int i;
    86 
    87     LOG_DEBUG_CONVERT("5.1", "quad");
    88     SDL_assert(format == AUDIO_F32SYS);
    89 
    90     /* assumes quad is FL+FR+BL+BR layout and 5.1 is FL+FR+FC+subwoof+BL+BR */
    91     for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
    92         /* FIXME: this is a good candidate for SIMD. */
    93         const double front_center = (double) src[2];
    94         dst[0] = (float) ((src[0] + front_center) * 0.5);  /* FL */
    95         dst[1] = (float) ((src[1] + front_center) * 0.5);  /* FR */
    96         dst[2] = (float) ((src[4] + front_center) * 0.5);  /* BL */
    97         dst[3] = (float) ((src[5] + front_center) * 0.5);  /* BR */
    98     }
    99 
   100     cvt->len_cvt /= 6;
   101     cvt->len_cvt *= 4;
   102     if (cvt->filters[++cvt->filter_index]) {
   103         cvt->filters[cvt->filter_index] (cvt, format);
   104     }
   105 }
   106 
   107 
   108 /* Duplicate a mono channel to both stereo channels */
   109 static void SDLCALL
   110 SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   111 {
   112     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   113     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   114     int i;
   115 
   116     LOG_DEBUG_CONVERT("mono", "stereo");
   117     SDL_assert(format == AUDIO_F32SYS);
   118 
   119     for (i = cvt->len_cvt / sizeof (float); i; --i) {
   120         src--;
   121         dst -= 2;
   122         dst[0] = dst[1] = *src;
   123     }
   124 
   125     cvt->len_cvt *= 2;
   126     if (cvt->filters[++cvt->filter_index]) {
   127         cvt->filters[cvt->filter_index] (cvt, format);
   128     }
   129 }
   130 
   131 
   132 /* Duplicate a stereo channel to a pseudo-5.1 stream */
   133 static void SDLCALL
   134 SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   135 {
   136     int i;
   137     float lf, rf, ce;
   138     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   139     float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
   140 
   141     LOG_DEBUG_CONVERT("stereo", "5.1");
   142     SDL_assert(format == AUDIO_F32SYS);
   143 
   144     for (i = cvt->len_cvt / 8; i; --i) {
   145         dst -= 6;
   146         src -= 2;
   147         lf = src[0];
   148         rf = src[1];
   149         ce = (lf + rf) * 0.5f;
   150         dst[0] = lf + (lf - ce);  /* FL */
   151         dst[1] = rf + (rf - ce);  /* FR */
   152         dst[2] = ce;  /* FC */
   153         dst[3] = ce;  /* !!! FIXME: wrong! This is the subwoofer. */
   154         dst[4] = lf;  /* BL */
   155         dst[5] = rf;  /* BR */
   156     }
   157 
   158     cvt->len_cvt *= 3;
   159     if (cvt->filters[++cvt->filter_index]) {
   160         cvt->filters[cvt->filter_index] (cvt, format);
   161     }
   162 }
   163 
   164 
   165 /* Duplicate a stereo channel to a pseudo-4.0 stream */
   166 static void SDLCALL
   167 SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   168 {
   169     const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   170     float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   171     float lf, rf;
   172     int i;
   173 
   174     LOG_DEBUG_CONVERT("stereo", "quad");
   175     SDL_assert(format == AUDIO_F32SYS);
   176 
   177     for (i = cvt->len_cvt / 8; i; --i) {
   178         dst -= 4;
   179         src -= 2;
   180         lf = src[0];
   181         rf = src[1];
   182         dst[0] = lf;  /* FL */
   183         dst[1] = rf;  /* FR */
   184         dst[2] = lf;  /* BL */
   185         dst[3] = rf;  /* BR */
   186     }
   187 
   188     cvt->len_cvt *= 2;
   189     if (cvt->filters[++cvt->filter_index]) {
   190         cvt->filters[cvt->filter_index] (cvt, format);
   191     }
   192 }
   193 
   194 static int
   195 SDL_ResampleAudioSimple(const int chans, const double rate_incr,
   196                         float *last_sample, const float *inbuf,
   197                         const int inbuflen, float *outbuf, const int outbuflen)
   198 {
   199     const int framelen = chans * sizeof(float);
   200     const int total = (inbuflen / framelen);
   201     const int finalpos = total - chans;
   202     const double src_incr = 1.0 / rate_incr;
   203     double idx = 0.0;
   204     float *dst = outbuf;
   205     int consumed = 0;
   206     int i;
   207 
   208     SDL_assert((inbuflen % framelen) == 0);
   209 
   210     while (consumed < total) {
   211         const int pos = ((int)idx) * chans;
   212         const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos];
   213         SDL_assert(dst < (outbuf + (outbuflen / framelen)));
   214         for (i = 0; i < chans; i++) {
   215             const float val = *(src++);
   216             *(dst++) = (val + last_sample[i]) * 0.5f;
   217             last_sample[i] = val;
   218         }
   219         consumed = pos + chans;
   220         idx += src_incr;
   221     }
   222 
   223     return (int)((dst - outbuf) * sizeof(float));
   224 }
   225 
   226 
   227 int
   228 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   229 {
   230     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   231     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   232 
   233     /* Make sure there's data to convert */
   234     if (cvt->buf == NULL) {
   235         return SDL_SetError("No buffer allocated for conversion");
   236     }
   237 
   238     /* Return okay if no conversion is necessary */
   239     cvt->len_cvt = cvt->len;
   240     if (cvt->filters[0] == NULL) {
   241         return 0;
   242     }
   243 
   244     /* Set up the conversion and go! */
   245     cvt->filter_index = 0;
   246     cvt->filters[0] (cvt, cvt->src_format);
   247     return 0;
   248 }
   249 
   250 static void SDLCALL
   251 SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
   252 {
   253 #if DEBUG_CONVERT
   254     printf("Converting byte order\n");
   255 #endif
   256 
   257     switch (SDL_AUDIO_BITSIZE(format)) {
   258         #define CASESWAP(b) \
   259             case b: { \
   260                 Uint##b *ptr = (Uint##b *) cvt->buf; \
   261                 int i; \
   262                 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
   263                     *ptr = SDL_Swap##b(*ptr); \
   264                 } \
   265                 break; \
   266             }
   267 
   268         CASESWAP(16);
   269         CASESWAP(32);
   270         CASESWAP(64);
   271 
   272         #undef CASESWAP
   273 
   274         default: SDL_assert(!"unhandled byteswap datatype!"); break;
   275     }
   276 
   277     if (cvt->filters[++cvt->filter_index]) {
   278         /* flip endian flag for data. */
   279         if (format & SDL_AUDIO_MASK_ENDIAN) {
   280             format &= ~SDL_AUDIO_MASK_ENDIAN;
   281         } else {
   282             format |= SDL_AUDIO_MASK_ENDIAN;
   283         }
   284         cvt->filters[cvt->filter_index](cvt, format);
   285     }
   286 }
   287 
   288 
   289 static int
   290 SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
   291 {
   292     int retval = 0;  /* 0 == no conversion necessary. */
   293 
   294     if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   295         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   296         retval = 1;  /* added a converter. */
   297     }
   298 
   299     if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
   300         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   301         const Uint16 dst_bitsize = 32;
   302         SDL_AudioFilter filter = NULL;
   303 
   304         switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   305             case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
   306             case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
   307             case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
   308             case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
   309             case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
   310             default: SDL_assert(!"Unexpected audio format!"); break;
   311         }
   312 
   313         if (!filter) {
   314             return SDL_SetError("No conversion available for these formats");
   315         }
   316 
   317         cvt->filters[cvt->filter_index++] = filter;
   318         if (src_bitsize < dst_bitsize) {
   319             const int mult = (dst_bitsize / src_bitsize);
   320             cvt->len_mult *= mult;
   321             cvt->len_ratio *= mult;
   322         } else if (src_bitsize > dst_bitsize) {
   323             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   324         }
   325 
   326         retval = 1;  /* added a converter. */
   327     }
   328 
   329     return retval;
   330 }
   331 
   332 static int
   333 SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
   334 {
   335     int retval = 0;  /* 0 == no conversion necessary. */
   336 
   337     if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
   338         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   339         const Uint16 src_bitsize = 32;
   340         SDL_AudioFilter filter = NULL;
   341         switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
   342             case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
   343             case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
   344             case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
   345             case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
   346             case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
   347             default: SDL_assert(!"Unexpected audio format!"); break;
   348         }
   349 
   350         if (!filter) {
   351             return SDL_SetError("No conversion available for these formats");
   352         }
   353 
   354         cvt->filters[cvt->filter_index++] = filter;
   355         if (src_bitsize < dst_bitsize) {
   356             const int mult = (dst_bitsize / src_bitsize);
   357             cvt->len_mult *= mult;
   358             cvt->len_ratio *= mult;
   359         } else if (src_bitsize > dst_bitsize) {
   360             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   361         }
   362         retval = 1;  /* added a converter. */
   363     }
   364 
   365     if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
   366         cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   367         retval = 1;  /* added a converter. */
   368     }
   369 
   370     return retval;
   371 }
   372 
   373 static void
   374 SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
   375 {
   376     const float *src = (const float *) cvt->buf;
   377     const int srclen = cvt->len_cvt;
   378     float *dst = (float *) (cvt->buf + srclen);
   379     const int dstlen = (cvt->len * cvt->len_mult) - srclen;
   380     SDL_bool do_simple = SDL_TRUE;
   381 
   382     SDL_assert(format == AUDIO_F32SYS);
   383 
   384 #ifdef HAVE_LIBSAMPLERATE_H
   385     if (SRC_available) {
   386         int result = 0;
   387         SRC_STATE *state = SRC_src_new(SRC_SINC_FASTEST, chans, &result);
   388         if (state) {
   389             const int framelen = sizeof(float) * chans;
   390             SRC_DATA data;
   391 
   392             data.data_in = (float *)src; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   393             data.input_frames = srclen / framelen;
   394             data.input_frames_used = 0;
   395 
   396             data.data_out = dst;
   397             data.output_frames = dstlen / framelen;
   398 
   399             data.end_of_input = 0;
   400             data.src_ratio = cvt->rate_incr;
   401 
   402             result = SRC_src_process(state, &data);
   403             SDL_assert(result == 0);  /* what to do if this fails? Can it fail? */
   404 
   405             /* What to do if this fails...? */
   406             SDL_assert(data.input_frames_used == data.input_frames);
   407 
   408             SRC_src_delete(state);
   409             cvt->len_cvt = data.output_frames_gen * (sizeof(float) * chans);
   410             do_simple = SDL_FALSE;
   411         }
   412 
   413         /* failed to create state? Fall back to simple method. */
   414     }
   415 #endif
   416 
   417     if (do_simple) {
   418         float state[8];
   419         int i;
   420 
   421         for (i = 0; i < chans; i++) {
   422             state[i] = src[i];
   423         }
   424 
   425         cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   426     }
   427 
   428     SDL_memcpy(cvt->buf, dst, cvt->len_cvt);
   429     if (cvt->filters[++cvt->filter_index]) {
   430         cvt->filters[cvt->filter_index](cvt, format);
   431     }
   432 }
   433 
   434 /* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   435    !!! FIXME:  store channel info, so we have to have function entry
   436    !!! FIXME:  points for each supported channel count and multiple
   437    !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   438 #define RESAMPLER_FUNCS(chans) \
   439     static void SDLCALL \
   440     SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   441         SDL_ResampleCVT(cvt, chans, format); \
   442     }
   443 RESAMPLER_FUNCS(1)
   444 RESAMPLER_FUNCS(2)
   445 RESAMPLER_FUNCS(4)
   446 RESAMPLER_FUNCS(6)
   447 RESAMPLER_FUNCS(8)
   448 #undef RESAMPLER_FUNCS
   449 
   450 static SDL_AudioFilter
   451 ChooseCVTResampler(const int dst_channels)
   452 {
   453     switch (dst_channels) {
   454         case 1: return SDL_ResampleCVT_c1;
   455         case 2: return SDL_ResampleCVT_c2;
   456         case 4: return SDL_ResampleCVT_c4;
   457         case 6: return SDL_ResampleCVT_c6;
   458         case 8: return SDL_ResampleCVT_c8;
   459         default: break;
   460     }
   461 
   462     return NULL;
   463 }
   464 
   465 static int
   466 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
   467                           const int src_rate, const int dst_rate)
   468 {
   469     SDL_AudioFilter filter;
   470 
   471     if (src_rate == dst_rate) {
   472         return 0;  /* no conversion necessary. */
   473     }
   474 
   475     filter = ChooseCVTResampler(dst_channels);
   476     if (filter == NULL) {
   477         return SDL_SetError("No conversion available for these rates");
   478     }
   479 
   480     /* Update (cvt) with filter details... */
   481     cvt->filters[cvt->filter_index++] = filter;
   482     if (src_rate < dst_rate) {
   483         const double mult = ((double) dst_rate) / ((double) src_rate);
   484         cvt->len_mult *= (int) SDL_ceil(mult);
   485         cvt->len_ratio *= mult;
   486     } else {
   487         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   488     }
   489 
   490     /* the buffer is big enough to hold the destination now, but
   491        we need it large enough to hold a separate scratch buffer. */
   492     cvt->len_mult *= 2;
   493 
   494     return 1;               /* added a converter. */
   495 }
   496 
   497 
   498 /* Creates a set of audio filters to convert from one format to another.
   499    Returns -1 if the format conversion is not supported, 0 if there's
   500    no conversion needed, or 1 if the audio filter is set up.
   501 */
   502 
   503 int
   504 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   505                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
   506                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
   507 {
   508     /* Sanity check target pointer */
   509     if (cvt == NULL) {
   510         return SDL_InvalidParamError("cvt");
   511     }
   512 
   513     /* Make sure we zero out the audio conversion before error checking */
   514     SDL_zerop(cvt);
   515 
   516     /* there are no unsigned types over 16 bits, so catch this up front. */
   517     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
   518         return SDL_SetError("Invalid source format");
   519     }
   520     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
   521         return SDL_SetError("Invalid destination format");
   522     }
   523 
   524     /* prevent possible divisions by zero, etc. */
   525     if ((src_channels == 0) || (dst_channels == 0)) {
   526         return SDL_SetError("Source or destination channels is zero");
   527     }
   528     if ((src_rate == 0) || (dst_rate == 0)) {
   529         return SDL_SetError("Source or destination rate is zero");
   530     }
   531 #if DEBUG_CONVERT
   532     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
   533            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
   534 #endif
   535 
   536     /* Start off with no conversion necessary */
   537     cvt->src_format = src_fmt;
   538     cvt->dst_format = dst_fmt;
   539     cvt->needed = 0;
   540     cvt->filter_index = 0;
   541     cvt->filters[0] = NULL;
   542     cvt->len_mult = 1;
   543     cvt->len_ratio = 1.0;
   544     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
   545 
   546     /* Type conversion goes like this now:
   547         - byteswap to CPU native format first if necessary.
   548         - convert to native Float32 if necessary.
   549         - resample and change channel count if necessary.
   550         - convert back to native format.
   551         - byteswap back to foreign format if necessary.
   552 
   553        The expectation is we can process data faster in float32
   554        (possibly with SIMD), and making several passes over the same
   555        buffer is likely to be CPU cache-friendly, avoiding the
   556        biggest performance hit in modern times. Previously we had
   557        (script-generated) custom converters for every data type and
   558        it was a bloat on SDL compile times and final library size. */
   559 
   560     /* see if we can skip float conversion entirely. */
   561     if (src_rate == dst_rate && src_channels == dst_channels) {
   562         if (src_fmt == dst_fmt) {
   563             return 0;
   564         }
   565 
   566         /* just a byteswap needed? */
   567         if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
   568             cvt->filters[cvt->filter_index++] = SDL_Convert_Byteswap;
   569             cvt->needed = 1;
   570             return 1;
   571         }
   572     }
   573 
   574     /* Convert data types, if necessary. Updates (cvt). */
   575     if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
   576         return -1;              /* shouldn't happen, but just in case... */
   577     }
   578 
   579     /* Channel conversion */
   580     if (src_channels != dst_channels) {
   581         if ((src_channels == 1) && (dst_channels > 1)) {
   582             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   583             cvt->len_mult *= 2;
   584             src_channels = 2;
   585             cvt->len_ratio *= 2;
   586         }
   587         if ((src_channels == 2) && (dst_channels == 6)) {
   588             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
   589             src_channels = 6;
   590             cvt->len_mult *= 3;
   591             cvt->len_ratio *= 3;
   592         }
   593         if ((src_channels == 2) && (dst_channels == 4)) {
   594             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
   595             src_channels = 4;
   596             cvt->len_mult *= 2;
   597             cvt->len_ratio *= 2;
   598         }
   599         while ((src_channels * 2) <= dst_channels) {
   600             cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
   601             cvt->len_mult *= 2;
   602             src_channels *= 2;
   603             cvt->len_ratio *= 2;
   604         }
   605         if ((src_channels == 6) && (dst_channels <= 2)) {
   606             cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
   607             src_channels = 2;
   608             cvt->len_ratio /= 3;
   609         }
   610         if ((src_channels == 6) && (dst_channels == 4)) {
   611             cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
   612             src_channels = 4;
   613             cvt->len_ratio /= 2;
   614         }
   615         /* This assumes that 4 channel audio is in the format:
   616            Left {front/back} + Right {front/back}
   617            so converting to L/R stereo works properly.
   618          */
   619         while (((src_channels % 2) == 0) &&
   620                ((src_channels / 2) >= dst_channels)) {
   621             cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToMono;
   622             src_channels /= 2;
   623             cvt->len_ratio /= 2;
   624         }
   625         if (src_channels != dst_channels) {
   626             /* Uh oh.. */ ;
   627         }
   628     }
   629 
   630     /* Do rate conversion, if necessary. Updates (cvt). */
   631     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
   632         return -1;              /* shouldn't happen, but just in case... */
   633     }
   634 
   635     /* Move to final data type. */
   636     if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
   637         return -1;              /* shouldn't happen, but just in case... */
   638     }
   639 
   640     cvt->needed = (cvt->filter_index != 0);
   641     return (cvt->needed);
   642 }
   643 
   644 typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen);
   645 typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   646 typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
   647 
   648 struct SDL_AudioStream
   649 {
   650     SDL_AudioCVT cvt_before_resampling;
   651     SDL_AudioCVT cvt_after_resampling;
   652     SDL_DataQueue *queue;
   653     Uint8 *work_buffer;
   654     int work_buffer_len;
   655     Uint8 *resample_buffer;
   656     int resample_buffer_len;
   657     int src_sample_frame_size;
   658     SDL_AudioFormat src_format;
   659     Uint8 src_channels;
   660     int src_rate;
   661     int dst_sample_frame_size;
   662     SDL_AudioFormat dst_format;
   663     Uint8 dst_channels;
   664     int dst_rate;
   665     double rate_incr;
   666     Uint8 pre_resample_channels;
   667     int packetlen;
   668     void *resampler_state;
   669     SDL_ResampleAudioStreamFunc resampler_func;
   670     SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
   671     SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
   672 };
   673 
   674 #ifdef HAVE_LIBSAMPLERATE_H
   675 static int
   676 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   677 {
   678     const int framelen = sizeof(float) * stream->pre_resample_channels;
   679     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   680     SRC_DATA data;
   681     int result;
   682 
   683     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   684     data.input_frames = inbuflen / framelen;
   685     data.input_frames_used = 0;
   686 
   687     data.data_out = outbuf;
   688     data.output_frames = outbuflen / framelen;
   689 
   690     data.end_of_input = 0;
   691     data.src_ratio = stream->rate_incr;
   692 
   693     result = SRC_src_process(state, &data);
   694     if (result != 0) {
   695         SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
   696         return 0;
   697     }
   698 
   699     /* If this fails, we need to store them off somewhere */
   700     SDL_assert(data.input_frames_used == data.input_frames);
   701 
   702     return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
   703 }
   704 
   705 static void
   706 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
   707 {
   708     SRC_src_reset((SRC_STATE *)stream->resampler_state);
   709 }
   710 
   711 static void
   712 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
   713 {
   714     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   715     if (state) {
   716         SRC_src_delete(state);
   717     }
   718 
   719     stream->resampler_state = NULL;
   720     stream->resampler_func = NULL;
   721     stream->reset_resampler_func = NULL;
   722     stream->cleanup_resampler_func = NULL;
   723 }
   724 
   725 static SDL_bool
   726 SetupLibSampleRateResampling(SDL_AudioStream *stream)
   727 {
   728     int result = 0;
   729     SRC_STATE *state = NULL;
   730 
   731     if (SRC_available) {
   732         state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
   733         if (!state) {
   734             SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
   735         }
   736     }
   737 
   738     if (!state) {
   739         SDL_CleanupAudioStreamResampler_SRC(stream);
   740         return SDL_FALSE;
   741     }
   742 
   743     stream->resampler_state = state;
   744     stream->resampler_func = SDL_ResampleAudioStream_SRC;
   745     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
   746     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
   747 
   748     return SDL_TRUE;
   749 }
   750 #endif /* HAVE_LIBSAMPLERATE_H */
   751 
   752 
   753 typedef struct
   754 {
   755     SDL_bool resampler_seeded;
   756     float resampler_state[8];
   757 } SDL_AudioStreamResamplerState;
   758 
   759 static int
   760 SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   761 {
   762     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   763     const int chans = (int)stream->pre_resample_channels;
   764 
   765     SDL_assert(chans <= SDL_arraysize(state->resampler_state));
   766 
   767     if (!state->resampler_seeded) {
   768         int i;
   769         for (i = 0; i < chans; i++) {
   770             state->resampler_state[i] = inbuf[i];
   771         }
   772         state->resampler_seeded = SDL_TRUE;
   773     }
   774 
   775     return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
   776 }
   777 
   778 static void
   779 SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
   780 {
   781     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   782     state->resampler_seeded = SDL_FALSE;
   783 }
   784 
   785 static void
   786 SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
   787 {
   788     SDL_free(stream->resampler_state);
   789 }
   790 
   791 SDL_AudioStream *
   792 SDL_NewAudioStream(const SDL_AudioFormat src_format,
   793                    const Uint8 src_channels,
   794                    const int src_rate,
   795                    const SDL_AudioFormat dst_format,
   796                    const Uint8 dst_channels,
   797                    const int dst_rate)
   798 {
   799     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
   800     Uint8 pre_resample_channels;
   801     SDL_AudioStream *retval;
   802 
   803     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
   804     if (!retval) {
   805         return NULL;
   806     }
   807 
   808     /* If increasing channels, do it after resampling, since we'd just
   809        do more work to resample duplicate channels. If we're decreasing, do
   810        it first so we resample the interpolated data instead of interpolating
   811        the resampled data (!!! FIXME: decide if that works in practice, though!). */
   812     pre_resample_channels = SDL_min(src_channels, dst_channels);
   813 
   814     retval->src_sample_frame_size = SDL_AUDIO_BITSIZE(src_format) * src_channels;
   815     retval->src_format = src_format;
   816     retval->src_channels = src_channels;
   817     retval->src_rate = src_rate;
   818     retval->dst_sample_frame_size = SDL_AUDIO_BITSIZE(dst_format) * dst_channels;
   819     retval->dst_format = dst_format;
   820     retval->dst_channels = dst_channels;
   821     retval->dst_rate = dst_rate;
   822     retval->pre_resample_channels = pre_resample_channels;
   823     retval->packetlen = packetlen;
   824     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
   825 
   826     /* Not resampling? It's an easy conversion (and maybe not even that!). */
   827     if (src_rate == dst_rate) {
   828         retval->cvt_before_resampling.needed = SDL_FALSE;
   829         retval->cvt_before_resampling.len_mult = 1;
   830         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   831             SDL_FreeAudioStream(retval);
   832             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   833         }
   834     } else {
   835         /* Don't resample at first. Just get us to Float32 format. */
   836         /* !!! FIXME: convert to int32 on devices without hardware float. */
   837         if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
   838             SDL_FreeAudioStream(retval);
   839             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   840         }
   841 
   842 #ifdef HAVE_LIBSAMPLERATE_H
   843         SetupLibSampleRateResampling(retval);
   844 #endif
   845 
   846         if (!retval->resampler_func) {
   847             retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
   848             if (!retval->resampler_state) {
   849                 SDL_FreeAudioStream(retval);
   850                 SDL_OutOfMemory();
   851                 return NULL;
   852             }
   853             retval->resampler_func = SDL_ResampleAudioStream;
   854             retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
   855             retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
   856         }
   857 
   858         /* Convert us to the final format after resampling. */
   859         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
   860             SDL_FreeAudioStream(retval);
   861             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
   862         }
   863     }
   864 
   865     retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
   866     if (!retval->queue) {
   867         SDL_FreeAudioStream(retval);
   868         return NULL;  /* SDL_NewDataQueue should have called SDL_SetError. */
   869     }
   870 
   871     return retval;
   872 }
   873 
   874 static Uint8 *
   875 EnsureBufferSize(Uint8 **buf, int *len, const int newlen)
   876 {
   877     if (*len < newlen) {
   878         void *ptr = SDL_realloc(*buf, newlen);
   879         if (!ptr) {
   880             SDL_OutOfMemory();
   881             return NULL;
   882         }
   883         *buf = (Uint8 *) ptr;
   884         *len = newlen;
   885     }
   886     return *buf;
   887 }
   888 
   889 int
   890 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
   891 {
   892     int buflen = (int) _buflen;
   893 
   894     if (!stream) {
   895         return SDL_InvalidParamError("stream");
   896     } else if (!buf) {
   897         return SDL_InvalidParamError("buf");
   898     } else if (buflen == 0) {
   899         return 0;  /* nothing to do. */
   900     } else if ((buflen % stream->src_sample_frame_size) != 0) {
   901         return SDL_SetError("Can't add partial sample frames");
   902     }
   903 
   904     if (stream->cvt_before_resampling.needed) {
   905         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   906         Uint8 *workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   907         if (workbuf == NULL) {
   908             return -1;  /* probably out of memory. */
   909         }
   910         SDL_memcpy(workbuf, buf, buflen);
   911         stream->cvt_before_resampling.buf = workbuf;
   912         stream->cvt_before_resampling.len = buflen;
   913         if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
   914             return -1;   /* uhoh! */
   915         }
   916         buf = workbuf;
   917         buflen = stream->cvt_before_resampling.len_cvt;
   918     }
   919 
   920     if (stream->dst_rate != stream->src_rate) {
   921         const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
   922         float *workbuf = (float *) EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   923         if (workbuf == NULL) {
   924             return -1;  /* probably out of memory. */
   925         }
   926         buflen = stream->resampler_func(stream, (float *) buf, buflen, workbuf, workbuflen);
   927         buf = workbuf;
   928     }
   929 
   930     if (stream->cvt_after_resampling.needed) {
   931         const int workbuflen = buflen * stream->cvt_before_resampling.len_mult;  /* will be "* 1" if not needed */
   932         Uint8 *workbuf;
   933 
   934         if (buf == stream->resample_buffer) {
   935             workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen);
   936         } else {
   937             const int inplace = (buf == stream->work_buffer);
   938             workbuf = EnsureBufferSize(&stream->work_buffer, &stream->work_buffer_len, workbuflen);
   939             if (workbuf && !inplace) {
   940                 SDL_memcpy(workbuf, buf, buflen);
   941             }
   942         }
   943 
   944         if (workbuf == NULL) {
   945             return -1;  /* probably out of memory. */
   946         }
   947 
   948         stream->cvt_after_resampling.buf = workbuf;
   949         stream->cvt_after_resampling.len = buflen;
   950         if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
   951             return -1;   /* uhoh! */
   952         }
   953         buf = workbuf;
   954         buflen = stream->cvt_after_resampling.len_cvt;
   955     }
   956 
   957     return SDL_WriteToDataQueue(stream->queue, buf, buflen);
   958 }
   959 
   960 void
   961 SDL_AudioStreamClear(SDL_AudioStream *stream)
   962 {
   963     if (!stream) {
   964         SDL_InvalidParamError("stream");
   965     } else {
   966         SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
   967         if (stream->reset_resampler_func) {
   968             stream->reset_resampler_func(stream);
   969         }
   970     }
   971 }
   972 
   973 
   974 /* get converted/resampled data from the stream */
   975 int
   976 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
   977 {
   978     if (!stream) {
   979         return SDL_InvalidParamError("stream");
   980     } else if (!buf) {
   981         return SDL_InvalidParamError("buf");
   982     } else if (len == 0) {
   983         return 0;  /* nothing to do. */
   984     } else if ((len % stream->dst_sample_frame_size) != 0) {
   985         return SDL_SetError("Can't request partial sample frames");
   986     }
   987 
   988     return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
   989 }
   990 
   991 /* number of converted/resampled bytes available */
   992 int
   993 SDL_AudioStreamAvailable(SDL_AudioStream *stream)
   994 {
   995     return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
   996 }
   997 
   998 /* dispose of a stream */
   999 void
  1000 SDL_FreeAudioStream(SDL_AudioStream *stream)
  1001 {
  1002     if (stream) {
  1003         if (stream->cleanup_resampler_func) {
  1004             stream->cleanup_resampler_func(stream);
  1005         }
  1006         SDL_FreeDataQueue(stream->queue);
  1007         SDL_free(stream->work_buffer);
  1008         SDL_free(stream->resample_buffer);
  1009         SDL_free(stream);
  1010     }
  1011 }
  1012 
  1013 /* vi: set ts=4 sw=4 expandtab: */
  1014