src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 24 Aug 2006 12:10:46 +0000
changeset 1982 3b4ce57c6215
parent 1895 c121d94672cb
child 1985 8055185ae4ed
permissions -rw-r--r--
First shot at new audio data types (int32 and float32).

Notable changes:
- Converters between types are autogenerated. Instead of making multiple
passes over the data with seperate filters for endianess, size, signedness,
etc, converting between data types is always one specialized filter. This
simplifies SDL_BuildAudioCVT(), which otherwise had a million edge cases
with the new types, and makes the actually conversions more CPU cache
friendly. Left a stub for adding specific optimized versions of these
routines (SSE/MMX/Altivec, assembler, etc)
- Autogenerated converters are built by SDL/src/audio/sdlgenaudiocvt.pl. This
does not need to be run unless tweaking the code, and thus doesn't need
integration into the build system.
- Went through all the drivers and tried to weed out all the "Uint16"
references that are better specified with the new SDL_AudioFormat typedef.
- Cleaned out a bunch of hardcoded bitwise magic numbers and replaced them
with new SDL_AUDIO_* macros.
- Added initial float32 and int32 support code. Theoretically, existing
drivers will push these through converters to get the data they want to
feed to the hardware.

Still TODO:
- Optimize and debug new converters.
- Update the CoreAudio backend to accept float32 data directly.
- Other backends, too?
- SDL_LoadWAV() needs to be updated to support int32 and float32 .wav files
(both of which exist and can be generated by 'sox' for testing purposes).
- Update the mixer to handle new datatypes.
- Optionally update SDL_sound and SDL_mixer, etc.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* Functions for audio drivers to perform runtime conversion of audio format */
slouken@0
    25
slouken@0
    26
#include "SDL_audio.h"
icculus@1982
    27
#include "SDL_audio_c.h"
slouken@0
    28
slouken@0
    29
/* Effectively mix right and left channels into a single channel */
icculus@1982
    30
static void SDLCALL
icculus@1982
    31
SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
    32
{
slouken@1895
    33
    int i;
slouken@1895
    34
    Sint32 sample;
slouken@0
    35
slouken@0
    36
#ifdef DEBUG_CONVERT
slouken@1895
    37
    fprintf(stderr, "Converting to mono\n");
slouken@0
    38
#endif
icculus@1982
    39
    switch (format & (SDL_AUDIO_MASK_SIGNED|SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
    40
    case AUDIO_U8:
slouken@1895
    41
        {
slouken@1895
    42
            Uint8 *src, *dst;
slouken@0
    43
slouken@1895
    44
            src = cvt->buf;
slouken@1895
    45
            dst = cvt->buf;
slouken@1895
    46
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    47
                sample = src[0] + src[1];
slouken@1895
    48
                if (sample > 255) {
slouken@1895
    49
                    *dst = 255;
slouken@1895
    50
                } else {
slouken@1895
    51
                    *dst = (Uint8) sample;
slouken@1895
    52
                }
slouken@1895
    53
                src += 2;
slouken@1895
    54
                dst += 1;
slouken@1895
    55
            }
slouken@1895
    56
        }
slouken@1895
    57
        break;
slouken@0
    58
slouken@1895
    59
    case AUDIO_S8:
slouken@1895
    60
        {
slouken@1895
    61
            Sint8 *src, *dst;
slouken@0
    62
slouken@1895
    63
            src = (Sint8 *) cvt->buf;
slouken@1895
    64
            dst = (Sint8 *) cvt->buf;
slouken@1895
    65
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    66
                sample = src[0] + src[1];
slouken@1895
    67
                if (sample > 127) {
slouken@1895
    68
                    *dst = 127;
slouken@1895
    69
                } else if (sample < -128) {
slouken@1895
    70
                    *dst = -128;
slouken@1895
    71
                } else {
slouken@1895
    72
                    *dst = (Sint8) sample;
slouken@1895
    73
                }
slouken@1895
    74
                src += 2;
slouken@1895
    75
                dst += 1;
slouken@1895
    76
            }
slouken@1895
    77
        }
slouken@1895
    78
        break;
slouken@0
    79
slouken@1895
    80
    case AUDIO_U16:
slouken@1895
    81
        {
slouken@1895
    82
            Uint8 *src, *dst;
slouken@0
    83
slouken@1895
    84
            src = cvt->buf;
slouken@1895
    85
            dst = cvt->buf;
icculus@1982
    86
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
    87
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
    88
                    sample = (Uint16) ((src[0] << 8) | src[1]) +
slouken@1895
    89
                        (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
    90
                    if (sample > 65535) {
slouken@1895
    91
                        dst[0] = 0xFF;
slouken@1895
    92
                        dst[1] = 0xFF;
slouken@1895
    93
                    } else {
slouken@1895
    94
                        dst[1] = (sample & 0xFF);
slouken@1895
    95
                        sample >>= 8;
slouken@1895
    96
                        dst[0] = (sample & 0xFF);
slouken@1895
    97
                    }
slouken@1895
    98
                    src += 4;
slouken@1895
    99
                    dst += 2;
slouken@1895
   100
                }
slouken@1895
   101
            } else {
slouken@1895
   102
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   103
                    sample = (Uint16) ((src[1] << 8) | src[0]) +
slouken@1895
   104
                        (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   105
                    if (sample > 65535) {
slouken@1895
   106
                        dst[0] = 0xFF;
slouken@1895
   107
                        dst[1] = 0xFF;
slouken@1895
   108
                    } else {
slouken@1895
   109
                        dst[0] = (sample & 0xFF);
slouken@1895
   110
                        sample >>= 8;
slouken@1895
   111
                        dst[1] = (sample & 0xFF);
slouken@1895
   112
                    }
slouken@1895
   113
                    src += 4;
slouken@1895
   114
                    dst += 2;
slouken@1895
   115
                }
slouken@1895
   116
            }
slouken@1895
   117
        }
slouken@1895
   118
        break;
slouken@0
   119
slouken@1895
   120
    case AUDIO_S16:
slouken@1895
   121
        {
slouken@1895
   122
            Uint8 *src, *dst;
slouken@0
   123
slouken@1895
   124
            src = cvt->buf;
slouken@1895
   125
            dst = cvt->buf;
icculus@1982
   126
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   127
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   128
                    sample = (Sint16) ((src[0] << 8) | src[1]) +
slouken@1895
   129
                        (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   130
                    if (sample > 32767) {
slouken@1895
   131
                        dst[0] = 0x7F;
slouken@1895
   132
                        dst[1] = 0xFF;
slouken@1895
   133
                    } else if (sample < -32768) {
slouken@1895
   134
                        dst[0] = 0x80;
slouken@1895
   135
                        dst[1] = 0x00;
slouken@1895
   136
                    } else {
slouken@1895
   137
                        dst[1] = (sample & 0xFF);
slouken@1895
   138
                        sample >>= 8;
slouken@1895
   139
                        dst[0] = (sample & 0xFF);
slouken@1895
   140
                    }
slouken@1895
   141
                    src += 4;
slouken@1895
   142
                    dst += 2;
slouken@1895
   143
                }
slouken@1895
   144
            } else {
slouken@1895
   145
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   146
                    sample = (Sint16) ((src[1] << 8) | src[0]) +
slouken@1895
   147
                        (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   148
                    if (sample > 32767) {
slouken@1895
   149
                        dst[1] = 0x7F;
slouken@1895
   150
                        dst[0] = 0xFF;
slouken@1895
   151
                    } else if (sample < -32768) {
slouken@1895
   152
                        dst[1] = 0x80;
slouken@1895
   153
                        dst[0] = 0x00;
slouken@1895
   154
                    } else {
slouken@1895
   155
                        dst[0] = (sample & 0xFF);
slouken@1895
   156
                        sample >>= 8;
slouken@1895
   157
                        dst[1] = (sample & 0xFF);
slouken@1895
   158
                    }
slouken@1895
   159
                    src += 4;
slouken@1895
   160
                    dst += 2;
slouken@1895
   161
                }
slouken@1895
   162
            }
slouken@1895
   163
        }
slouken@1895
   164
        break;
icculus@1982
   165
icculus@1982
   166
    case AUDIO_S32:
icculus@1982
   167
        {
icculus@1982
   168
            const Uint32 *src = (const Uint32 *) cvt->buf;
icculus@1982
   169
            Uint32 *dst = (Uint32 *) cvt->buf;
icculus@1982
   170
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   171
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   172
                    const Sint64 added =
icculus@1982
   173
                                    (((Sint64) (Sint32) SDL_SwapBE32(src[0])) +
icculus@1982
   174
                                     ((Sint64) (Sint32) SDL_SwapBE32(src[1])));
icculus@1982
   175
                    *(dst++) = SDL_SwapBE32((Uint32) ((Sint32) (added >> 1)));
icculus@1982
   176
                }
icculus@1982
   177
            } else {
icculus@1982
   178
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   179
                    const Sint64 added =
icculus@1982
   180
                                    (((Sint64) (Sint32) SDL_SwapLE32(src[0])) +
icculus@1982
   181
                                     ((Sint64) (Sint32) SDL_SwapLE32(src[1])));
icculus@1982
   182
                    *(dst++) = SDL_SwapLE32((Uint32) ((Sint32) (added >> 1)));
icculus@1982
   183
                }
icculus@1982
   184
            }
icculus@1982
   185
        }
icculus@1982
   186
        break;
icculus@1982
   187
icculus@1982
   188
    case AUDIO_F32:
icculus@1982
   189
        {
icculus@1982
   190
            /* !!! FIXME: this convert union is nasty. */
icculus@1982
   191
            union { float f; Uint32 ui32; } f2i;
icculus@1982
   192
            const Uint32 *src = (const Uint32 *) cvt->buf;
icculus@1982
   193
            Uint32 *dst = (Uint32 *) cvt->buf;
icculus@1982
   194
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   195
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   196
                    float src1, src2;
icculus@1982
   197
                    f2i.ui32 = SDL_SwapBE32(src[0]);
icculus@1982
   198
                    src1 = f2i.f;
icculus@1982
   199
                    f2i.ui32 = SDL_SwapBE32(src[1]);
icculus@1982
   200
                    src2 = f2i.f;
icculus@1982
   201
                    const double added = ((double) src1) + ((double) src2);
icculus@1982
   202
                    f2i.f = (float) (added * 0.5);
icculus@1982
   203
                    *(dst++) = SDL_SwapBE32(f2i.ui32);
icculus@1982
   204
                }
icculus@1982
   205
            } else {
icculus@1982
   206
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   207
                    float src1, src2;
icculus@1982
   208
                    f2i.ui32 = SDL_SwapLE32(src[0]);
icculus@1982
   209
                    src1 = f2i.f;
icculus@1982
   210
                    f2i.ui32 = SDL_SwapLE32(src[1]);
icculus@1982
   211
                    src2 = f2i.f;
icculus@1982
   212
                    const double added = ((double) src1) + ((double) src2);
icculus@1982
   213
                    f2i.f = (float) (added * 0.5);
icculus@1982
   214
                    *(dst++) = SDL_SwapLE32(f2i.ui32);
icculus@1982
   215
                }
icculus@1982
   216
            }
icculus@1982
   217
        }
icculus@1982
   218
        break;
slouken@1895
   219
    }
icculus@1982
   220
slouken@1895
   221
    cvt->len_cvt /= 2;
slouken@1895
   222
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   223
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   224
    }
slouken@0
   225
}
slouken@0
   226
icculus@1982
   227
slouken@942
   228
/* Discard top 4 channels */
icculus@1982
   229
static void SDLCALL
icculus@1982
   230
SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   231
{
slouken@1895
   232
    int i;
slouken@942
   233
slouken@942
   234
#ifdef DEBUG_CONVERT
icculus@1982
   235
    fprintf(stderr, "Converting down from 6 channels to stereo\n");
slouken@942
   236
#endif
slouken@942
   237
icculus@1982
   238
    #define strip_chans_6_to_2(type) \
icculus@1982
   239
    { \
icculus@1982
   240
        const type *src = (const type *) cvt->buf; \
icculus@1982
   241
        type *dst = (type *) cvt->buf; \
icculus@1982
   242
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   243
            dst[0] = src[0]; \
icculus@1982
   244
            dst[1] = src[1]; \
icculus@1982
   245
            src += 6; \
icculus@1982
   246
            dst += 2; \
icculus@1982
   247
        } \
icculus@1982
   248
    }
slouken@942
   249
icculus@1982
   250
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   251
    switch (SDL_AUDIO_BITSIZE(format)) {
icculus@1982
   252
        case 8:
icculus@1982
   253
            strip_chans_6_to_2(Uint8);
icculus@1982
   254
            break;
icculus@1982
   255
        case 16:
icculus@1982
   256
            strip_chans_6_to_2(Uint16);
icculus@1982
   257
            break;
icculus@1982
   258
        case 32:
icculus@1982
   259
            strip_chans_6_to_2(Uint32);
icculus@1982
   260
            break;
icculus@1982
   261
    }
slouken@942
   262
icculus@1982
   263
    #undef strip_chans_6_to_2
slouken@942
   264
slouken@1895
   265
    cvt->len_cvt /= 3;
slouken@1895
   266
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   267
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   268
    }
slouken@942
   269
}
slouken@942
   270
slouken@942
   271
slouken@942
   272
/* Discard top 2 channels of 6 */
icculus@1982
   273
static void SDLCALL
icculus@1982
   274
SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   275
{
slouken@1895
   276
    int i;
slouken@942
   277
slouken@942
   278
#ifdef DEBUG_CONVERT
slouken@1895
   279
    fprintf(stderr, "Converting 6 down to quad\n");
slouken@942
   280
#endif
slouken@942
   281
icculus@1982
   282
    #define strip_chans_6_to_4(type) \
icculus@1982
   283
    { \
icculus@1982
   284
        const type *src = (const type *) cvt->buf; \
icculus@1982
   285
        type *dst = (type *) cvt->buf; \
icculus@1982
   286
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   287
            dst[0] = src[0]; \
icculus@1982
   288
            dst[1] = src[1]; \
icculus@1982
   289
            dst[2] = src[2]; \
icculus@1982
   290
            dst[3] = src[3]; \
icculus@1982
   291
            src += 6; \
icculus@1982
   292
            dst += 4; \
icculus@1982
   293
        } \
icculus@1982
   294
    }
slouken@942
   295
icculus@1982
   296
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   297
    switch (SDL_AUDIO_BITSIZE(format)) {
icculus@1982
   298
        case 8:
icculus@1982
   299
            strip_chans_6_to_4(Uint8);
icculus@1982
   300
            break;
icculus@1982
   301
        case 16:
icculus@1982
   302
            strip_chans_6_to_4(Uint16);
icculus@1982
   303
            break;
icculus@1982
   304
        case 32:
icculus@1982
   305
            strip_chans_6_to_4(Uint32);
icculus@1982
   306
            break;
icculus@1982
   307
    }
slouken@942
   308
icculus@1982
   309
    #undef strip_chans_6_to_4
slouken@942
   310
icculus@1982
   311
    cvt->len_cvt /= 6;
icculus@1982
   312
    cvt->len_cvt *= 4;
slouken@1895
   313
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   314
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   315
    }
slouken@942
   316
}
slouken@0
   317
slouken@0
   318
/* Duplicate a mono channel to both stereo channels */
icculus@1982
   319
static void SDLCALL
icculus@1982
   320
SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
   321
{
slouken@1895
   322
    int i;
slouken@0
   323
slouken@0
   324
#ifdef DEBUG_CONVERT
slouken@1895
   325
    fprintf(stderr, "Converting to stereo\n");
slouken@0
   326
#endif
slouken@0
   327
icculus@1982
   328
    #define dup_chans_1_to_2(type) \
icculus@1982
   329
    { \
icculus@1982
   330
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   331
        type *dst = (type *) (cvt->buf + cvt->len_cvt * 2); \
icculus@1982
   332
        for (i = cvt->len_cvt / 2; i; --i, --src) { \
icculus@1982
   333
            const type val = *src; \
icculus@1982
   334
            dst -= 2; \
icculus@1982
   335
            dst[0] = dst[1] = val; \
icculus@1982
   336
        } \
icculus@1982
   337
    }
slouken@0
   338
icculus@1982
   339
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   340
    switch (SDL_AUDIO_BITSIZE(format)) {
icculus@1982
   341
        case 8:
icculus@1982
   342
            dup_chans_1_to_2(Uint8);
icculus@1982
   343
            break;
icculus@1982
   344
        case 16:
icculus@1982
   345
            dup_chans_1_to_2(Uint16);
icculus@1982
   346
            break;
icculus@1982
   347
        case 32:
icculus@1982
   348
            dup_chans_1_to_2(Uint32);
icculus@1982
   349
            break;
slouken@1895
   350
    }
icculus@1982
   351
icculus@1982
   352
    #undef dup_chans_1_to_2
icculus@1982
   353
slouken@1895
   354
    cvt->len_cvt *= 2;
slouken@1895
   355
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   356
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   357
    }
slouken@0
   358
}
slouken@0
   359
slouken@942
   360
slouken@942
   361
/* Duplicate a stereo channel to a pseudo-5.1 stream */
icculus@1982
   362
static void SDLCALL
icculus@1982
   363
SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   364
{
slouken@1895
   365
    int i;
slouken@942
   366
slouken@942
   367
#ifdef DEBUG_CONVERT
slouken@1895
   368
    fprintf(stderr, "Converting stereo to surround\n");
slouken@942
   369
#endif
slouken@942
   370
icculus@1982
   371
    switch (format & (SDL_AUDIO_MASK_SIGNED|SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
   372
    case AUDIO_U8:
slouken@1895
   373
        {
slouken@1895
   374
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   375
slouken@1895
   376
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   377
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 3);
slouken@1895
   378
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   379
                dst -= 6;
slouken@1895
   380
                src -= 2;
slouken@1895
   381
                lf = src[0];
slouken@1895
   382
                rf = src[1];
slouken@1895
   383
                ce = (lf / 2) + (rf / 2);
slouken@1895
   384
                dst[0] = lf;
slouken@1895
   385
                dst[1] = rf;
slouken@1895
   386
                dst[2] = lf - ce;
slouken@1895
   387
                dst[3] = rf - ce;
slouken@1895
   388
                dst[4] = ce;
slouken@1895
   389
                dst[5] = ce;
slouken@1895
   390
            }
slouken@1895
   391
        }
slouken@1895
   392
        break;
slouken@942
   393
slouken@1895
   394
    case AUDIO_S8:
slouken@1895
   395
        {
slouken@1895
   396
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   397
slouken@1895
   398
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   399
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 3;
slouken@1895
   400
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   401
                dst -= 6;
slouken@1895
   402
                src -= 2;
slouken@1895
   403
                lf = src[0];
slouken@1895
   404
                rf = src[1];
slouken@1895
   405
                ce = (lf / 2) + (rf / 2);
slouken@1895
   406
                dst[0] = lf;
slouken@1895
   407
                dst[1] = rf;
slouken@1895
   408
                dst[2] = lf - ce;
slouken@1895
   409
                dst[3] = rf - ce;
slouken@1895
   410
                dst[4] = ce;
slouken@1895
   411
                dst[5] = ce;
slouken@1895
   412
            }
slouken@1895
   413
        }
slouken@1895
   414
        break;
slouken@942
   415
slouken@1895
   416
    case AUDIO_U16:
slouken@1895
   417
        {
slouken@1895
   418
            Uint8 *src, *dst;
slouken@1895
   419
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   420
slouken@1895
   421
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   422
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   423
icculus@1982
   424
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   425
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   426
                    dst -= 12;
slouken@1895
   427
                    src -= 4;
slouken@1895
   428
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   429
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   430
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   431
                    rr = lf - ce;
slouken@1895
   432
                    lr = rf - ce;
slouken@1895
   433
                    dst[1] = (lf & 0xFF);
slouken@1895
   434
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   435
                    dst[3] = (rf & 0xFF);
slouken@1895
   436
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   437
slouken@1895
   438
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   439
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   440
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   441
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   442
slouken@1895
   443
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   444
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   445
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   446
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   447
                }
slouken@1895
   448
            } else {
slouken@1895
   449
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   450
                    dst -= 12;
slouken@1895
   451
                    src -= 4;
slouken@1895
   452
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   453
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   454
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   455
                    rr = lf - ce;
slouken@1895
   456
                    lr = rf - ce;
slouken@1895
   457
                    dst[0] = (lf & 0xFF);
slouken@1895
   458
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   459
                    dst[2] = (rf & 0xFF);
slouken@1895
   460
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   461
slouken@1895
   462
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   463
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   464
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   465
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   466
slouken@1895
   467
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   468
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   469
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   470
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   471
                }
slouken@1895
   472
            }
slouken@1895
   473
        }
slouken@1895
   474
        break;
slouken@942
   475
slouken@1895
   476
    case AUDIO_S16:
slouken@1895
   477
        {
slouken@1895
   478
            Uint8 *src, *dst;
slouken@1895
   479
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   480
slouken@1895
   481
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   482
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   483
icculus@1982
   484
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   485
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   486
                    dst -= 12;
slouken@1895
   487
                    src -= 4;
slouken@1895
   488
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   489
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   490
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   491
                    rr = lf - ce;
slouken@1895
   492
                    lr = rf - ce;
slouken@1895
   493
                    dst[1] = (lf & 0xFF);
slouken@1895
   494
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   495
                    dst[3] = (rf & 0xFF);
slouken@1895
   496
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   497
slouken@1895
   498
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   499
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   500
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   501
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   502
slouken@1895
   503
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   504
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   505
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   506
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   507
                }
slouken@1895
   508
            } else {
slouken@1895
   509
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   510
                    dst -= 12;
slouken@1895
   511
                    src -= 4;
slouken@1895
   512
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   513
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   514
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   515
                    rr = lf - ce;
slouken@1895
   516
                    lr = rf - ce;
slouken@1895
   517
                    dst[0] = (lf & 0xFF);
slouken@1895
   518
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   519
                    dst[2] = (rf & 0xFF);
slouken@1895
   520
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   521
slouken@1895
   522
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   523
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   524
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   525
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   526
slouken@1895
   527
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   528
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   529
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   530
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   531
                }
slouken@1895
   532
            }
slouken@1895
   533
        }
slouken@1895
   534
        break;
icculus@1982
   535
icculus@1982
   536
    case AUDIO_S32:
icculus@1982
   537
        {
icculus@1982
   538
            Sint32 lf, rf, ce;
icculus@1982
   539
            const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt;
icculus@1982
   540
            Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3;
icculus@1982
   541
icculus@1982
   542
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   543
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   544
                    dst -= 6;
icculus@1982
   545
                    src -= 2;
icculus@1982
   546
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   547
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   548
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   549
                    dst[0] = SDL_SwapBE32((Uint32) lf);
icculus@1982
   550
                    dst[1] = SDL_SwapBE32((Uint32) rf);
icculus@1982
   551
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   552
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   553
                    dst[4] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   554
                    dst[5] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   555
                }
icculus@1982
   556
            } else {
icculus@1982
   557
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   558
                    dst -= 6;
icculus@1982
   559
                    src -= 2;
icculus@1982
   560
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   561
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   562
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   563
                    dst[0] = src[0];
icculus@1982
   564
                    dst[1] = src[1];
icculus@1982
   565
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   566
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   567
                    dst[4] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   568
                    dst[5] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   569
                }
icculus@1982
   570
            }
icculus@1982
   571
        }
icculus@1982
   572
        break;
icculus@1982
   573
icculus@1982
   574
    case AUDIO_F32:
icculus@1982
   575
        {
icculus@1982
   576
            union { float f; Uint32 ui32; } f2i;  /* !!! FIXME: lame. */
icculus@1982
   577
            float lf, rf, ce;
icculus@1982
   578
            const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt;
icculus@1982
   579
            Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3;
icculus@1982
   580
icculus@1982
   581
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   582
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   583
                    dst -= 6;
icculus@1982
   584
                    src -= 2;
icculus@1982
   585
                    f2i.ui32 = SDL_SwapBE32(src[0]);
icculus@1982
   586
                    lf = f2i.f;
icculus@1982
   587
                    f2i.ui32 = SDL_SwapBE32(src[1]);
icculus@1982
   588
                    rf = f2i.f;
icculus@1982
   589
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   590
                    dst[0] = src[0];
icculus@1982
   591
                    dst[1] = src[1];
icculus@1982
   592
                    f2i.f = (lf - ce);
icculus@1982
   593
                    dst[2] = SDL_SwapBE32(f2i.ui32);
icculus@1982
   594
                    f2i.f = (rf - ce);
icculus@1982
   595
                    dst[3] = SDL_SwapBE32(f2i.ui32);
icculus@1982
   596
                    f2i.f = ce;
icculus@1982
   597
                    f2i.ui32 = SDL_SwapBE32(f2i.ui32);
icculus@1982
   598
                    dst[4] = f2i.ui32;
icculus@1982
   599
                    dst[5] = f2i.ui32;
icculus@1982
   600
                }
icculus@1982
   601
            } else {
icculus@1982
   602
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   603
                    dst -= 6;
icculus@1982
   604
                    src -= 2;
icculus@1982
   605
                    f2i.ui32 = SDL_SwapLE32(src[0]);
icculus@1982
   606
                    lf = f2i.f;
icculus@1982
   607
                    f2i.ui32 = SDL_SwapLE32(src[1]);
icculus@1982
   608
                    rf = f2i.f;
icculus@1982
   609
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   610
                    dst[0] = src[0];
icculus@1982
   611
                    dst[1] = src[1];
icculus@1982
   612
                    f2i.f = (lf - ce);
icculus@1982
   613
                    dst[2] = SDL_SwapLE32(f2i.ui32);
icculus@1982
   614
                    f2i.f = (rf - ce);
icculus@1982
   615
                    dst[3] = SDL_SwapLE32(f2i.ui32);
icculus@1982
   616
                    f2i.f = ce;
icculus@1982
   617
                    f2i.ui32 = SDL_SwapLE32(f2i.ui32);
icculus@1982
   618
                    dst[4] = f2i.ui32;
icculus@1982
   619
                    dst[5] = f2i.ui32;
icculus@1982
   620
                }
icculus@1982
   621
            }
icculus@1982
   622
        }
icculus@1982
   623
        break;
icculus@1982
   624
slouken@1895
   625
    }
slouken@1895
   626
    cvt->len_cvt *= 3;
slouken@1895
   627
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   628
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   629
    }
slouken@942
   630
}
slouken@942
   631
slouken@942
   632
slouken@942
   633
/* Duplicate a stereo channel to a pseudo-4.0 stream */
icculus@1982
   634
static void SDLCALL
icculus@1982
   635
SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   636
{
slouken@1895
   637
    int i;
slouken@942
   638
slouken@942
   639
#ifdef DEBUG_CONVERT
slouken@1895
   640
    fprintf(stderr, "Converting stereo to quad\n");
slouken@942
   641
#endif
slouken@942
   642
icculus@1982
   643
    switch (format & (SDL_AUDIO_MASK_SIGNED|SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
   644
    case AUDIO_U8:
slouken@1895
   645
        {
slouken@1895
   646
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   647
slouken@1895
   648
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   649
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 2);
slouken@1895
   650
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   651
                dst -= 4;
slouken@1895
   652
                src -= 2;
slouken@1895
   653
                lf = src[0];
slouken@1895
   654
                rf = src[1];
slouken@1895
   655
                ce = (lf / 2) + (rf / 2);
slouken@1895
   656
                dst[0] = lf;
slouken@1895
   657
                dst[1] = rf;
slouken@1895
   658
                dst[2] = lf - ce;
slouken@1895
   659
                dst[3] = rf - ce;
slouken@1895
   660
            }
slouken@1895
   661
        }
slouken@1895
   662
        break;
slouken@942
   663
slouken@1895
   664
    case AUDIO_S8:
slouken@1895
   665
        {
slouken@1895
   666
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   667
slouken@1895
   668
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   669
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 2;
slouken@1895
   670
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   671
                dst -= 4;
slouken@1895
   672
                src -= 2;
slouken@1895
   673
                lf = src[0];
slouken@1895
   674
                rf = src[1];
slouken@1895
   675
                ce = (lf / 2) + (rf / 2);
slouken@1895
   676
                dst[0] = lf;
slouken@1895
   677
                dst[1] = rf;
slouken@1895
   678
                dst[2] = lf - ce;
slouken@1895
   679
                dst[3] = rf - ce;
slouken@1895
   680
            }
slouken@1895
   681
        }
slouken@1895
   682
        break;
slouken@942
   683
slouken@1895
   684
    case AUDIO_U16:
slouken@1895
   685
        {
slouken@1895
   686
            Uint8 *src, *dst;
slouken@1895
   687
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   688
slouken@1895
   689
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   690
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   691
icculus@1982
   692
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   693
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   694
                    dst -= 8;
slouken@1895
   695
                    src -= 4;
slouken@1895
   696
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   697
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   698
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   699
                    rr = lf - ce;
slouken@1895
   700
                    lr = rf - ce;
slouken@1895
   701
                    dst[1] = (lf & 0xFF);
slouken@1895
   702
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   703
                    dst[3] = (rf & 0xFF);
slouken@1895
   704
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   705
slouken@1895
   706
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   707
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   708
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   709
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   710
                }
slouken@1895
   711
            } else {
slouken@1895
   712
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   713
                    dst -= 8;
slouken@1895
   714
                    src -= 4;
slouken@1895
   715
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   716
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   717
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   718
                    rr = lf - ce;
slouken@1895
   719
                    lr = rf - ce;
slouken@1895
   720
                    dst[0] = (lf & 0xFF);
slouken@1895
   721
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   722
                    dst[2] = (rf & 0xFF);
slouken@1895
   723
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   724
slouken@1895
   725
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   726
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   727
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   728
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   729
                }
slouken@1895
   730
            }
slouken@1895
   731
        }
slouken@1895
   732
        break;
slouken@942
   733
slouken@1895
   734
    case AUDIO_S16:
slouken@1895
   735
        {
slouken@1895
   736
            Uint8 *src, *dst;
slouken@1895
   737
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   738
slouken@1895
   739
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   740
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   741
icculus@1982
   742
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   743
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   744
                    dst -= 8;
slouken@1895
   745
                    src -= 4;
slouken@1895
   746
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   747
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   748
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   749
                    rr = lf - ce;
slouken@1895
   750
                    lr = rf - ce;
slouken@1895
   751
                    dst[1] = (lf & 0xFF);
slouken@1895
   752
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   753
                    dst[3] = (rf & 0xFF);
slouken@1895
   754
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   755
slouken@1895
   756
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   757
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   758
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   759
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   760
                }
slouken@1895
   761
            } else {
slouken@1895
   762
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   763
                    dst -= 8;
slouken@1895
   764
                    src -= 4;
slouken@1895
   765
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   766
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   767
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   768
                    rr = lf - ce;
slouken@1895
   769
                    lr = rf - ce;
slouken@1895
   770
                    dst[0] = (lf & 0xFF);
slouken@1895
   771
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   772
                    dst[2] = (rf & 0xFF);
slouken@1895
   773
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   774
slouken@1895
   775
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   776
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   777
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   778
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   779
                }
slouken@1895
   780
            }
slouken@1895
   781
        }
slouken@1895
   782
        break;
slouken@942
   783
icculus@1982
   784
    case AUDIO_S32:
icculus@1982
   785
        {
icculus@1982
   786
            const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
icculus@1982
   787
            Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 2);
icculus@1982
   788
            Sint32 lf, rf, ce;
slouken@942
   789
icculus@1982
   790
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   791
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   792
                    dst -= 4;
icculus@1982
   793
                    src -= 2;
icculus@1982
   794
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   795
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   796
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   797
                    dst[0] = src[0];
icculus@1982
   798
                    dst[1] = src[1];
icculus@1982
   799
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   800
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   801
                }
icculus@1982
   802
            } else {
icculus@1982
   803
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   804
                    dst -= 4;
icculus@1982
   805
                    src -= 2;
icculus@1982
   806
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   807
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   808
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   809
                    dst[0] = src[0];
icculus@1982
   810
                    dst[1] = src[1];
icculus@1982
   811
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   812
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   813
                }
icculus@1982
   814
            }
slouken@1895
   815
        }
slouken@1895
   816
        break;
slouken@1895
   817
    }
slouken@1895
   818
    cvt->len_cvt *= 2;
slouken@1895
   819
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   820
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   821
    }
slouken@0
   822
}
slouken@0
   823
icculus@1982
   824
/* Convert rate up by multiple of 2 */
icculus@1982
   825
static void SDLCALL
icculus@1982
   826
SDL_RateMUL2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
icculus@1982
   827
{
icculus@1982
   828
    int i;
icculus@1982
   829
icculus@1982
   830
#ifdef DEBUG_CONVERT
icculus@1982
   831
    fprintf(stderr, "Converting audio rate * 2 (mono)\n");
icculus@1982
   832
#endif
icculus@1982
   833
icculus@1982
   834
    #define mul2_mono(type) { \
icculus@1982
   835
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   836
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   837
        for (i = cvt->len_cvt / sizeof (type); i; --i) { \
icculus@1982
   838
            src--; \
icculus@1982
   839
            dst[-1] = dst[-2] = src[0]; \
icculus@1982
   840
            dst -= 2; \
icculus@1982
   841
        } \
icculus@1982
   842
    }
icculus@1982
   843
icculus@1982
   844
    switch (SDL_AUDIO_BITSIZE(format)) {
icculus@1982
   845
    case 8:
icculus@1982
   846
        mul2_mono(Uint8);
icculus@1982
   847
        break;
icculus@1982
   848
    case 16:
icculus@1982
   849
        mul2_mono(Uint16);
icculus@1982
   850
        break;
icculus@1982
   851
    case 32:
icculus@1982
   852
        mul2_mono(Uint32);
icculus@1982
   853
        break;
icculus@1982
   854
    }
icculus@1982
   855
icculus@1982
   856
    #undef mul2_mono
icculus@1982
   857
icculus@1982
   858
    cvt->len_cvt *= 2;
icculus@1982
   859
    if (cvt->filters[++cvt->filter_index]) {
icculus@1982
   860
        cvt->filters[cvt->filter_index] (cvt, format);
icculus@1982
   861
    }
icculus@1982
   862
}
icculus@1982
   863
slouken@942
   864
slouken@942
   865
/* Convert rate up by multiple of 2, for stereo */
icculus@1982
   866
static void SDLCALL
icculus@1982
   867
SDL_RateMUL2_c2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   868
{
slouken@1895
   869
    int i;
slouken@942
   870
slouken@942
   871
#ifdef DEBUG_CONVERT
icculus@1982
   872
    fprintf(stderr, "Converting audio rate * 2 (stereo)\n");
slouken@942
   873
#endif
icculus@1982
   874
icculus@1982
   875
    #define mul2_stereo(type) { \
icculus@1982
   876
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   877
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   878
        for (i = cvt->len_cvt / (sizeof (type) * 2); i; --i) { \
icculus@1982
   879
            const type r = src[-1]; \
icculus@1982
   880
            const type l = src[-2]; \
icculus@1982
   881
            src -= 2; \
icculus@1982
   882
            dst[-1] = r; \
icculus@1982
   883
            dst[-2] = l; \
icculus@1982
   884
            dst[-3] = r; \
icculus@1982
   885
            dst[-4] = l; \
icculus@1982
   886
            dst -= 4; \
icculus@1982
   887
        } \
icculus@1982
   888
    }
icculus@1982
   889
icculus@1982
   890
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   891
    case 8:
icculus@1982
   892
        mul2_stereo(Uint8);
slouken@1895
   893
        break;
slouken@1895
   894
    case 16:
icculus@1982
   895
        mul2_stereo(Uint16);
icculus@1982
   896
        break;
icculus@1982
   897
    case 32:
icculus@1982
   898
        mul2_stereo(Uint32);
slouken@1895
   899
        break;
slouken@1895
   900
    }
icculus@1982
   901
icculus@1982
   902
    #undef mul2_stereo
icculus@1982
   903
slouken@1895
   904
    cvt->len_cvt *= 2;
slouken@1895
   905
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   906
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   907
    }
slouken@942
   908
}
slouken@942
   909
slouken@942
   910
/* Convert rate up by multiple of 2, for quad */
icculus@1982
   911
static void SDLCALL
icculus@1982
   912
SDL_RateMUL2_c4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   913
{
slouken@1895
   914
    int i;
slouken@942
   915
slouken@942
   916
#ifdef DEBUG_CONVERT
icculus@1982
   917
    fprintf(stderr, "Converting audio rate * 2 (quad)\n");
slouken@942
   918
#endif
icculus@1982
   919
icculus@1982
   920
    #define mul2_quad(type) { \
icculus@1982
   921
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   922
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   923
        for (i = cvt->len_cvt / (sizeof (type) * 4); i; --i) { \
icculus@1982
   924
            const type c1 = src[-1]; \
icculus@1982
   925
            const type c2 = src[-2]; \
icculus@1982
   926
            const type c3 = src[-3]; \
icculus@1982
   927
            const type c4 = src[-4]; \
icculus@1982
   928
            src -= 4; \
icculus@1982
   929
            dst[-1] = c1; \
icculus@1982
   930
            dst[-2] = c2; \
icculus@1982
   931
            dst[-3] = c3; \
icculus@1982
   932
            dst[-4] = c4; \
icculus@1982
   933
            dst[-5] = c1; \
icculus@1982
   934
            dst[-6] = c2; \
icculus@1982
   935
            dst[-7] = c3; \
icculus@1982
   936
            dst[-8] = c4; \
icculus@1982
   937
            dst -= 8; \
icculus@1982
   938
        } \
icculus@1982
   939
    }
icculus@1982
   940
icculus@1982
   941
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   942
    case 8:
icculus@1982
   943
        mul2_quad(Uint8);
slouken@1895
   944
        break;
slouken@1895
   945
    case 16:
icculus@1982
   946
        mul2_quad(Uint16);
icculus@1982
   947
        break;
icculus@1982
   948
    case 32:
icculus@1982
   949
        mul2_quad(Uint32);
slouken@1895
   950
        break;
slouken@1895
   951
    }
icculus@1982
   952
icculus@1982
   953
    #undef mul2_quad
icculus@1982
   954
slouken@1895
   955
    cvt->len_cvt *= 2;
slouken@1895
   956
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   957
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   958
    }
slouken@942
   959
}
slouken@942
   960
slouken@942
   961
slouken@942
   962
/* Convert rate up by multiple of 2, for 5.1 */
icculus@1982
   963
static void SDLCALL
icculus@1982
   964
SDL_RateMUL2_c6(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   965
{
slouken@1895
   966
    int i;
slouken@942
   967
slouken@942
   968
#ifdef DEBUG_CONVERT
icculus@1982
   969
    fprintf(stderr, "Converting audio rate * 2 (six channels)\n");
slouken@942
   970
#endif
icculus@1982
   971
icculus@1982
   972
    #define mul2_chansix(type) { \
icculus@1982
   973
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   974
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   975
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   976
            const type c1 = src[-1]; \
icculus@1982
   977
            const type c2 = src[-2]; \
icculus@1982
   978
            const type c3 = src[-3]; \
icculus@1982
   979
            const type c4 = src[-4]; \
icculus@1982
   980
            const type c5 = src[-5]; \
icculus@1982
   981
            const type c6 = src[-6]; \
icculus@1982
   982
            src -= 6; \
icculus@1982
   983
            dst[-1] = c1; \
icculus@1982
   984
            dst[-2] = c2; \
icculus@1982
   985
            dst[-3] = c3; \
icculus@1982
   986
            dst[-4] = c4; \
icculus@1982
   987
            dst[-5] = c5; \
icculus@1982
   988
            dst[-6] = c6; \
icculus@1982
   989
            dst[-7] = c1; \
icculus@1982
   990
            dst[-8] = c2; \
icculus@1982
   991
            dst[-9] = c3; \
icculus@1982
   992
            dst[-10] = c4; \
icculus@1982
   993
            dst[-11] = c5; \
icculus@1982
   994
            dst[-12] = c6; \
icculus@1982
   995
            dst -= 12; \
icculus@1982
   996
        } \
icculus@1982
   997
    }
icculus@1982
   998
icculus@1982
   999
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1000
    case 8:
icculus@1982
  1001
        mul2_chansix(Uint8);
slouken@1895
  1002
        break;
slouken@1895
  1003
    case 16:
icculus@1982
  1004
        mul2_chansix(Uint16);
icculus@1982
  1005
        break;
icculus@1982
  1006
    case 32:
icculus@1982
  1007
        mul2_chansix(Uint32);
slouken@1895
  1008
        break;
slouken@1895
  1009
    }
icculus@1982
  1010
icculus@1982
  1011
    #undef mul2_chansix
icculus@1982
  1012
slouken@1895
  1013
    cvt->len_cvt *= 2;
slouken@1895
  1014
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1015
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1016
    }
slouken@942
  1017
}
slouken@942
  1018
slouken@0
  1019
/* Convert rate down by multiple of 2 */
icculus@1982
  1020
static void SDLCALL
icculus@1982
  1021
SDL_RateDIV2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
  1022
{
slouken@1895
  1023
    int i;
slouken@0
  1024
slouken@0
  1025
#ifdef DEBUG_CONVERT
icculus@1982
  1026
    fprintf(stderr, "Converting audio rate / 2 (mono)\n");
slouken@0
  1027
#endif
icculus@1982
  1028
icculus@1982
  1029
    #define div2_mono(type) { \
icculus@1982
  1030
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1031
        type *dst = (type *) cvt->buf; \
icculus@1982
  1032
        for (i = cvt->len_cvt / (sizeof (type) * 2); i; --i) { \
icculus@1982
  1033
            dst[0] = src[0]; \
icculus@1982
  1034
            src += 2; \
icculus@1982
  1035
            dst++; \
icculus@1982
  1036
        } \
icculus@1982
  1037
    }
icculus@1982
  1038
icculus@1982
  1039
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1040
    case 8:
icculus@1982
  1041
        div2_mono(Uint8);
slouken@1895
  1042
        break;
slouken@1895
  1043
    case 16:
icculus@1982
  1044
        div2_mono(Uint16);
icculus@1982
  1045
        break;
icculus@1982
  1046
    case 32:
icculus@1982
  1047
        div2_mono(Uint32);
slouken@1895
  1048
        break;
slouken@1895
  1049
    }
icculus@1982
  1050
icculus@1982
  1051
    #undef div2_mono
icculus@1982
  1052
slouken@1895
  1053
    cvt->len_cvt /= 2;
slouken@1895
  1054
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1055
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1056
    }
slouken@0
  1057
}
slouken@0
  1058
slouken@942
  1059
slouken@942
  1060
/* Convert rate down by multiple of 2, for stereo */
icculus@1982
  1061
static void SDLCALL
icculus@1982
  1062
SDL_RateDIV2_c2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1063
{
slouken@1895
  1064
    int i;
slouken@942
  1065
slouken@942
  1066
#ifdef DEBUG_CONVERT
icculus@1982
  1067
    fprintf(stderr, "Converting audio rate / 2 (stereo)\n");
slouken@942
  1068
#endif
icculus@1982
  1069
icculus@1982
  1070
    #define div2_stereo(type) { \
icculus@1982
  1071
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1072
        type *dst = (type *) cvt->buf; \
icculus@1982
  1073
        for (i = cvt->len_cvt / (sizeof (type) * 4); i; --i) { \
icculus@1982
  1074
            dst[0] = src[0]; \
icculus@1982
  1075
            dst[1] = src[1]; \
icculus@1982
  1076
            src += 4; \
icculus@1982
  1077
            dst += 2; \
icculus@1982
  1078
        } \
icculus@1982
  1079
    }
icculus@1982
  1080
icculus@1982
  1081
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1082
    case 8:
icculus@1982
  1083
        div2_stereo(Uint8);
slouken@1895
  1084
        break;
slouken@1895
  1085
    case 16:
icculus@1982
  1086
        div2_stereo(Uint16);
icculus@1982
  1087
        break;
icculus@1982
  1088
    case 32:
icculus@1982
  1089
        div2_stereo(Uint32);
slouken@1895
  1090
        break;
slouken@1895
  1091
    }
icculus@1982
  1092
icculus@1982
  1093
    #undef div2_stereo
icculus@1982
  1094
slouken@1895
  1095
    cvt->len_cvt /= 2;
slouken@1895
  1096
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1097
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1098
    }
slouken@942
  1099
}
slouken@942
  1100
slouken@942
  1101
slouken@942
  1102
/* Convert rate down by multiple of 2, for quad */
icculus@1982
  1103
static void SDLCALL
icculus@1982
  1104
SDL_RateDIV2_c4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1105
{
slouken@1895
  1106
    int i;
slouken@942
  1107
slouken@942
  1108
#ifdef DEBUG_CONVERT
icculus@1982
  1109
    fprintf(stderr, "Converting audio rate / 2 (quad)\n");
slouken@942
  1110
#endif
icculus@1982
  1111
icculus@1982
  1112
    #define div2_quad(type) { \
icculus@1982
  1113
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1114
        type *dst = (type *) cvt->buf; \
icculus@1982
  1115
        for (i = cvt->len_cvt / (sizeof (type) * 8); i; --i) { \
icculus@1982
  1116
            dst[0] = src[0]; \
icculus@1982
  1117
            dst[1] = src[1]; \
icculus@1982
  1118
            dst[2] = src[2]; \
icculus@1982
  1119
            dst[3] = src[3]; \
icculus@1982
  1120
            src += 8; \
icculus@1982
  1121
            dst += 4; \
icculus@1982
  1122
        } \
icculus@1982
  1123
    }
icculus@1982
  1124
icculus@1982
  1125
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1126
    case 8:
icculus@1982
  1127
        div2_quad(Uint8);
slouken@1895
  1128
        break;
slouken@1895
  1129
    case 16:
icculus@1982
  1130
        div2_quad(Uint16);
icculus@1982
  1131
        break;
icculus@1982
  1132
    case 32:
icculus@1982
  1133
        div2_quad(Uint32);
slouken@1895
  1134
        break;
slouken@1895
  1135
    }
icculus@1982
  1136
icculus@1982
  1137
    #undef div2_quad
icculus@1982
  1138
slouken@1895
  1139
    cvt->len_cvt /= 2;
slouken@1895
  1140
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1141
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1142
    }
slouken@942
  1143
}
slouken@942
  1144
slouken@942
  1145
/* Convert rate down by multiple of 2, for 5.1 */
icculus@1982
  1146
static void SDLCALL
icculus@1982
  1147
SDL_RateDIV2_c6(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1148
{
slouken@1895
  1149
    int i;
slouken@942
  1150
slouken@942
  1151
#ifdef DEBUG_CONVERT
icculus@1982
  1152
    fprintf(stderr, "Converting audio rate / 2 (six channels)\n");
slouken@942
  1153
#endif
icculus@1982
  1154
icculus@1982
  1155
    #define div2_chansix(type) { \
icculus@1982
  1156
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1157
        type *dst = (type *) cvt->buf; \
icculus@1982
  1158
        for (i = cvt->len_cvt / (sizeof (type) * 12); i; --i) { \
icculus@1982
  1159
            dst[0] = src[0]; \
icculus@1982
  1160
            dst[1] = src[1]; \
icculus@1982
  1161
            dst[2] = src[2]; \
icculus@1982
  1162
            dst[3] = src[3]; \
icculus@1982
  1163
            dst[4] = src[4]; \
icculus@1982
  1164
            dst[5] = src[5]; \
icculus@1982
  1165
            src += 12; \
icculus@1982
  1166
            dst += 6; \
icculus@1982
  1167
        } \
icculus@1982
  1168
    }
icculus@1982
  1169
icculus@1982
  1170
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1171
    case 8:
icculus@1982
  1172
        div2_chansix(Uint8);
slouken@1895
  1173
        break;
slouken@1895
  1174
    case 16:
icculus@1982
  1175
        div2_chansix(Uint16);
icculus@1982
  1176
        break;
icculus@1982
  1177
    case 32:
icculus@1982
  1178
        div2_chansix(Uint32);
slouken@1895
  1179
        break;
slouken@1895
  1180
    }
icculus@1982
  1181
icculus@1982
  1182
    #undef div_chansix
icculus@1982
  1183
slouken@1895
  1184
    cvt->len_cvt /= 2;
slouken@1895
  1185
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1186
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1187
    }
slouken@942
  1188
}
slouken@942
  1189
slouken@0
  1190
/* Very slow rate conversion routine */
icculus@1982
  1191
static void SDLCALL
icculus@1982
  1192
SDL_RateSLOW(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
  1193
{
slouken@1895
  1194
    double ipos;
slouken@1895
  1195
    int i, clen;
slouken@0
  1196
slouken@0
  1197
#ifdef DEBUG_CONVERT
slouken@1895
  1198
    fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0 / cvt->rate_incr);
slouken@0
  1199
#endif
slouken@1895
  1200
    clen = (int) ((double) cvt->len_cvt / cvt->rate_incr);
slouken@1895
  1201
    if (cvt->rate_incr > 1.0) {
icculus@1982
  1202
        switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1203
        case 8:
slouken@1895
  1204
            {
slouken@1895
  1205
                Uint8 *output;
slouken@0
  1206
slouken@1895
  1207
                output = cvt->buf;
slouken@1895
  1208
                ipos = 0.0;
slouken@1895
  1209
                for (i = clen; i; --i) {
slouken@1895
  1210
                    *output = cvt->buf[(int) ipos];
slouken@1895
  1211
                    ipos += cvt->rate_incr;
slouken@1895
  1212
                    output += 1;
slouken@1895
  1213
                }
slouken@1895
  1214
            }
slouken@1895
  1215
            break;
slouken@0
  1216
slouken@1895
  1217
        case 16:
slouken@1895
  1218
            {
slouken@1895
  1219
                Uint16 *output;
slouken@0
  1220
slouken@1895
  1221
                clen &= ~1;
slouken@1895
  1222
                output = (Uint16 *) cvt->buf;
slouken@1895
  1223
                ipos = 0.0;
slouken@1895
  1224
                for (i = clen / 2; i; --i) {
slouken@1895
  1225
                    *output = ((Uint16 *) cvt->buf)[(int) ipos];
slouken@1895
  1226
                    ipos += cvt->rate_incr;
slouken@1895
  1227
                    output += 1;
slouken@1895
  1228
                }
slouken@1895
  1229
            }
slouken@1895
  1230
            break;
icculus@1982
  1231
icculus@1982
  1232
        case 32:
icculus@1982
  1233
            {
icculus@1982
  1234
                /* !!! FIXME: need 32-bit converter here! */
icculus@1982
  1235
                fprintf(stderr, "FIXME: need 32-bit converter here!\n");
icculus@1982
  1236
            }
slouken@1895
  1237
        }
slouken@1895
  1238
    } else {
icculus@1982
  1239
        switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1240
        case 8:
slouken@1895
  1241
            {
slouken@1895
  1242
                Uint8 *output;
slouken@0
  1243
slouken@1895
  1244
                output = cvt->buf + clen;
slouken@1895
  1245
                ipos = (double) cvt->len_cvt;
slouken@1895
  1246
                for (i = clen; i; --i) {
slouken@1895
  1247
                    ipos -= cvt->rate_incr;
slouken@1895
  1248
                    output -= 1;
slouken@1895
  1249
                    *output = cvt->buf[(int) ipos];
slouken@1895
  1250
                }
slouken@1895
  1251
            }
slouken@1895
  1252
            break;
slouken@0
  1253
slouken@1895
  1254
        case 16:
slouken@1895
  1255
            {
slouken@1895
  1256
                Uint16 *output;
slouken@0
  1257
slouken@1895
  1258
                clen &= ~1;
slouken@1895
  1259
                output = (Uint16 *) (cvt->buf + clen);
slouken@1895
  1260
                ipos = (double) cvt->len_cvt / 2;
slouken@1895
  1261
                for (i = clen / 2; i; --i) {
slouken@1895
  1262
                    ipos -= cvt->rate_incr;
slouken@1895
  1263
                    output -= 1;
slouken@1895
  1264
                    *output = ((Uint16 *) cvt->buf)[(int) ipos];
slouken@1895
  1265
                }
slouken@1895
  1266
            }
slouken@1895
  1267
            break;
icculus@1982
  1268
icculus@1982
  1269
        case 32:
icculus@1982
  1270
            {
icculus@1982
  1271
                /* !!! FIXME: need 32-bit converter here! */
icculus@1982
  1272
                fprintf(stderr, "FIXME: need 32-bit converter here!\n");
icculus@1982
  1273
            }
slouken@1895
  1274
        }
slouken@1895
  1275
    }
icculus@1982
  1276
slouken@1895
  1277
    cvt->len_cvt = clen;
slouken@1895
  1278
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1279
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1280
    }
slouken@0
  1281
}
slouken@0
  1282
slouken@1895
  1283
int
slouken@1895
  1284
SDL_ConvertAudio(SDL_AudioCVT * cvt)
slouken@0
  1285
{
slouken@1895
  1286
    /* Make sure there's data to convert */
slouken@1895
  1287
    if (cvt->buf == NULL) {
slouken@1895
  1288
        SDL_SetError("No buffer allocated for conversion");
slouken@1895
  1289
        return (-1);
slouken@1895
  1290
    }
slouken@1895
  1291
    /* Return okay if no conversion is necessary */
slouken@1895
  1292
    cvt->len_cvt = cvt->len;
slouken@1895
  1293
    if (cvt->filters[0] == NULL) {
slouken@1895
  1294
        return (0);
slouken@1895
  1295
    }
slouken@0
  1296
slouken@1895
  1297
    /* Set up the conversion and go! */
slouken@1895
  1298
    cvt->filter_index = 0;
slouken@1895
  1299
    cvt->filters[0] (cvt, cvt->src_format);
slouken@1895
  1300
    return (0);
slouken@0
  1301
}
slouken@0
  1302
icculus@1982
  1303
icculus@1982
  1304
static SDL_AudioFilter
icculus@1982
  1305
SDL_HandTunedTypeCVT(SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
  1306
{
icculus@1982
  1307
    /*
icculus@1982
  1308
     * Fill in any future conversions that are specialized to a
icculus@1982
  1309
     *  processor, platform, compiler, or library here.
icculus@1982
  1310
     */
icculus@1982
  1311
icculus@1982
  1312
    return NULL;  /* no specialized converter code available. */
icculus@1982
  1313
}
icculus@1982
  1314
icculus@1982
  1315
icculus@1982
  1316
/*
icculus@1982
  1317
 * Find a converter between two data types. We try to select a hand-tuned
icculus@1982
  1318
 *  asm/vectorized/optimized function first, and then fallback to an
icculus@1982
  1319
 *  autogenerated function that is customized to convert between two
icculus@1982
  1320
 *  specific data types.
icculus@1982
  1321
 */
icculus@1982
  1322
static int
icculus@1982
  1323
SDL_BuildAudioTypeCVT(SDL_AudioCVT * cvt,
icculus@1982
  1324
                      SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
  1325
{
icculus@1982
  1326
    if (src_fmt != dst_fmt) {
icculus@1982
  1327
        const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
icculus@1982
  1328
        const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
icculus@1982
  1329
        SDL_AudioFilter filter = SDL_HandTunedTypeCVT(src_fmt, dst_fmt);
icculus@1982
  1330
icculus@1982
  1331
        /* No hand-tuned converter? Try the autogenerated ones. */
icculus@1982
  1332
        if (filter == NULL) {
icculus@1982
  1333
            int i;
icculus@1982
  1334
            for (i = 0; sdl_audio_type_filters[i].filter != NULL; i++) {
icculus@1982
  1335
                const SDL_AudioTypeFilters *filt = &sdl_audio_type_filters[i];
icculus@1982
  1336
                if ((filt->src_fmt == src_fmt) && (filt->dst_fmt == dst_fmt)) {
icculus@1982
  1337
                    filter = filt->filter;
icculus@1982
  1338
                    break;
icculus@1982
  1339
                }
icculus@1982
  1340
            }
icculus@1982
  1341
icculus@1982
  1342
            if (filter == NULL) {
icculus@1982
  1343
                return -1;  /* Still no matching converter?! */
icculus@1982
  1344
            }
icculus@1982
  1345
        }
icculus@1982
  1346
icculus@1982
  1347
        /* Update (cvt) with filter details... */
icculus@1982
  1348
        cvt->filters[cvt->filter_index++] = filter;
icculus@1982
  1349
        if (src_bitsize < dst_bitsize) {
icculus@1982
  1350
            const int mult = (dst_bitsize / src_bitsize);
icculus@1982
  1351
            cvt->len_mult *= mult;
icculus@1982
  1352
            cvt->len_ratio *= mult;
icculus@1982
  1353
        } else if (src_bitsize > dst_bitsize) {
icculus@1982
  1354
            cvt->len_ratio /= (src_bitsize / dst_bitsize);
icculus@1982
  1355
        }
icculus@1982
  1356
icculus@1982
  1357
        return 1;  /* added a converter. */
icculus@1982
  1358
    }
icculus@1982
  1359
icculus@1982
  1360
    return 0;  /* no conversion necessary. */
icculus@1982
  1361
}
icculus@1982
  1362
icculus@1982
  1363
icculus@1982
  1364
icculus@1982
  1365
/* Creates a set of audio filters to convert from one format to another.
icculus@1982
  1366
   Returns -1 if the format conversion is not supported, 0 if there's
icculus@1982
  1367
   no conversion needed, or 1 if the audio filter is set up.
slouken@0
  1368
*/
slouken@1895
  1369
slouken@1895
  1370
int
slouken@1895
  1371
SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
icculus@1982
  1372
                  SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
icculus@1982
  1373
                  SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
slouken@0
  1374
{
icculus@1982
  1375
    /* there are no unsigned types over 16 bits, so catch this upfront. */
icculus@1982
  1376
    if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
icculus@1982
  1377
        return -1;
icculus@1982
  1378
    }
icculus@1982
  1379
    if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
icculus@1982
  1380
        return -1;
icculus@1982
  1381
    }
icculus@1982
  1382
icculus@1982
  1383
    #ifdef DEBUG_CONVERT
icculus@1982
  1384
    printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
icculus@1982
  1385
		    src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
icculus@1982
  1386
    #endif
icculus@1982
  1387
slouken@1895
  1388
    /* Start off with no conversion necessary */
icculus@1982
  1389
icculus@1982
  1390
    cvt->src_format = src_fmt;
icculus@1982
  1391
    cvt->dst_format = dst_fmt;
slouken@1895
  1392
    cvt->needed = 0;
slouken@1895
  1393
    cvt->filter_index = 0;
slouken@1895
  1394
    cvt->filters[0] = NULL;
slouken@1895
  1395
    cvt->len_mult = 1;
slouken@1895
  1396
    cvt->len_ratio = 1.0;
slouken@0
  1397
icculus@1982
  1398
    /* Convert data types, if necessary. Updates (cvt). */
icculus@1982
  1399
    if (SDL_BuildAudioTypeCVT(cvt, src_fmt, dst_fmt) == -1)
icculus@1982
  1400
        return -1;  /* shouldn't happen, but just in case... */
slouken@0
  1401
icculus@1982
  1402
    /* Channel conversion */
slouken@1895
  1403
    if (src_channels != dst_channels) {
slouken@1895
  1404
        if ((src_channels == 1) && (dst_channels > 1)) {
slouken@1895
  1405
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1406
            cvt->len_mult *= 2;
slouken@1895
  1407
            src_channels = 2;
slouken@1895
  1408
            cvt->len_ratio *= 2;
slouken@1895
  1409
        }
slouken@1895
  1410
        if ((src_channels == 2) && (dst_channels == 6)) {
slouken@1895
  1411
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
slouken@1895
  1412
            src_channels = 6;
slouken@1895
  1413
            cvt->len_mult *= 3;
slouken@1895
  1414
            cvt->len_ratio *= 3;
slouken@1895
  1415
        }
slouken@1895
  1416
        if ((src_channels == 2) && (dst_channels == 4)) {
slouken@1895
  1417
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
slouken@1895
  1418
            src_channels = 4;
slouken@1895
  1419
            cvt->len_mult *= 2;
slouken@1895
  1420
            cvt->len_ratio *= 2;
slouken@1895
  1421
        }
slouken@1895
  1422
        while ((src_channels * 2) <= dst_channels) {
slouken@1895
  1423
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1424
            cvt->len_mult *= 2;
slouken@1895
  1425
            src_channels *= 2;
slouken@1895
  1426
            cvt->len_ratio *= 2;
slouken@1895
  1427
        }
slouken@1895
  1428
        if ((src_channels == 6) && (dst_channels <= 2)) {
slouken@1895
  1429
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
slouken@1895
  1430
            src_channels = 2;
slouken@1895
  1431
            cvt->len_ratio /= 3;
slouken@1895
  1432
        }
slouken@1895
  1433
        if ((src_channels == 6) && (dst_channels == 4)) {
slouken@1895
  1434
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
slouken@1895
  1435
            src_channels = 4;
slouken@1895
  1436
            cvt->len_ratio /= 2;
slouken@1895
  1437
        }
slouken@1895
  1438
        /* This assumes that 4 channel audio is in the format:
slouken@1895
  1439
           Left {front/back} + Right {front/back}
slouken@1895
  1440
           so converting to L/R stereo works properly.
slouken@1895
  1441
         */
slouken@1895
  1442
        while (((src_channels % 2) == 0) &&
slouken@1895
  1443
               ((src_channels / 2) >= dst_channels)) {
slouken@1895
  1444
            cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
slouken@1895
  1445
            src_channels /= 2;
slouken@1895
  1446
            cvt->len_ratio /= 2;
slouken@1895
  1447
        }
slouken@1895
  1448
        if (src_channels != dst_channels) {
slouken@1895
  1449
            /* Uh oh.. */ ;
slouken@1895
  1450
        }
slouken@1895
  1451
    }
slouken@0
  1452
slouken@1895
  1453
    /* Do rate conversion */
slouken@1895
  1454
    cvt->rate_incr = 0.0;
slouken@1895
  1455
    if ((src_rate / 100) != (dst_rate / 100)) {
slouken@1895
  1456
        Uint32 hi_rate, lo_rate;
slouken@1895
  1457
        int len_mult;
slouken@1895
  1458
        double len_ratio;
icculus@1982
  1459
        SDL_AudioFilter rate_cvt = NULL;
slouken@1895
  1460
slouken@1895
  1461
        if (src_rate > dst_rate) {
slouken@1895
  1462
            hi_rate = src_rate;
slouken@1895
  1463
            lo_rate = dst_rate;
slouken@1895
  1464
            switch (src_channels) {
slouken@1895
  1465
            case 1:
slouken@1895
  1466
                rate_cvt = SDL_RateDIV2;
slouken@1895
  1467
                break;
slouken@1895
  1468
            case 2:
slouken@1895
  1469
                rate_cvt = SDL_RateDIV2_c2;
slouken@1895
  1470
                break;
slouken@1895
  1471
            case 4:
slouken@1895
  1472
                rate_cvt = SDL_RateDIV2_c4;
slouken@1895
  1473
                break;
slouken@1895
  1474
            case 6:
slouken@1895
  1475
                rate_cvt = SDL_RateDIV2_c6;
slouken@1895
  1476
                break;
slouken@1895
  1477
            default:
slouken@1895
  1478
                return -1;
slouken@1895
  1479
            }
slouken@1895
  1480
            len_mult = 1;
slouken@1895
  1481
            len_ratio = 0.5;
slouken@1895
  1482
        } else {
slouken@1895
  1483
            hi_rate = dst_rate;
slouken@1895
  1484
            lo_rate = src_rate;
slouken@1895
  1485
            switch (src_channels) {
slouken@1895
  1486
            case 1:
slouken@1895
  1487
                rate_cvt = SDL_RateMUL2;
slouken@1895
  1488
                break;
slouken@1895
  1489
            case 2:
slouken@1895
  1490
                rate_cvt = SDL_RateMUL2_c2;
slouken@1895
  1491
                break;
slouken@1895
  1492
            case 4:
slouken@1895
  1493
                rate_cvt = SDL_RateMUL2_c4;
slouken@1895
  1494
                break;
slouken@1895
  1495
            case 6:
slouken@1895
  1496
                rate_cvt = SDL_RateMUL2_c6;
slouken@1895
  1497
                break;
slouken@1895
  1498
            default:
slouken@1895
  1499
                return -1;
slouken@1895
  1500
            }
slouken@1895
  1501
            len_mult = 2;
slouken@1895
  1502
            len_ratio = 2.0;
slouken@1895
  1503
        }
slouken@1895
  1504
        /* If hi_rate = lo_rate*2^x then conversion is easy */
slouken@1895
  1505
        while (((lo_rate * 2) / 100) <= (hi_rate / 100)) {
slouken@1895
  1506
            cvt->filters[cvt->filter_index++] = rate_cvt;
slouken@1895
  1507
            cvt->len_mult *= len_mult;
slouken@1895
  1508
            lo_rate *= 2;
slouken@1895
  1509
            cvt->len_ratio *= len_ratio;
slouken@1895
  1510
        }
slouken@1895
  1511
        /* We may need a slow conversion here to finish up */
slouken@1895
  1512
        if ((lo_rate / 100) != (hi_rate / 100)) {
slouken@0
  1513
#if 1
slouken@1895
  1514
            /* The problem with this is that if the input buffer is
slouken@1895
  1515
               say 1K, and the conversion rate is say 1.1, then the
slouken@1895
  1516
               output buffer is 1.1K, which may not be an acceptable
slouken@1895
  1517
               buffer size for the audio driver (not a power of 2)
slouken@1895
  1518
             */
slouken@1895
  1519
            /* For now, punt and hope the rate distortion isn't great.
slouken@1895
  1520
             */
slouken@0
  1521
#else
slouken@1895
  1522
            if (src_rate < dst_rate) {
slouken@1895
  1523
                cvt->rate_incr = (double) lo_rate / hi_rate;
slouken@1895
  1524
                cvt->len_mult *= 2;
slouken@1895
  1525
                cvt->len_ratio /= cvt->rate_incr;
slouken@1895
  1526
            } else {
slouken@1895
  1527
                cvt->rate_incr = (double) hi_rate / lo_rate;
slouken@1895
  1528
                cvt->len_ratio *= cvt->rate_incr;
slouken@1895
  1529
            }
slouken@1895
  1530
            cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
slouken@0
  1531
#endif
slouken@1895
  1532
        }
slouken@1895
  1533
    }
slouken@0
  1534
slouken@1895
  1535
    /* Set up the filter information */
slouken@1895
  1536
    if (cvt->filter_index != 0) {
slouken@1895
  1537
        cvt->needed = 1;
icculus@1982
  1538
        cvt->src_format = src_fmt;
icculus@1982
  1539
        cvt->dst_format = dst_fmt;
slouken@1895
  1540
        cvt->len = 0;
slouken@1895
  1541
        cvt->buf = NULL;
slouken@1895
  1542
        cvt->filters[cvt->filter_index] = NULL;
slouken@1895
  1543
    }
slouken@1895
  1544
    return (cvt->needed);
slouken@0
  1545
}
slouken@1895
  1546
slouken@1895
  1547
/* vi: set ts=4 sw=4 expandtab: */