src/audio/SDL_audiocvt.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 24 Sep 2006 15:56:36 +0000
changeset 2042 3908e1f808e1
parent 2014 7abe37467fa5
child 2049 5f6550e5184f
permissions -rw-r--r--
Fixed bug #292

I might be on crack here.

It looks like SDL_ConvertMono() in src/audio/SDL_audiocvt.c adds the left and
right channels of a stereo stream together, and clamps the new mono channel if
it would overflow.

Shouldn't it be dividing by 2 to average the two sample points instead of
clamping? Otherwise the mono sample point's volume doubles in the conversion.
This would also make the conversion faster, as it replaces two branches per
sample frame with a bitwise shift.

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