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