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