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