src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 29 Nov 2006 10:38:07 +0000
changeset 2078 f932ac47a331
parent 2049 5f6550e5184f
child 2130 3ee59c43d784
permissions -rw-r--r--
Apparently it's possible that MSVC will want to call a built-in function to
bitshift an Sint64, but it can't find this function since we don't use the
C runtime on Windows.

Division doesn't have this problem, though. Strange.

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