src/audio/SDL_audiocvt.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 22 Feb 2015 23:21:32 +0100
changeset 9373 679eb3986e37
parent 8235 cc1d377f014a
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Emscripten: Fixed out of range joystick device index after joystick disconnect.

After disconnecting a joystick the remaining kept their original device index.
This was not correct because the device index must be a number between 0 and
SDL_NumJoysticks(). It was fixed with ideas from SDL's joystick implementation
for Android. Some range checks were removed as the caller already checks them.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_assert.h"
    29 
    30 /* #define DEBUG_CONVERT */
    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     int i;
    37     Sint32 sample;
    38 
    39 #ifdef DEBUG_CONVERT
    40     fprintf(stderr, "Converting to mono\n");
    41 #endif
    42 	switch (format & (SDL_AUDIO_MASK_SIGNED |
    43                       SDL_AUDIO_MASK_BITSIZE |
    44                       SDL_AUDIO_MASK_DATATYPE)) {
    45     case AUDIO_U8:
    46         {
    47             Uint8 *src, *dst;
    48 
    49             src = cvt->buf;
    50             dst = cvt->buf;
    51             for (i = cvt->len_cvt / 2; i; --i) {
    52                 sample = src[0] + src[1];
    53                 *dst = (Uint8) (sample / 2);
    54                 src += 2;
    55                 dst += 1;
    56             }
    57         }
    58         break;
    59 
    60     case AUDIO_S8:
    61         {
    62             Sint8 *src, *dst;
    63 
    64             src = (Sint8 *) cvt->buf;
    65             dst = (Sint8 *) cvt->buf;
    66             for (i = cvt->len_cvt / 2; i; --i) {
    67                 sample = src[0] + src[1];
    68                 *dst = (Sint8) (sample / 2);
    69                 src += 2;
    70                 dst += 1;
    71             }
    72         }
    73         break;
    74 
    75     case AUDIO_U16:
    76         {
    77             Uint8 *src, *dst;
    78 
    79             src = cvt->buf;
    80             dst = cvt->buf;
    81             if (SDL_AUDIO_ISBIGENDIAN(format)) {
    82                 for (i = cvt->len_cvt / 4; i; --i) {
    83                     sample = (Uint16) ((src[0] << 8) | src[1]) +
    84                         (Uint16) ((src[2] << 8) | src[3]);
    85                     sample /= 2;
    86                     dst[1] = (sample & 0xFF);
    87                     sample >>= 8;
    88                     dst[0] = (sample & 0xFF);
    89                     src += 4;
    90                     dst += 2;
    91                 }
    92             } else {
    93                 for (i = cvt->len_cvt / 4; i; --i) {
    94                     sample = (Uint16) ((src[1] << 8) | src[0]) +
    95                         (Uint16) ((src[3] << 8) | src[2]);
    96                     sample /= 2;
    97                     dst[0] = (sample & 0xFF);
    98                     sample >>= 8;
    99                     dst[1] = (sample & 0xFF);
   100                     src += 4;
   101                     dst += 2;
   102                 }
   103             }
   104         }
   105         break;
   106 
   107     case AUDIO_S16:
   108         {
   109             Uint8 *src, *dst;
   110 
   111             src = cvt->buf;
   112             dst = cvt->buf;
   113             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   114                 for (i = cvt->len_cvt / 4; i; --i) {
   115                     sample = (Sint16) ((src[0] << 8) | src[1]) +
   116                         (Sint16) ((src[2] << 8) | src[3]);
   117                     sample /= 2;
   118                     dst[1] = (sample & 0xFF);
   119                     sample >>= 8;
   120                     dst[0] = (sample & 0xFF);
   121                     src += 4;
   122                     dst += 2;
   123                 }
   124             } else {
   125                 for (i = cvt->len_cvt / 4; i; --i) {
   126                     sample = (Sint16) ((src[1] << 8) | src[0]) +
   127                         (Sint16) ((src[3] << 8) | src[2]);
   128                     sample /= 2;
   129                     dst[0] = (sample & 0xFF);
   130                     sample >>= 8;
   131                     dst[1] = (sample & 0xFF);
   132                     src += 4;
   133                     dst += 2;
   134                 }
   135             }
   136         }
   137         break;
   138 
   139     case AUDIO_S32:
   140         {
   141             const Uint32 *src = (const Uint32 *) cvt->buf;
   142             Uint32 *dst = (Uint32 *) cvt->buf;
   143             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   144                 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
   145                     const Sint64 added =
   146                         (((Sint64) (Sint32) SDL_SwapBE32(src[0])) +
   147                          ((Sint64) (Sint32) SDL_SwapBE32(src[1])));
   148                     *(dst++) = SDL_SwapBE32((Uint32) ((Sint32) (added / 2)));
   149                 }
   150             } else {
   151                 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
   152                     const Sint64 added =
   153                         (((Sint64) (Sint32) SDL_SwapLE32(src[0])) +
   154                          ((Sint64) (Sint32) SDL_SwapLE32(src[1])));
   155                     *(dst++) = SDL_SwapLE32((Uint32) ((Sint32) (added / 2)));
   156                 }
   157             }
   158         }
   159         break;
   160 
   161     case AUDIO_F32:
   162         {
   163             const float *src = (const float *) cvt->buf;
   164             float *dst = (float *) cvt->buf;
   165             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   166                 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
   167                     const float src1 = SDL_SwapFloatBE(src[0]);
   168                     const float src2 = SDL_SwapFloatBE(src[1]);
   169                     const double added = ((double) src1) + ((double) src2);
   170                     const float halved = (float) (added * 0.5);
   171                     *(dst++) = SDL_SwapFloatBE(halved);
   172                 }
   173             } else {
   174                 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
   175                     const float src1 = SDL_SwapFloatLE(src[0]);
   176                     const float src2 = SDL_SwapFloatLE(src[1]);
   177                     const double added = ((double) src1) + ((double) src2);
   178                     const float halved = (float) (added * 0.5);
   179                     *(dst++) = SDL_SwapFloatLE(halved);
   180                 }
   181             }
   182         }
   183         break;
   184     }
   185 
   186     cvt->len_cvt /= 2;
   187     if (cvt->filters[++cvt->filter_index]) {
   188         cvt->filters[cvt->filter_index] (cvt, format);
   189     }
   190 }
   191 
   192 
   193 /* Discard top 4 channels */
   194 static void SDLCALL
   195 SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   196 {
   197     int i;
   198 
   199 #ifdef DEBUG_CONVERT
   200     fprintf(stderr, "Converting down from 6 channels to stereo\n");
   201 #endif
   202 
   203 #define strip_chans_6_to_2(type) \
   204     { \
   205         const type *src = (const type *) cvt->buf; \
   206         type *dst = (type *) cvt->buf; \
   207         for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
   208             dst[0] = src[0]; \
   209             dst[1] = src[1]; \
   210             src += 6; \
   211             dst += 2; \
   212         } \
   213     }
   214 
   215     /* this function only cares about typesize, and data as a block of bits. */
   216     switch (SDL_AUDIO_BITSIZE(format)) {
   217     case 8:
   218         strip_chans_6_to_2(Uint8);
   219         break;
   220     case 16:
   221         strip_chans_6_to_2(Uint16);
   222         break;
   223     case 32:
   224         strip_chans_6_to_2(Uint32);
   225         break;
   226     }
   227 
   228 #undef strip_chans_6_to_2
   229 
   230     cvt->len_cvt /= 3;
   231     if (cvt->filters[++cvt->filter_index]) {
   232         cvt->filters[cvt->filter_index] (cvt, format);
   233     }
   234 }
   235 
   236 
   237 /* Discard top 2 channels of 6 */
   238 static void SDLCALL
   239 SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   240 {
   241     int i;
   242 
   243 #ifdef DEBUG_CONVERT
   244     fprintf(stderr, "Converting 6 down to quad\n");
   245 #endif
   246 
   247 #define strip_chans_6_to_4(type) \
   248     { \
   249         const type *src = (const type *) cvt->buf; \
   250         type *dst = (type *) cvt->buf; \
   251         for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
   252             dst[0] = src[0]; \
   253             dst[1] = src[1]; \
   254             dst[2] = src[2]; \
   255             dst[3] = src[3]; \
   256             src += 6; \
   257             dst += 4; \
   258         } \
   259     }
   260 
   261     /* this function only cares about typesize, and data as a block of bits. */
   262     switch (SDL_AUDIO_BITSIZE(format)) {
   263     case 8:
   264         strip_chans_6_to_4(Uint8);
   265         break;
   266     case 16:
   267         strip_chans_6_to_4(Uint16);
   268         break;
   269     case 32:
   270         strip_chans_6_to_4(Uint32);
   271         break;
   272     }
   273 
   274 #undef strip_chans_6_to_4
   275 
   276     cvt->len_cvt /= 6;
   277     cvt->len_cvt *= 4;
   278     if (cvt->filters[++cvt->filter_index]) {
   279         cvt->filters[cvt->filter_index] (cvt, format);
   280     }
   281 }
   282 
   283 /* Duplicate a mono channel to both stereo channels */
   284 static void SDLCALL
   285 SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   286 {
   287     int i;
   288 
   289 #ifdef DEBUG_CONVERT
   290     fprintf(stderr, "Converting to stereo\n");
   291 #endif
   292 
   293 #define dup_chans_1_to_2(type) \
   294     { \
   295         const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
   296         type *dst = (type *) (cvt->buf + cvt->len_cvt * 2); \
   297         for (i = cvt->len_cvt / sizeof(type); i; --i) { \
   298             src -= 1; \
   299             dst -= 2; \
   300             dst[0] = dst[1] = *src; \
   301         } \
   302     }
   303 
   304     /* this function only cares about typesize, and data as a block of bits. */
   305     switch (SDL_AUDIO_BITSIZE(format)) {
   306     case 8:
   307         dup_chans_1_to_2(Uint8);
   308         break;
   309     case 16:
   310         dup_chans_1_to_2(Uint16);
   311         break;
   312     case 32:
   313         dup_chans_1_to_2(Uint32);
   314         break;
   315     }
   316 
   317 #undef dup_chans_1_to_2
   318 
   319     cvt->len_cvt *= 2;
   320     if (cvt->filters[++cvt->filter_index]) {
   321         cvt->filters[cvt->filter_index] (cvt, format);
   322     }
   323 }
   324 
   325 
   326 /* Duplicate a stereo channel to a pseudo-5.1 stream */
   327 static void SDLCALL
   328 SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   329 {
   330     int i;
   331 
   332 #ifdef DEBUG_CONVERT
   333     fprintf(stderr, "Converting stereo to surround\n");
   334 #endif
   335 
   336     switch (format & (SDL_AUDIO_MASK_SIGNED  |
   337                       SDL_AUDIO_MASK_BITSIZE |
   338                       SDL_AUDIO_MASK_DATATYPE)) {
   339     case AUDIO_U8:
   340         {
   341             Uint8 *src, *dst, lf, rf, ce;
   342 
   343             src = (Uint8 *) (cvt->buf + cvt->len_cvt);
   344             dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 3);
   345             for (i = cvt->len_cvt; i; --i) {
   346                 dst -= 6;
   347                 src -= 2;
   348                 lf = src[0];
   349                 rf = src[1];
   350                 ce = (lf / 2) + (rf / 2);
   351                 dst[0] = lf;
   352                 dst[1] = rf;
   353                 dst[2] = lf - ce;
   354                 dst[3] = rf - ce;
   355                 dst[4] = ce;
   356                 dst[5] = ce;
   357             }
   358         }
   359         break;
   360 
   361     case AUDIO_S8:
   362         {
   363             Sint8 *src, *dst, lf, rf, ce;
   364 
   365             src = (Sint8 *) cvt->buf + cvt->len_cvt;
   366             dst = (Sint8 *) cvt->buf + cvt->len_cvt * 3;
   367             for (i = cvt->len_cvt; i; --i) {
   368                 dst -= 6;
   369                 src -= 2;
   370                 lf = src[0];
   371                 rf = src[1];
   372                 ce = (lf / 2) + (rf / 2);
   373                 dst[0] = lf;
   374                 dst[1] = rf;
   375                 dst[2] = lf - ce;
   376                 dst[3] = rf - ce;
   377                 dst[4] = ce;
   378                 dst[5] = ce;
   379             }
   380         }
   381         break;
   382 
   383     case AUDIO_U16:
   384         {
   385             Uint8 *src, *dst;
   386             Uint16 lf, rf, ce, lr, rr;
   387 
   388             src = cvt->buf + cvt->len_cvt;
   389             dst = cvt->buf + cvt->len_cvt * 3;
   390 
   391             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   392                 for (i = cvt->len_cvt / 4; i; --i) {
   393                     dst -= 12;
   394                     src -= 4;
   395                     lf = (Uint16) ((src[0] << 8) | src[1]);
   396                     rf = (Uint16) ((src[2] << 8) | src[3]);
   397                     ce = (lf / 2) + (rf / 2);
   398                     rr = lf - ce;
   399                     lr = rf - ce;
   400                     dst[1] = (lf & 0xFF);
   401                     dst[0] = ((lf >> 8) & 0xFF);
   402                     dst[3] = (rf & 0xFF);
   403                     dst[2] = ((rf >> 8) & 0xFF);
   404 
   405                     dst[1 + 4] = (lr & 0xFF);
   406                     dst[0 + 4] = ((lr >> 8) & 0xFF);
   407                     dst[3 + 4] = (rr & 0xFF);
   408                     dst[2 + 4] = ((rr >> 8) & 0xFF);
   409 
   410                     dst[1 + 8] = (ce & 0xFF);
   411                     dst[0 + 8] = ((ce >> 8) & 0xFF);
   412                     dst[3 + 8] = (ce & 0xFF);
   413                     dst[2 + 8] = ((ce >> 8) & 0xFF);
   414                 }
   415             } else {
   416                 for (i = cvt->len_cvt / 4; i; --i) {
   417                     dst -= 12;
   418                     src -= 4;
   419                     lf = (Uint16) ((src[1] << 8) | src[0]);
   420                     rf = (Uint16) ((src[3] << 8) | src[2]);
   421                     ce = (lf / 2) + (rf / 2);
   422                     rr = lf - ce;
   423                     lr = rf - ce;
   424                     dst[0] = (lf & 0xFF);
   425                     dst[1] = ((lf >> 8) & 0xFF);
   426                     dst[2] = (rf & 0xFF);
   427                     dst[3] = ((rf >> 8) & 0xFF);
   428 
   429                     dst[0 + 4] = (lr & 0xFF);
   430                     dst[1 + 4] = ((lr >> 8) & 0xFF);
   431                     dst[2 + 4] = (rr & 0xFF);
   432                     dst[3 + 4] = ((rr >> 8) & 0xFF);
   433 
   434                     dst[0 + 8] = (ce & 0xFF);
   435                     dst[1 + 8] = ((ce >> 8) & 0xFF);
   436                     dst[2 + 8] = (ce & 0xFF);
   437                     dst[3 + 8] = ((ce >> 8) & 0xFF);
   438                 }
   439             }
   440         }
   441         break;
   442 
   443     case AUDIO_S16:
   444         {
   445             Uint8 *src, *dst;
   446             Sint16 lf, rf, ce, lr, rr;
   447 
   448             src = cvt->buf + cvt->len_cvt;
   449             dst = cvt->buf + cvt->len_cvt * 3;
   450 
   451             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   452                 for (i = cvt->len_cvt / 4; i; --i) {
   453                     dst -= 12;
   454                     src -= 4;
   455                     lf = (Sint16) ((src[0] << 8) | src[1]);
   456                     rf = (Sint16) ((src[2] << 8) | src[3]);
   457                     ce = (lf / 2) + (rf / 2);
   458                     rr = lf - ce;
   459                     lr = rf - ce;
   460                     dst[1] = (lf & 0xFF);
   461                     dst[0] = ((lf >> 8) & 0xFF);
   462                     dst[3] = (rf & 0xFF);
   463                     dst[2] = ((rf >> 8) & 0xFF);
   464 
   465                     dst[1 + 4] = (lr & 0xFF);
   466                     dst[0 + 4] = ((lr >> 8) & 0xFF);
   467                     dst[3 + 4] = (rr & 0xFF);
   468                     dst[2 + 4] = ((rr >> 8) & 0xFF);
   469 
   470                     dst[1 + 8] = (ce & 0xFF);
   471                     dst[0 + 8] = ((ce >> 8) & 0xFF);
   472                     dst[3 + 8] = (ce & 0xFF);
   473                     dst[2 + 8] = ((ce >> 8) & 0xFF);
   474                 }
   475             } else {
   476                 for (i = cvt->len_cvt / 4; i; --i) {
   477                     dst -= 12;
   478                     src -= 4;
   479                     lf = (Sint16) ((src[1] << 8) | src[0]);
   480                     rf = (Sint16) ((src[3] << 8) | src[2]);
   481                     ce = (lf / 2) + (rf / 2);
   482                     rr = lf - ce;
   483                     lr = rf - ce;
   484                     dst[0] = (lf & 0xFF);
   485                     dst[1] = ((lf >> 8) & 0xFF);
   486                     dst[2] = (rf & 0xFF);
   487                     dst[3] = ((rf >> 8) & 0xFF);
   488 
   489                     dst[0 + 4] = (lr & 0xFF);
   490                     dst[1 + 4] = ((lr >> 8) & 0xFF);
   491                     dst[2 + 4] = (rr & 0xFF);
   492                     dst[3 + 4] = ((rr >> 8) & 0xFF);
   493 
   494                     dst[0 + 8] = (ce & 0xFF);
   495                     dst[1 + 8] = ((ce >> 8) & 0xFF);
   496                     dst[2 + 8] = (ce & 0xFF);
   497                     dst[3 + 8] = ((ce >> 8) & 0xFF);
   498                 }
   499             }
   500         }
   501         break;
   502 
   503     case AUDIO_S32:
   504         {
   505             Sint32 lf, rf, ce;
   506             const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
   507             Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 3);
   508 
   509             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   510                 for (i = cvt->len_cvt / 8; i; --i) {
   511                     dst -= 6;
   512                     src -= 2;
   513                     lf = (Sint32) SDL_SwapBE32(src[0]);
   514                     rf = (Sint32) SDL_SwapBE32(src[1]);
   515                     ce = (lf / 2) + (rf / 2);
   516                     dst[0] = SDL_SwapBE32((Uint32) lf);
   517                     dst[1] = SDL_SwapBE32((Uint32) rf);
   518                     dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
   519                     dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
   520                     dst[4] = SDL_SwapBE32((Uint32) ce);
   521                     dst[5] = SDL_SwapBE32((Uint32) ce);
   522                 }
   523             } else {
   524                 for (i = cvt->len_cvt / 8; i; --i) {
   525                     dst -= 6;
   526                     src -= 2;
   527                     lf = (Sint32) SDL_SwapLE32(src[0]);
   528                     rf = (Sint32) SDL_SwapLE32(src[1]);
   529                     ce = (lf / 2) + (rf / 2);
   530                     dst[0] = src[0];
   531                     dst[1] = src[1];
   532                     dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
   533                     dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
   534                     dst[4] = SDL_SwapLE32((Uint32) ce);
   535                     dst[5] = SDL_SwapLE32((Uint32) ce);
   536                 }
   537             }
   538         }
   539         break;
   540 
   541     case AUDIO_F32:
   542         {
   543             float lf, rf, ce;
   544             const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   545             float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
   546 
   547             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   548                 for (i = cvt->len_cvt / 8; i; --i) {
   549                     dst -= 6;
   550                     src -= 2;
   551                     lf = SDL_SwapFloatBE(src[0]);
   552                     rf = SDL_SwapFloatBE(src[1]);
   553                     ce = (lf * 0.5f) + (rf * 0.5f);
   554                     dst[0] = src[0];
   555                     dst[1] = src[1];
   556                     dst[2] = SDL_SwapFloatBE(lf - ce);
   557                     dst[3] = SDL_SwapFloatBE(rf - ce);
   558                     dst[4] = dst[5] = SDL_SwapFloatBE(ce);
   559                 }
   560             } else {
   561                 for (i = cvt->len_cvt / 8; i; --i) {
   562                     dst -= 6;
   563                     src -= 2;
   564                     lf = SDL_SwapFloatLE(src[0]);
   565                     rf = SDL_SwapFloatLE(src[1]);
   566                     ce = (lf * 0.5f) + (rf * 0.5f);
   567                     dst[0] = src[0];
   568                     dst[1] = src[1];
   569                     dst[2] = SDL_SwapFloatLE(lf - ce);
   570                     dst[3] = SDL_SwapFloatLE(rf - ce);
   571                     dst[4] = dst[5] = SDL_SwapFloatLE(ce);
   572                 }
   573             }
   574         }
   575         break;
   576 
   577     }
   578     cvt->len_cvt *= 3;
   579     if (cvt->filters[++cvt->filter_index]) {
   580         cvt->filters[cvt->filter_index] (cvt, format);
   581     }
   582 }
   583 
   584 
   585 /* Duplicate a stereo channel to a pseudo-4.0 stream */
   586 static void SDLCALL
   587 SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   588 {
   589     int i;
   590 
   591 #ifdef DEBUG_CONVERT
   592     fprintf(stderr, "Converting stereo to quad\n");
   593 #endif
   594 
   595     switch (format & (SDL_AUDIO_MASK_SIGNED |
   596                       SDL_AUDIO_MASK_BITSIZE |
   597                       SDL_AUDIO_MASK_DATATYPE)) {
   598     case AUDIO_U8:
   599         {
   600             Uint8 *src, *dst, lf, rf, ce;
   601 
   602             src = (Uint8 *) (cvt->buf + cvt->len_cvt);
   603             dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 2);
   604             for (i = cvt->len_cvt; i; --i) {
   605                 dst -= 4;
   606                 src -= 2;
   607                 lf = src[0];
   608                 rf = src[1];
   609                 ce = (lf / 2) + (rf / 2);
   610                 dst[0] = lf;
   611                 dst[1] = rf;
   612                 dst[2] = lf - ce;
   613                 dst[3] = rf - ce;
   614             }
   615         }
   616         break;
   617 
   618     case AUDIO_S8:
   619         {
   620             Sint8 *src, *dst, lf, rf, ce;
   621 
   622             src = (Sint8 *) cvt->buf + cvt->len_cvt;
   623             dst = (Sint8 *) cvt->buf + cvt->len_cvt * 2;
   624             for (i = cvt->len_cvt; i; --i) {
   625                 dst -= 4;
   626                 src -= 2;
   627                 lf = src[0];
   628                 rf = src[1];
   629                 ce = (lf / 2) + (rf / 2);
   630                 dst[0] = lf;
   631                 dst[1] = rf;
   632                 dst[2] = lf - ce;
   633                 dst[3] = rf - ce;
   634             }
   635         }
   636         break;
   637 
   638     case AUDIO_U16:
   639         {
   640             Uint8 *src, *dst;
   641             Uint16 lf, rf, ce, lr, rr;
   642 
   643             src = cvt->buf + cvt->len_cvt;
   644             dst = cvt->buf + cvt->len_cvt * 2;
   645 
   646             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   647                 for (i = cvt->len_cvt / 4; i; --i) {
   648                     dst -= 8;
   649                     src -= 4;
   650                     lf = (Uint16) ((src[0] << 8) | src[1]);
   651                     rf = (Uint16) ((src[2] << 8) | src[3]);
   652                     ce = (lf / 2) + (rf / 2);
   653                     rr = lf - ce;
   654                     lr = rf - ce;
   655                     dst[1] = (lf & 0xFF);
   656                     dst[0] = ((lf >> 8) & 0xFF);
   657                     dst[3] = (rf & 0xFF);
   658                     dst[2] = ((rf >> 8) & 0xFF);
   659 
   660                     dst[1 + 4] = (lr & 0xFF);
   661                     dst[0 + 4] = ((lr >> 8) & 0xFF);
   662                     dst[3 + 4] = (rr & 0xFF);
   663                     dst[2 + 4] = ((rr >> 8) & 0xFF);
   664                 }
   665             } else {
   666                 for (i = cvt->len_cvt / 4; i; --i) {
   667                     dst -= 8;
   668                     src -= 4;
   669                     lf = (Uint16) ((src[1] << 8) | src[0]);
   670                     rf = (Uint16) ((src[3] << 8) | src[2]);
   671                     ce = (lf / 2) + (rf / 2);
   672                     rr = lf - ce;
   673                     lr = rf - ce;
   674                     dst[0] = (lf & 0xFF);
   675                     dst[1] = ((lf >> 8) & 0xFF);
   676                     dst[2] = (rf & 0xFF);
   677                     dst[3] = ((rf >> 8) & 0xFF);
   678 
   679                     dst[0 + 4] = (lr & 0xFF);
   680                     dst[1 + 4] = ((lr >> 8) & 0xFF);
   681                     dst[2 + 4] = (rr & 0xFF);
   682                     dst[3 + 4] = ((rr >> 8) & 0xFF);
   683                 }
   684             }
   685         }
   686         break;
   687 
   688     case AUDIO_S16:
   689         {
   690             Uint8 *src, *dst;
   691             Sint16 lf, rf, ce, lr, rr;
   692 
   693             src = cvt->buf + cvt->len_cvt;
   694             dst = cvt->buf + cvt->len_cvt * 2;
   695 
   696             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   697                 for (i = cvt->len_cvt / 4; i; --i) {
   698                     dst -= 8;
   699                     src -= 4;
   700                     lf = (Sint16) ((src[0] << 8) | src[1]);
   701                     rf = (Sint16) ((src[2] << 8) | src[3]);
   702                     ce = (lf / 2) + (rf / 2);
   703                     rr = lf - ce;
   704                     lr = rf - ce;
   705                     dst[1] = (lf & 0xFF);
   706                     dst[0] = ((lf >> 8) & 0xFF);
   707                     dst[3] = (rf & 0xFF);
   708                     dst[2] = ((rf >> 8) & 0xFF);
   709 
   710                     dst[1 + 4] = (lr & 0xFF);
   711                     dst[0 + 4] = ((lr >> 8) & 0xFF);
   712                     dst[3 + 4] = (rr & 0xFF);
   713                     dst[2 + 4] = ((rr >> 8) & 0xFF);
   714                 }
   715             } else {
   716                 for (i = cvt->len_cvt / 4; i; --i) {
   717                     dst -= 8;
   718                     src -= 4;
   719                     lf = (Sint16) ((src[1] << 8) | src[0]);
   720                     rf = (Sint16) ((src[3] << 8) | src[2]);
   721                     ce = (lf / 2) + (rf / 2);
   722                     rr = lf - ce;
   723                     lr = rf - ce;
   724                     dst[0] = (lf & 0xFF);
   725                     dst[1] = ((lf >> 8) & 0xFF);
   726                     dst[2] = (rf & 0xFF);
   727                     dst[3] = ((rf >> 8) & 0xFF);
   728 
   729                     dst[0 + 4] = (lr & 0xFF);
   730                     dst[1 + 4] = ((lr >> 8) & 0xFF);
   731                     dst[2 + 4] = (rr & 0xFF);
   732                     dst[3 + 4] = ((rr >> 8) & 0xFF);
   733                 }
   734             }
   735         }
   736         break;
   737 
   738     case AUDIO_S32:
   739         {
   740             const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
   741             Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 2);
   742             Sint32 lf, rf, ce;
   743 
   744             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   745                 for (i = cvt->len_cvt / 8; i; --i) {
   746                     dst -= 4;
   747                     src -= 2;
   748                     lf = (Sint32) SDL_SwapBE32(src[0]);
   749                     rf = (Sint32) SDL_SwapBE32(src[1]);
   750                     ce = (lf / 2) + (rf / 2);
   751                     dst[0] = src[0];
   752                     dst[1] = src[1];
   753                     dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
   754                     dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
   755                 }
   756             } else {
   757                 for (i = cvt->len_cvt / 8; i; --i) {
   758                     dst -= 4;
   759                     src -= 2;
   760                     lf = (Sint32) SDL_SwapLE32(src[0]);
   761                     rf = (Sint32) SDL_SwapLE32(src[1]);
   762                     ce = (lf / 2) + (rf / 2);
   763                     dst[0] = src[0];
   764                     dst[1] = src[1];
   765                     dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
   766                     dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
   767                 }
   768             }
   769         }
   770         break;
   771 
   772     case AUDIO_F32:
   773         {
   774             const float *src = (const float *) (cvt->buf + cvt->len_cvt);
   775             float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
   776             float lf, rf, ce;
   777 
   778             if (SDL_AUDIO_ISBIGENDIAN(format)) {
   779                 for (i = cvt->len_cvt / 8; i; --i) {
   780                     dst -= 4;
   781                     src -= 2;
   782                     lf = SDL_SwapFloatBE(src[0]);
   783                     rf = SDL_SwapFloatBE(src[1]);
   784                     ce = (lf / 2) + (rf / 2);
   785                     dst[0] = src[0];
   786                     dst[1] = src[1];
   787                     dst[2] = SDL_SwapFloatBE(lf - ce);
   788                     dst[3] = SDL_SwapFloatBE(rf - ce);
   789                 }
   790             } else {
   791                 for (i = cvt->len_cvt / 8; i; --i) {
   792                     dst -= 4;
   793                     src -= 2;
   794                     lf = SDL_SwapFloatLE(src[0]);
   795                     rf = SDL_SwapFloatLE(src[1]);
   796                     ce = (lf / 2) + (rf / 2);
   797                     dst[0] = src[0];
   798                     dst[1] = src[1];
   799                     dst[2] = SDL_SwapFloatLE(lf - ce);
   800                     dst[3] = SDL_SwapFloatLE(rf - ce);
   801                 }
   802             }
   803         }
   804         break;
   805     }
   806     cvt->len_cvt *= 2;
   807     if (cvt->filters[++cvt->filter_index]) {
   808         cvt->filters[cvt->filter_index] (cvt, format);
   809     }
   810 }
   811 
   812 
   813 int
   814 SDL_ConvertAudio(SDL_AudioCVT * cvt)
   815 {
   816     /* !!! FIXME: (cvt) should be const; stack-copy it here. */
   817     /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
   818 
   819     /* Make sure there's data to convert */
   820     if (cvt->buf == NULL) {
   821         SDL_SetError("No buffer allocated for conversion");
   822         return (-1);
   823     }
   824     /* Return okay if no conversion is necessary */
   825     cvt->len_cvt = cvt->len;
   826     if (cvt->filters[0] == NULL) {
   827         return (0);
   828     }
   829 
   830     /* Set up the conversion and go! */
   831     cvt->filter_index = 0;
   832     cvt->filters[0] (cvt, cvt->src_format);
   833     return (0);
   834 }
   835 
   836 
   837 static SDL_AudioFilter
   838 SDL_HandTunedTypeCVT(SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
   839 {
   840     /*
   841      * Fill in any future conversions that are specialized to a
   842      *  processor, platform, compiler, or library here.
   843      */
   844 
   845     return NULL;                /* no specialized converter code available. */
   846 }
   847 
   848 
   849 /*
   850  * Find a converter between two data types. We try to select a hand-tuned
   851  *  asm/vectorized/optimized function first, and then fallback to an
   852  *  autogenerated function that is customized to convert between two
   853  *  specific data types.
   854  */
   855 static int
   856 SDL_BuildAudioTypeCVT(SDL_AudioCVT * cvt,
   857                       SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
   858 {
   859     if (src_fmt != dst_fmt) {
   860         const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
   861         const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
   862         SDL_AudioFilter filter = SDL_HandTunedTypeCVT(src_fmt, dst_fmt);
   863 
   864         /* No hand-tuned converter? Try the autogenerated ones. */
   865         if (filter == NULL) {
   866             int i;
   867             for (i = 0; sdl_audio_type_filters[i].filter != NULL; i++) {
   868                 const SDL_AudioTypeFilters *filt = &sdl_audio_type_filters[i];
   869                 if ((filt->src_fmt == src_fmt) && (filt->dst_fmt == dst_fmt)) {
   870                     filter = filt->filter;
   871                     break;
   872                 }
   873             }
   874 
   875             if (filter == NULL) {
   876                 SDL_SetError("No conversion available for these formats");
   877                 return -1;
   878             }
   879         }
   880 
   881         /* Update (cvt) with filter details... */
   882         cvt->filters[cvt->filter_index++] = filter;
   883         if (src_bitsize < dst_bitsize) {
   884             const int mult = (dst_bitsize / src_bitsize);
   885             cvt->len_mult *= mult;
   886             cvt->len_ratio *= mult;
   887         } else if (src_bitsize > dst_bitsize) {
   888             cvt->len_ratio /= (src_bitsize / dst_bitsize);
   889         }
   890 
   891         return 1;               /* added a converter. */
   892     }
   893 
   894     return 0;                   /* no conversion necessary. */
   895 }
   896 
   897 
   898 static SDL_AudioFilter
   899 SDL_HandTunedResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
   900                          int src_rate, int dst_rate)
   901 {
   902     /*
   903      * Fill in any future conversions that are specialized to a
   904      *  processor, platform, compiler, or library here.
   905      */
   906 
   907     return NULL;                /* no specialized converter code available. */
   908 }
   909 
   910 static int
   911 SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
   912 {
   913     int retval = 0;
   914 
   915     /* If we only built with the arbitrary resamplers, ignore multiples. */
   916 #if !LESS_RESAMPLERS
   917     int lo, hi;
   918     int div;
   919 
   920     SDL_assert(src_rate != 0);
   921     SDL_assert(dst_rate != 0);
   922     SDL_assert(src_rate != dst_rate);
   923 
   924     if (src_rate < dst_rate) {
   925         lo = src_rate;
   926         hi = dst_rate;
   927     } else {
   928         lo = dst_rate;
   929         hi = src_rate;
   930     }
   931 
   932     /* zero means "not a supported multiple" ... we only do 2x and 4x. */
   933     if ((hi % lo) != 0)
   934         return 0;               /* not a multiple. */
   935 
   936     div = hi / lo;
   937     retval = ((div == 2) || (div == 4)) ? div : 0;
   938 #endif
   939 
   940     return retval;
   941 }
   942 
   943 static int
   944 SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
   945                           int src_rate, int dst_rate)
   946 {
   947     if (src_rate != dst_rate) {
   948         SDL_AudioFilter filter = SDL_HandTunedResampleCVT(cvt, dst_channels,
   949                                                           src_rate, dst_rate);
   950 
   951         /* No hand-tuned converter? Try the autogenerated ones. */
   952         if (filter == NULL) {
   953             int i;
   954             const int upsample = (src_rate < dst_rate) ? 1 : 0;
   955             const int multiple =
   956                 SDL_FindFrequencyMultiple(src_rate, dst_rate);
   957 
   958             for (i = 0; sdl_audio_rate_filters[i].filter != NULL; i++) {
   959                 const SDL_AudioRateFilters *filt = &sdl_audio_rate_filters[i];
   960                 if ((filt->fmt == cvt->dst_format) &&
   961                     (filt->channels == dst_channels) &&
   962                     (filt->upsample == upsample) &&
   963                     (filt->multiple == multiple)) {
   964                     filter = filt->filter;
   965                     break;
   966                 }
   967             }
   968 
   969             if (filter == NULL) {
   970                 SDL_SetError("No conversion available for these rates");
   971                 return -1;
   972             }
   973         }
   974 
   975         /* Update (cvt) with filter details... */
   976         cvt->filters[cvt->filter_index++] = filter;
   977         if (src_rate < dst_rate) {
   978             const double mult = ((double) dst_rate) / ((double) src_rate);
   979             cvt->len_mult *= (int) SDL_ceil(mult);
   980             cvt->len_ratio *= mult;
   981         } else {
   982             cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   983         }
   984 
   985         return 1;               /* added a converter. */
   986     }
   987 
   988     return 0;                   /* no conversion necessary. */
   989 }
   990 
   991 
   992 /* Creates a set of audio filters to convert from one format to another.
   993    Returns -1 if the format conversion is not supported, 0 if there's
   994    no conversion needed, or 1 if the audio filter is set up.
   995 */
   996 
   997 int
   998 SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
   999                   SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
  1000                   SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
  1001 {
  1002     /*
  1003      * !!! FIXME: reorder filters based on which grow/shrink the buffer.
  1004      * !!! FIXME: ideally, we should do everything that shrinks the buffer
  1005      * !!! FIXME: first, so we don't have to process as many bytes in a given
  1006      * !!! FIXME: filter and abuse the CPU cache less. This might not be as
  1007      * !!! FIXME: good in practice as it sounds in theory, though.
  1008      */
  1009 
  1010     /* Sanity check target pointer */
  1011     if (cvt == NULL) {
  1012         return SDL_InvalidParamError("cvt");
  1013     }
  1014 
  1015     /* there are no unsigned types over 16 bits, so catch this up front. */
  1016     if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
  1017         return SDL_SetError("Invalid source format");
  1018     }
  1019     if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
  1020         return SDL_SetError("Invalid destination format");
  1021     }
  1022 
  1023     /* prevent possible divisions by zero, etc. */
  1024     if ((src_channels == 0) || (dst_channels == 0)) {
  1025         return SDL_SetError("Source or destination channels is zero");
  1026     }
  1027     if ((src_rate == 0) || (dst_rate == 0)) {
  1028         return SDL_SetError("Source or destination rate is zero");
  1029     }
  1030 #ifdef DEBUG_CONVERT
  1031     printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
  1032            src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
  1033 #endif
  1034 
  1035     /* Start off with no conversion necessary */
  1036     SDL_zerop(cvt);
  1037     cvt->src_format = src_fmt;
  1038     cvt->dst_format = dst_fmt;
  1039     cvt->needed = 0;
  1040     cvt->filter_index = 0;
  1041     cvt->filters[0] = NULL;
  1042     cvt->len_mult = 1;
  1043     cvt->len_ratio = 1.0;
  1044     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
  1045 
  1046     /* Convert data types, if necessary. Updates (cvt). */
  1047     if (SDL_BuildAudioTypeCVT(cvt, src_fmt, dst_fmt) == -1) {
  1048         return -1;              /* shouldn't happen, but just in case... */
  1049     }
  1050 
  1051     /* Channel conversion */
  1052     if (src_channels != dst_channels) {
  1053         if ((src_channels == 1) && (dst_channels > 1)) {
  1054             cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
  1055             cvt->len_mult *= 2;
  1056             src_channels = 2;
  1057             cvt->len_ratio *= 2;
  1058         }
  1059         if ((src_channels == 2) && (dst_channels == 6)) {
  1060             cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
  1061             src_channels = 6;
  1062             cvt->len_mult *= 3;
  1063             cvt->len_ratio *= 3;
  1064         }
  1065         if ((src_channels == 2) && (dst_channels == 4)) {
  1066             cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
  1067             src_channels = 4;
  1068             cvt->len_mult *= 2;
  1069             cvt->len_ratio *= 2;
  1070         }
  1071         while ((src_channels * 2) <= dst_channels) {
  1072             cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
  1073             cvt->len_mult *= 2;
  1074             src_channels *= 2;
  1075             cvt->len_ratio *= 2;
  1076         }
  1077         if ((src_channels == 6) && (dst_channels <= 2)) {
  1078             cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
  1079             src_channels = 2;
  1080             cvt->len_ratio /= 3;
  1081         }
  1082         if ((src_channels == 6) && (dst_channels == 4)) {
  1083             cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
  1084             src_channels = 4;
  1085             cvt->len_ratio /= 2;
  1086         }
  1087         /* This assumes that 4 channel audio is in the format:
  1088            Left {front/back} + Right {front/back}
  1089            so converting to L/R stereo works properly.
  1090          */
  1091         while (((src_channels % 2) == 0) &&
  1092                ((src_channels / 2) >= dst_channels)) {
  1093             cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
  1094             src_channels /= 2;
  1095             cvt->len_ratio /= 2;
  1096         }
  1097         if (src_channels != dst_channels) {
  1098             /* Uh oh.. */ ;
  1099         }
  1100     }
  1101 
  1102     /* Do rate conversion, if necessary. Updates (cvt). */
  1103     if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) ==
  1104         -1) {
  1105         return -1;              /* shouldn't happen, but just in case... */
  1106     }
  1107 
  1108     /* Set up the filter information */
  1109     if (cvt->filter_index != 0) {
  1110         cvt->needed = 1;
  1111         cvt->src_format = src_fmt;
  1112         cvt->dst_format = dst_fmt;
  1113         cvt->len = 0;
  1114         cvt->buf = NULL;
  1115         cvt->filters[cvt->filter_index] = NULL;
  1116     }
  1117     return (cvt->needed);
  1118 }
  1119 
  1120 
  1121 /* vi: set ts=4 sw=4 expandtab: */