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