src/audio/SDL_audiocvt.c
author Aaron Wishnick <schnarf@gmail.com>
Wed, 18 Jun 2008 18:55:50 +0000
branchgsoc2008_audio_resampling
changeset 2656 dd74182b3c3c
parent 2655 b8e736c8a5a8
child 2657 29306e52dab8
permissions -rw-r--r--
Began implementing IIR and FIR filters, and got zero stuffing and sample discarding working.
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"
schnarf@2655
    23
#include <math.h>
slouken@0
    24
slouken@0
    25
/* Functions for audio drivers to perform runtime conversion of audio format */
slouken@0
    26
slouken@0
    27
#include "SDL_audio.h"
icculus@1982
    28
#include "SDL_audio_c.h"
slouken@0
    29
schnarf@2656
    30
#define DEBUG_CONVERT
schnarf@2656
    31
slouken@0
    32
/* Effectively mix right and left channels into a single channel */
icculus@1982
    33
static void SDLCALL
icculus@1982
    34
SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
    35
{
slouken@1895
    36
    int i;
slouken@1895
    37
    Sint32 sample;
slouken@0
    38
slouken@0
    39
#ifdef DEBUG_CONVERT
slouken@1895
    40
    fprintf(stderr, "Converting to mono\n");
slouken@0
    41
#endif
slouken@1985
    42
    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
    43
    case AUDIO_U8:
slouken@1895
    44
        {
slouken@1895
    45
            Uint8 *src, *dst;
slouken@0
    46
slouken@1895
    47
            src = cvt->buf;
slouken@1895
    48
            dst = cvt->buf;
slouken@1895
    49
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    50
                sample = src[0] + src[1];
slouken@2042
    51
                *dst = (Uint8) (sample / 2);
slouken@1895
    52
                src += 2;
slouken@1895
    53
                dst += 1;
slouken@1895
    54
            }
slouken@1895
    55
        }
slouken@1895
    56
        break;
slouken@0
    57
slouken@1895
    58
    case AUDIO_S8:
slouken@1895
    59
        {
slouken@1895
    60
            Sint8 *src, *dst;
slouken@0
    61
slouken@1895
    62
            src = (Sint8 *) cvt->buf;
slouken@1895
    63
            dst = (Sint8 *) cvt->buf;
slouken@1895
    64
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    65
                sample = src[0] + src[1];
slouken@2042
    66
                *dst = (Sint8) (sample / 2);
slouken@1895
    67
                src += 2;
slouken@1895
    68
                dst += 1;
slouken@1895
    69
            }
slouken@1895
    70
        }
slouken@1895
    71
        break;
slouken@0
    72
slouken@1895
    73
    case AUDIO_U16:
slouken@1895
    74
        {
slouken@1895
    75
            Uint8 *src, *dst;
slouken@0
    76
slouken@1895
    77
            src = cvt->buf;
slouken@1895
    78
            dst = cvt->buf;
icculus@1982
    79
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
    80
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
    81
                    sample = (Uint16) ((src[0] << 8) | src[1]) +
slouken@1895
    82
                        (Uint16) ((src[2] << 8) | src[3]);
slouken@2042
    83
                    sample /= 2;
slouken@2042
    84
                    dst[1] = (sample & 0xFF);
slouken@2042
    85
                    sample >>= 8;
slouken@2042
    86
                    dst[0] = (sample & 0xFF);
slouken@1895
    87
                    src += 4;
slouken@1895
    88
                    dst += 2;
slouken@1895
    89
                }
slouken@1895
    90
            } else {
slouken@1895
    91
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
    92
                    sample = (Uint16) ((src[1] << 8) | src[0]) +
slouken@1895
    93
                        (Uint16) ((src[3] << 8) | src[2]);
slouken@2042
    94
                    sample /= 2;
slouken@2042
    95
                    dst[0] = (sample & 0xFF);
slouken@2042
    96
                    sample >>= 8;
slouken@2042
    97
                    dst[1] = (sample & 0xFF);
slouken@1895
    98
                    src += 4;
slouken@1895
    99
                    dst += 2;
slouken@1895
   100
                }
slouken@1895
   101
            }
slouken@1895
   102
        }
slouken@1895
   103
        break;
slouken@0
   104
slouken@1895
   105
    case AUDIO_S16:
slouken@1895
   106
        {
slouken@1895
   107
            Uint8 *src, *dst;
slouken@0
   108
slouken@1895
   109
            src = cvt->buf;
slouken@1895
   110
            dst = cvt->buf;
icculus@1982
   111
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   112
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   113
                    sample = (Sint16) ((src[0] << 8) | src[1]) +
slouken@1895
   114
                        (Sint16) ((src[2] << 8) | src[3]);
slouken@2042
   115
                    sample /= 2;
slouken@2042
   116
                    dst[1] = (sample & 0xFF);
slouken@2042
   117
                    sample >>= 8;
slouken@2042
   118
                    dst[0] = (sample & 0xFF);
slouken@1895
   119
                    src += 4;
slouken@1895
   120
                    dst += 2;
slouken@1895
   121
                }
slouken@1895
   122
            } else {
slouken@1895
   123
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   124
                    sample = (Sint16) ((src[1] << 8) | src[0]) +
slouken@1895
   125
                        (Sint16) ((src[3] << 8) | src[2]);
slouken@2042
   126
                    sample /= 2;
slouken@2042
   127
                    dst[0] = (sample & 0xFF);
slouken@2042
   128
                    sample >>= 8;
slouken@2042
   129
                    dst[1] = (sample & 0xFF);
slouken@1895
   130
                    src += 4;
slouken@1895
   131
                    dst += 2;
slouken@1895
   132
                }
slouken@1895
   133
            }
slouken@1895
   134
        }
slouken@1895
   135
        break;
icculus@1982
   136
icculus@1982
   137
    case AUDIO_S32:
icculus@1982
   138
        {
icculus@1982
   139
            const Uint32 *src = (const Uint32 *) cvt->buf;
icculus@1982
   140
            Uint32 *dst = (Uint32 *) cvt->buf;
icculus@1982
   141
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   142
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   143
                    const Sint64 added =
slouken@1985
   144
                        (((Sint64) (Sint32) SDL_SwapBE32(src[0])) +
slouken@1985
   145
                         ((Sint64) (Sint32) SDL_SwapBE32(src[1])));
icculus@2078
   146
                    *(dst++) = SDL_SwapBE32((Uint32) ((Sint32) (added / 2)));
icculus@1982
   147
                }
icculus@1982
   148
            } else {
icculus@1982
   149
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   150
                    const Sint64 added =
slouken@1985
   151
                        (((Sint64) (Sint32) SDL_SwapLE32(src[0])) +
slouken@1985
   152
                         ((Sint64) (Sint32) SDL_SwapLE32(src[1])));
icculus@2078
   153
                    *(dst++) = SDL_SwapLE32((Uint32) ((Sint32) (added / 2)));
icculus@1982
   154
                }
icculus@1982
   155
            }
icculus@1982
   156
        }
icculus@1982
   157
        break;
icculus@1982
   158
icculus@1982
   159
    case AUDIO_F32:
icculus@1982
   160
        {
icculus@2014
   161
            const float *src = (const float *) cvt->buf;
icculus@2014
   162
            float *dst = (float *) cvt->buf;
icculus@1982
   163
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   164
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@2049
   165
                    const float src1 = SDL_SwapFloatBE(src[0]);
icculus@2049
   166
                    const float src2 = SDL_SwapFloatBE(src[1]);
icculus@1982
   167
                    const double added = ((double) src1) + ((double) src2);
icculus@2049
   168
                    const float halved = (float) (added * 0.5);
icculus@2049
   169
                    *(dst++) = SDL_SwapFloatBE(halved);
icculus@1982
   170
                }
icculus@1982
   171
            } else {
icculus@1982
   172
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@2049
   173
                    const float src1 = SDL_SwapFloatLE(src[0]);
icculus@2049
   174
                    const float src2 = SDL_SwapFloatLE(src[1]);
icculus@1982
   175
                    const double added = ((double) src1) + ((double) src2);
icculus@2049
   176
                    const float halved = (float) (added * 0.5);
icculus@2049
   177
                    *(dst++) = SDL_SwapFloatLE(halved);
icculus@1982
   178
                }
icculus@1982
   179
            }
icculus@1982
   180
        }
icculus@1982
   181
        break;
slouken@1895
   182
    }
icculus@1982
   183
slouken@1895
   184
    cvt->len_cvt /= 2;
slouken@1895
   185
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   186
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   187
    }
slouken@0
   188
}
slouken@0
   189
icculus@1982
   190
slouken@942
   191
/* Discard top 4 channels */
icculus@1982
   192
static void SDLCALL
icculus@1982
   193
SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   194
{
slouken@1895
   195
    int i;
slouken@942
   196
slouken@942
   197
#ifdef DEBUG_CONVERT
icculus@1982
   198
    fprintf(stderr, "Converting down from 6 channels to stereo\n");
slouken@942
   199
#endif
slouken@942
   200
slouken@1985
   201
#define strip_chans_6_to_2(type) \
icculus@1982
   202
    { \
icculus@1982
   203
        const type *src = (const type *) cvt->buf; \
icculus@1982
   204
        type *dst = (type *) cvt->buf; \
icculus@1982
   205
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   206
            dst[0] = src[0]; \
icculus@1982
   207
            dst[1] = src[1]; \
icculus@1982
   208
            src += 6; \
icculus@1982
   209
            dst += 2; \
icculus@1982
   210
        } \
icculus@1982
   211
    }
slouken@942
   212
icculus@1982
   213
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   214
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   215
    case 8:
slouken@1985
   216
        strip_chans_6_to_2(Uint8);
slouken@1985
   217
        break;
slouken@1985
   218
    case 16:
slouken@1985
   219
        strip_chans_6_to_2(Uint16);
slouken@1985
   220
        break;
slouken@1985
   221
    case 32:
slouken@1985
   222
        strip_chans_6_to_2(Uint32);
slouken@1985
   223
        break;
icculus@1982
   224
    }
slouken@942
   225
slouken@1985
   226
#undef strip_chans_6_to_2
slouken@942
   227
slouken@1895
   228
    cvt->len_cvt /= 3;
slouken@1895
   229
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   230
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   231
    }
slouken@942
   232
}
slouken@942
   233
slouken@942
   234
slouken@942
   235
/* Discard top 2 channels of 6 */
icculus@1982
   236
static void SDLCALL
icculus@1982
   237
SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   238
{
slouken@1895
   239
    int i;
slouken@942
   240
slouken@942
   241
#ifdef DEBUG_CONVERT
slouken@1895
   242
    fprintf(stderr, "Converting 6 down to quad\n");
slouken@942
   243
#endif
slouken@942
   244
slouken@1985
   245
#define strip_chans_6_to_4(type) \
icculus@1982
   246
    { \
icculus@1982
   247
        const type *src = (const type *) cvt->buf; \
icculus@1982
   248
        type *dst = (type *) cvt->buf; \
icculus@1982
   249
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   250
            dst[0] = src[0]; \
icculus@1982
   251
            dst[1] = src[1]; \
icculus@1982
   252
            dst[2] = src[2]; \
icculus@1982
   253
            dst[3] = src[3]; \
icculus@1982
   254
            src += 6; \
icculus@1982
   255
            dst += 4; \
icculus@1982
   256
        } \
icculus@1982
   257
    }
slouken@942
   258
icculus@1982
   259
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   260
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   261
    case 8:
slouken@1985
   262
        strip_chans_6_to_4(Uint8);
slouken@1985
   263
        break;
slouken@1985
   264
    case 16:
slouken@1985
   265
        strip_chans_6_to_4(Uint16);
slouken@1985
   266
        break;
slouken@1985
   267
    case 32:
slouken@1985
   268
        strip_chans_6_to_4(Uint32);
slouken@1985
   269
        break;
icculus@1982
   270
    }
slouken@942
   271
slouken@1985
   272
#undef strip_chans_6_to_4
slouken@942
   273
icculus@1982
   274
    cvt->len_cvt /= 6;
icculus@1982
   275
    cvt->len_cvt *= 4;
slouken@1895
   276
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   277
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   278
    }
slouken@942
   279
}
slouken@0
   280
slouken@0
   281
/* Duplicate a mono channel to both stereo channels */
icculus@1982
   282
static void SDLCALL
icculus@1982
   283
SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
   284
{
slouken@1895
   285
    int i;
slouken@0
   286
slouken@0
   287
#ifdef DEBUG_CONVERT
slouken@1895
   288
    fprintf(stderr, "Converting to stereo\n");
slouken@0
   289
#endif
slouken@0
   290
slouken@1985
   291
#define dup_chans_1_to_2(type) \
icculus@1982
   292
    { \
icculus@1982
   293
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   294
        type *dst = (type *) (cvt->buf + cvt->len_cvt * 2); \
icculus@1982
   295
        for (i = cvt->len_cvt / 2; i; --i, --src) { \
icculus@1982
   296
            const type val = *src; \
icculus@1982
   297
            dst -= 2; \
icculus@1982
   298
            dst[0] = dst[1] = val; \
icculus@1982
   299
        } \
icculus@1982
   300
    }
slouken@0
   301
icculus@1982
   302
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   303
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   304
    case 8:
slouken@1985
   305
        dup_chans_1_to_2(Uint8);
slouken@1985
   306
        break;
slouken@1985
   307
    case 16:
slouken@1985
   308
        dup_chans_1_to_2(Uint16);
slouken@1985
   309
        break;
slouken@1985
   310
    case 32:
slouken@1985
   311
        dup_chans_1_to_2(Uint32);
slouken@1985
   312
        break;
slouken@1895
   313
    }
icculus@1982
   314
slouken@1985
   315
#undef dup_chans_1_to_2
icculus@1982
   316
slouken@1895
   317
    cvt->len_cvt *= 2;
slouken@1895
   318
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   319
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   320
    }
slouken@0
   321
}
slouken@0
   322
slouken@942
   323
slouken@942
   324
/* Duplicate a stereo channel to a pseudo-5.1 stream */
icculus@1982
   325
static void SDLCALL
icculus@1982
   326
SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   327
{
slouken@1895
   328
    int i;
slouken@942
   329
slouken@942
   330
#ifdef DEBUG_CONVERT
slouken@1895
   331
    fprintf(stderr, "Converting stereo to surround\n");
slouken@942
   332
#endif
slouken@942
   333
slouken@1985
   334
    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
   335
    case AUDIO_U8:
slouken@1895
   336
        {
slouken@1895
   337
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   338
slouken@1895
   339
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   340
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 3);
slouken@1895
   341
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   342
                dst -= 6;
slouken@1895
   343
                src -= 2;
slouken@1895
   344
                lf = src[0];
slouken@1895
   345
                rf = src[1];
slouken@1895
   346
                ce = (lf / 2) + (rf / 2);
slouken@1895
   347
                dst[0] = lf;
slouken@1895
   348
                dst[1] = rf;
slouken@1895
   349
                dst[2] = lf - ce;
slouken@1895
   350
                dst[3] = rf - ce;
slouken@1895
   351
                dst[4] = ce;
slouken@1895
   352
                dst[5] = ce;
slouken@1895
   353
            }
slouken@1895
   354
        }
slouken@1895
   355
        break;
slouken@942
   356
slouken@1895
   357
    case AUDIO_S8:
slouken@1895
   358
        {
slouken@1895
   359
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   360
slouken@1895
   361
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   362
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 3;
slouken@1895
   363
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   364
                dst -= 6;
slouken@1895
   365
                src -= 2;
slouken@1895
   366
                lf = src[0];
slouken@1895
   367
                rf = src[1];
slouken@1895
   368
                ce = (lf / 2) + (rf / 2);
slouken@1895
   369
                dst[0] = lf;
slouken@1895
   370
                dst[1] = rf;
slouken@1895
   371
                dst[2] = lf - ce;
slouken@1895
   372
                dst[3] = rf - ce;
slouken@1895
   373
                dst[4] = ce;
slouken@1895
   374
                dst[5] = ce;
slouken@1895
   375
            }
slouken@1895
   376
        }
slouken@1895
   377
        break;
slouken@942
   378
slouken@1895
   379
    case AUDIO_U16:
slouken@1895
   380
        {
slouken@1895
   381
            Uint8 *src, *dst;
slouken@1895
   382
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   383
slouken@1895
   384
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   385
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   386
icculus@1982
   387
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   388
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   389
                    dst -= 12;
slouken@1895
   390
                    src -= 4;
slouken@1895
   391
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   392
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   393
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   394
                    rr = lf - ce;
slouken@1895
   395
                    lr = rf - ce;
slouken@1895
   396
                    dst[1] = (lf & 0xFF);
slouken@1895
   397
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   398
                    dst[3] = (rf & 0xFF);
slouken@1895
   399
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   400
slouken@1895
   401
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   402
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   403
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   404
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   405
slouken@1895
   406
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   407
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   408
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   409
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   410
                }
slouken@1895
   411
            } else {
slouken@1895
   412
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   413
                    dst -= 12;
slouken@1895
   414
                    src -= 4;
slouken@1895
   415
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   416
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   417
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   418
                    rr = lf - ce;
slouken@1895
   419
                    lr = rf - ce;
slouken@1895
   420
                    dst[0] = (lf & 0xFF);
slouken@1895
   421
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   422
                    dst[2] = (rf & 0xFF);
slouken@1895
   423
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   424
slouken@1895
   425
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   426
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   427
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   428
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   429
slouken@1895
   430
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   431
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   432
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   433
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   434
                }
slouken@1895
   435
            }
slouken@1895
   436
        }
slouken@1895
   437
        break;
slouken@942
   438
slouken@1895
   439
    case AUDIO_S16:
slouken@1895
   440
        {
slouken@1895
   441
            Uint8 *src, *dst;
slouken@1895
   442
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   443
slouken@1895
   444
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   445
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   446
icculus@1982
   447
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   448
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   449
                    dst -= 12;
slouken@1895
   450
                    src -= 4;
slouken@1895
   451
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   452
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   453
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   454
                    rr = lf - ce;
slouken@1895
   455
                    lr = rf - ce;
slouken@1895
   456
                    dst[1] = (lf & 0xFF);
slouken@1895
   457
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   458
                    dst[3] = (rf & 0xFF);
slouken@1895
   459
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   460
slouken@1895
   461
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   462
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   463
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   464
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   465
slouken@1895
   466
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   467
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   468
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   469
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   470
                }
slouken@1895
   471
            } else {
slouken@1895
   472
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   473
                    dst -= 12;
slouken@1895
   474
                    src -= 4;
slouken@1895
   475
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   476
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   477
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   478
                    rr = lf - ce;
slouken@1895
   479
                    lr = rf - ce;
slouken@1895
   480
                    dst[0] = (lf & 0xFF);
slouken@1895
   481
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   482
                    dst[2] = (rf & 0xFF);
slouken@1895
   483
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   484
slouken@1895
   485
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   486
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   487
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   488
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   489
slouken@1895
   490
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   491
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   492
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   493
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   494
                }
slouken@1895
   495
            }
slouken@1895
   496
        }
slouken@1895
   497
        break;
icculus@1982
   498
icculus@1982
   499
    case AUDIO_S32:
icculus@1982
   500
        {
icculus@1982
   501
            Sint32 lf, rf, ce;
icculus@1982
   502
            const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt;
icculus@1982
   503
            Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3;
icculus@1982
   504
icculus@1982
   505
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   506
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   507
                    dst -= 6;
icculus@1982
   508
                    src -= 2;
icculus@1982
   509
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   510
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   511
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   512
                    dst[0] = SDL_SwapBE32((Uint32) lf);
icculus@1982
   513
                    dst[1] = SDL_SwapBE32((Uint32) rf);
icculus@1982
   514
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   515
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   516
                    dst[4] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   517
                    dst[5] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   518
                }
icculus@1982
   519
            } else {
icculus@1982
   520
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   521
                    dst -= 6;
icculus@1982
   522
                    src -= 2;
icculus@1982
   523
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   524
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   525
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   526
                    dst[0] = src[0];
icculus@1982
   527
                    dst[1] = src[1];
icculus@1982
   528
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   529
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   530
                    dst[4] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   531
                    dst[5] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   532
                }
icculus@1982
   533
            }
icculus@1982
   534
        }
icculus@1982
   535
        break;
icculus@1982
   536
icculus@1982
   537
    case AUDIO_F32:
icculus@1982
   538
        {
icculus@1982
   539
            float lf, rf, ce;
icculus@2014
   540
            const float *src = (const float *) cvt->buf + cvt->len_cvt;
icculus@2014
   541
            float *dst = (float *) cvt->buf + cvt->len_cvt * 3;
icculus@1982
   542
icculus@1982
   543
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   544
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   545
                    dst -= 6;
icculus@1982
   546
                    src -= 2;
icculus@2014
   547
                    lf = SDL_SwapFloatBE(src[0]);
icculus@2014
   548
                    rf = SDL_SwapFloatBE(src[1]);
icculus@1982
   549
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   550
                    dst[0] = src[0];
icculus@1982
   551
                    dst[1] = src[1];
icculus@2014
   552
                    dst[2] = SDL_SwapFloatBE(lf - ce);
icculus@2014
   553
                    dst[3] = SDL_SwapFloatBE(rf - ce);
icculus@2014
   554
                    dst[4] = dst[5] = SDL_SwapFloatBE(ce);
icculus@1982
   555
                }
icculus@1982
   556
            } else {
icculus@1982
   557
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   558
                    dst -= 6;
icculus@1982
   559
                    src -= 2;
icculus@2014
   560
                    lf = SDL_SwapFloatLE(src[0]);
icculus@2014
   561
                    rf = SDL_SwapFloatLE(src[1]);
icculus@1982
   562
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   563
                    dst[0] = src[0];
icculus@1982
   564
                    dst[1] = src[1];
icculus@2014
   565
                    dst[2] = SDL_SwapFloatLE(lf - ce);
icculus@2014
   566
                    dst[3] = SDL_SwapFloatLE(rf - ce);
icculus@2014
   567
                    dst[4] = dst[5] = SDL_SwapFloatLE(ce);
icculus@1982
   568
                }
icculus@1982
   569
            }
icculus@1982
   570
        }
icculus@1982
   571
        break;
icculus@1982
   572
slouken@1895
   573
    }
slouken@1895
   574
    cvt->len_cvt *= 3;
slouken@1895
   575
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   576
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   577
    }
slouken@942
   578
}
slouken@942
   579
slouken@942
   580
slouken@942
   581
/* Duplicate a stereo channel to a pseudo-4.0 stream */
icculus@1982
   582
static void SDLCALL
icculus@1982
   583
SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   584
{
slouken@1895
   585
    int i;
slouken@942
   586
slouken@942
   587
#ifdef DEBUG_CONVERT
slouken@1895
   588
    fprintf(stderr, "Converting stereo to quad\n");
slouken@942
   589
#endif
slouken@942
   590
slouken@1985
   591
    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
slouken@1895
   592
    case AUDIO_U8:
slouken@1895
   593
        {
slouken@1895
   594
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   595
slouken@1895
   596
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   597
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 2);
slouken@1895
   598
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   599
                dst -= 4;
slouken@1895
   600
                src -= 2;
slouken@1895
   601
                lf = src[0];
slouken@1895
   602
                rf = src[1];
slouken@1895
   603
                ce = (lf / 2) + (rf / 2);
slouken@1895
   604
                dst[0] = lf;
slouken@1895
   605
                dst[1] = rf;
slouken@1895
   606
                dst[2] = lf - ce;
slouken@1895
   607
                dst[3] = rf - ce;
slouken@1895
   608
            }
slouken@1895
   609
        }
slouken@1895
   610
        break;
slouken@942
   611
slouken@1895
   612
    case AUDIO_S8:
slouken@1895
   613
        {
slouken@1895
   614
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   615
slouken@1895
   616
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   617
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 2;
slouken@1895
   618
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   619
                dst -= 4;
slouken@1895
   620
                src -= 2;
slouken@1895
   621
                lf = src[0];
slouken@1895
   622
                rf = src[1];
slouken@1895
   623
                ce = (lf / 2) + (rf / 2);
slouken@1895
   624
                dst[0] = lf;
slouken@1895
   625
                dst[1] = rf;
slouken@1895
   626
                dst[2] = lf - ce;
slouken@1895
   627
                dst[3] = rf - ce;
slouken@1895
   628
            }
slouken@1895
   629
        }
slouken@1895
   630
        break;
slouken@942
   631
slouken@1895
   632
    case AUDIO_U16:
slouken@1895
   633
        {
slouken@1895
   634
            Uint8 *src, *dst;
slouken@1895
   635
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   636
slouken@1895
   637
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   638
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   639
icculus@1982
   640
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   641
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   642
                    dst -= 8;
slouken@1895
   643
                    src -= 4;
slouken@1895
   644
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   645
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   646
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   647
                    rr = lf - ce;
slouken@1895
   648
                    lr = rf - ce;
slouken@1895
   649
                    dst[1] = (lf & 0xFF);
slouken@1895
   650
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   651
                    dst[3] = (rf & 0xFF);
slouken@1895
   652
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   653
slouken@1895
   654
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   655
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   656
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   657
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   658
                }
slouken@1895
   659
            } else {
slouken@1895
   660
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   661
                    dst -= 8;
slouken@1895
   662
                    src -= 4;
slouken@1895
   663
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   664
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   665
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   666
                    rr = lf - ce;
slouken@1895
   667
                    lr = rf - ce;
slouken@1895
   668
                    dst[0] = (lf & 0xFF);
slouken@1895
   669
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   670
                    dst[2] = (rf & 0xFF);
slouken@1895
   671
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   672
slouken@1895
   673
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   674
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   675
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   676
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   677
                }
slouken@1895
   678
            }
slouken@1895
   679
        }
slouken@1895
   680
        break;
slouken@942
   681
slouken@1895
   682
    case AUDIO_S16:
slouken@1895
   683
        {
slouken@1895
   684
            Uint8 *src, *dst;
slouken@1895
   685
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   686
slouken@1895
   687
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   688
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   689
icculus@1982
   690
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   691
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   692
                    dst -= 8;
slouken@1895
   693
                    src -= 4;
slouken@1895
   694
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   695
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   696
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   697
                    rr = lf - ce;
slouken@1895
   698
                    lr = rf - ce;
slouken@1895
   699
                    dst[1] = (lf & 0xFF);
slouken@1895
   700
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   701
                    dst[3] = (rf & 0xFF);
slouken@1895
   702
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   703
slouken@1895
   704
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   705
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   706
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   707
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   708
                }
slouken@1895
   709
            } else {
slouken@1895
   710
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   711
                    dst -= 8;
slouken@1895
   712
                    src -= 4;
slouken@1895
   713
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   714
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   715
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   716
                    rr = lf - ce;
slouken@1895
   717
                    lr = rf - ce;
slouken@1895
   718
                    dst[0] = (lf & 0xFF);
slouken@1895
   719
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   720
                    dst[2] = (rf & 0xFF);
slouken@1895
   721
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   722
slouken@1895
   723
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   724
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   725
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   726
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   727
                }
slouken@1895
   728
            }
slouken@1895
   729
        }
slouken@1895
   730
        break;
slouken@942
   731
icculus@1982
   732
    case AUDIO_S32:
icculus@1982
   733
        {
icculus@1982
   734
            const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
icculus@1982
   735
            Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 2);
icculus@1982
   736
            Sint32 lf, rf, ce;
slouken@942
   737
icculus@1982
   738
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   739
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   740
                    dst -= 4;
icculus@1982
   741
                    src -= 2;
icculus@1982
   742
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   743
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   744
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   745
                    dst[0] = src[0];
icculus@1982
   746
                    dst[1] = src[1];
icculus@1982
   747
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   748
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   749
                }
icculus@1982
   750
            } else {
icculus@1982
   751
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   752
                    dst -= 4;
icculus@1982
   753
                    src -= 2;
icculus@1982
   754
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   755
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   756
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   757
                    dst[0] = src[0];
icculus@1982
   758
                    dst[1] = src[1];
icculus@1982
   759
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   760
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   761
                }
icculus@1982
   762
            }
slouken@1895
   763
        }
slouken@1895
   764
        break;
slouken@1895
   765
    }
slouken@1895
   766
    cvt->len_cvt *= 2;
slouken@1895
   767
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   768
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   769
    }
slouken@0
   770
}
slouken@0
   771
icculus@1982
   772
/* Convert rate up by multiple of 2 */
icculus@1982
   773
static void SDLCALL
icculus@1982
   774
SDL_RateMUL2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
icculus@1982
   775
{
icculus@1982
   776
    int i;
icculus@1982
   777
icculus@1982
   778
#ifdef DEBUG_CONVERT
icculus@1982
   779
    fprintf(stderr, "Converting audio rate * 2 (mono)\n");
icculus@1982
   780
#endif
icculus@1982
   781
slouken@1985
   782
#define mul2_mono(type) { \
icculus@1982
   783
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   784
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   785
        for (i = cvt->len_cvt / sizeof (type); i; --i) { \
icculus@1982
   786
            src--; \
icculus@1982
   787
            dst[-1] = dst[-2] = src[0]; \
icculus@1982
   788
            dst -= 2; \
icculus@1982
   789
        } \
icculus@1982
   790
    }
icculus@1982
   791
icculus@1982
   792
    switch (SDL_AUDIO_BITSIZE(format)) {
icculus@1982
   793
    case 8:
icculus@1982
   794
        mul2_mono(Uint8);
icculus@1982
   795
        break;
icculus@1982
   796
    case 16:
icculus@1982
   797
        mul2_mono(Uint16);
icculus@1982
   798
        break;
icculus@1982
   799
    case 32:
icculus@1982
   800
        mul2_mono(Uint32);
icculus@1982
   801
        break;
icculus@1982
   802
    }
icculus@1982
   803
slouken@1985
   804
#undef mul2_mono
icculus@1982
   805
icculus@1982
   806
    cvt->len_cvt *= 2;
icculus@1982
   807
    if (cvt->filters[++cvt->filter_index]) {
icculus@1982
   808
        cvt->filters[cvt->filter_index] (cvt, format);
icculus@1982
   809
    }
icculus@1982
   810
}
icculus@1982
   811
slouken@942
   812
slouken@942
   813
/* Convert rate up by multiple of 2, for stereo */
icculus@1982
   814
static void SDLCALL
icculus@1982
   815
SDL_RateMUL2_c2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   816
{
slouken@1895
   817
    int i;
slouken@942
   818
slouken@942
   819
#ifdef DEBUG_CONVERT
icculus@1982
   820
    fprintf(stderr, "Converting audio rate * 2 (stereo)\n");
slouken@942
   821
#endif
icculus@1982
   822
slouken@1985
   823
#define mul2_stereo(type) { \
icculus@1982
   824
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   825
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   826
        for (i = cvt->len_cvt / (sizeof (type) * 2); i; --i) { \
icculus@1982
   827
            const type r = src[-1]; \
icculus@1982
   828
            const type l = src[-2]; \
icculus@1982
   829
            src -= 2; \
icculus@1982
   830
            dst[-1] = r; \
icculus@1982
   831
            dst[-2] = l; \
icculus@1982
   832
            dst[-3] = r; \
icculus@1982
   833
            dst[-4] = l; \
icculus@1982
   834
            dst -= 4; \
icculus@1982
   835
        } \
icculus@1982
   836
    }
icculus@1982
   837
icculus@1982
   838
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   839
    case 8:
icculus@1982
   840
        mul2_stereo(Uint8);
slouken@1895
   841
        break;
slouken@1895
   842
    case 16:
icculus@1982
   843
        mul2_stereo(Uint16);
icculus@1982
   844
        break;
icculus@1982
   845
    case 32:
icculus@1982
   846
        mul2_stereo(Uint32);
slouken@1895
   847
        break;
slouken@1895
   848
    }
icculus@1982
   849
slouken@1985
   850
#undef mul2_stereo
icculus@1982
   851
slouken@1895
   852
    cvt->len_cvt *= 2;
slouken@1895
   853
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   854
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   855
    }
slouken@942
   856
}
slouken@942
   857
slouken@942
   858
/* Convert rate up by multiple of 2, for quad */
icculus@1982
   859
static void SDLCALL
icculus@1982
   860
SDL_RateMUL2_c4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   861
{
slouken@1895
   862
    int i;
slouken@942
   863
slouken@942
   864
#ifdef DEBUG_CONVERT
icculus@1982
   865
    fprintf(stderr, "Converting audio rate * 2 (quad)\n");
slouken@942
   866
#endif
icculus@1982
   867
slouken@1985
   868
#define mul2_quad(type) { \
icculus@1982
   869
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   870
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   871
        for (i = cvt->len_cvt / (sizeof (type) * 4); i; --i) { \
icculus@1982
   872
            const type c1 = src[-1]; \
icculus@1982
   873
            const type c2 = src[-2]; \
icculus@1982
   874
            const type c3 = src[-3]; \
icculus@1982
   875
            const type c4 = src[-4]; \
icculus@1982
   876
            src -= 4; \
icculus@1982
   877
            dst[-1] = c1; \
icculus@1982
   878
            dst[-2] = c2; \
icculus@1982
   879
            dst[-3] = c3; \
icculus@1982
   880
            dst[-4] = c4; \
icculus@1982
   881
            dst[-5] = c1; \
icculus@1982
   882
            dst[-6] = c2; \
icculus@1982
   883
            dst[-7] = c3; \
icculus@1982
   884
            dst[-8] = c4; \
icculus@1982
   885
            dst -= 8; \
icculus@1982
   886
        } \
icculus@1982
   887
    }
icculus@1982
   888
icculus@1982
   889
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   890
    case 8:
icculus@1982
   891
        mul2_quad(Uint8);
slouken@1895
   892
        break;
slouken@1895
   893
    case 16:
icculus@1982
   894
        mul2_quad(Uint16);
icculus@1982
   895
        break;
icculus@1982
   896
    case 32:
icculus@1982
   897
        mul2_quad(Uint32);
slouken@1895
   898
        break;
slouken@1895
   899
    }
icculus@1982
   900
slouken@1985
   901
#undef mul2_quad
icculus@1982
   902
slouken@1895
   903
    cvt->len_cvt *= 2;
slouken@1895
   904
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   905
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   906
    }
slouken@942
   907
}
slouken@942
   908
slouken@942
   909
slouken@942
   910
/* Convert rate up by multiple of 2, for 5.1 */
icculus@1982
   911
static void SDLCALL
icculus@1982
   912
SDL_RateMUL2_c6(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   913
{
slouken@1895
   914
    int i;
slouken@942
   915
slouken@942
   916
#ifdef DEBUG_CONVERT
icculus@1982
   917
    fprintf(stderr, "Converting audio rate * 2 (six channels)\n");
slouken@942
   918
#endif
icculus@1982
   919
slouken@1985
   920
#define mul2_chansix(type) { \
icculus@1982
   921
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   922
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * 2)); \
icculus@1982
   923
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   924
            const type c1 = src[-1]; \
icculus@1982
   925
            const type c2 = src[-2]; \
icculus@1982
   926
            const type c3 = src[-3]; \
icculus@1982
   927
            const type c4 = src[-4]; \
icculus@1982
   928
            const type c5 = src[-5]; \
icculus@1982
   929
            const type c6 = src[-6]; \
icculus@1982
   930
            src -= 6; \
icculus@1982
   931
            dst[-1] = c1; \
icculus@1982
   932
            dst[-2] = c2; \
icculus@1982
   933
            dst[-3] = c3; \
icculus@1982
   934
            dst[-4] = c4; \
icculus@1982
   935
            dst[-5] = c5; \
icculus@1982
   936
            dst[-6] = c6; \
icculus@1982
   937
            dst[-7] = c1; \
icculus@1982
   938
            dst[-8] = c2; \
icculus@1982
   939
            dst[-9] = c3; \
icculus@1982
   940
            dst[-10] = c4; \
icculus@1982
   941
            dst[-11] = c5; \
icculus@1982
   942
            dst[-12] = c6; \
icculus@1982
   943
            dst -= 12; \
icculus@1982
   944
        } \
icculus@1982
   945
    }
icculus@1982
   946
icculus@1982
   947
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   948
    case 8:
icculus@1982
   949
        mul2_chansix(Uint8);
slouken@1895
   950
        break;
slouken@1895
   951
    case 16:
icculus@1982
   952
        mul2_chansix(Uint16);
icculus@1982
   953
        break;
icculus@1982
   954
    case 32:
icculus@1982
   955
        mul2_chansix(Uint32);
slouken@1895
   956
        break;
slouken@1895
   957
    }
icculus@1982
   958
slouken@1985
   959
#undef mul2_chansix
icculus@1982
   960
slouken@1895
   961
    cvt->len_cvt *= 2;
slouken@1895
   962
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   963
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   964
    }
slouken@942
   965
}
slouken@942
   966
slouken@0
   967
/* Convert rate down by multiple of 2 */
icculus@1982
   968
static void SDLCALL
icculus@1982
   969
SDL_RateDIV2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
   970
{
slouken@1895
   971
    int i;
slouken@0
   972
slouken@0
   973
#ifdef DEBUG_CONVERT
icculus@1982
   974
    fprintf(stderr, "Converting audio rate / 2 (mono)\n");
slouken@0
   975
#endif
icculus@1982
   976
slouken@1985
   977
#define div2_mono(type) { \
icculus@1982
   978
        const type *src = (const type *) cvt->buf; \
icculus@1982
   979
        type *dst = (type *) cvt->buf; \
icculus@1982
   980
        for (i = cvt->len_cvt / (sizeof (type) * 2); i; --i) { \
icculus@1982
   981
            dst[0] = src[0]; \
icculus@1982
   982
            src += 2; \
icculus@1982
   983
            dst++; \
icculus@1982
   984
        } \
icculus@1982
   985
    }
icculus@1982
   986
icculus@1982
   987
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
   988
    case 8:
icculus@1982
   989
        div2_mono(Uint8);
slouken@1895
   990
        break;
slouken@1895
   991
    case 16:
icculus@1982
   992
        div2_mono(Uint16);
icculus@1982
   993
        break;
icculus@1982
   994
    case 32:
icculus@1982
   995
        div2_mono(Uint32);
slouken@1895
   996
        break;
slouken@1895
   997
    }
icculus@1982
   998
slouken@1985
   999
#undef div2_mono
icculus@1982
  1000
slouken@1895
  1001
    cvt->len_cvt /= 2;
slouken@1895
  1002
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1003
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1004
    }
slouken@0
  1005
}
slouken@0
  1006
slouken@942
  1007
slouken@942
  1008
/* Convert rate down by multiple of 2, for stereo */
icculus@1982
  1009
static void SDLCALL
icculus@1982
  1010
SDL_RateDIV2_c2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1011
{
slouken@1895
  1012
    int i;
slouken@942
  1013
slouken@942
  1014
#ifdef DEBUG_CONVERT
icculus@1982
  1015
    fprintf(stderr, "Converting audio rate / 2 (stereo)\n");
slouken@942
  1016
#endif
icculus@1982
  1017
slouken@1985
  1018
#define div2_stereo(type) { \
icculus@1982
  1019
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1020
        type *dst = (type *) cvt->buf; \
icculus@1982
  1021
        for (i = cvt->len_cvt / (sizeof (type) * 4); i; --i) { \
icculus@1982
  1022
            dst[0] = src[0]; \
icculus@1982
  1023
            dst[1] = src[1]; \
icculus@1982
  1024
            src += 4; \
icculus@1982
  1025
            dst += 2; \
icculus@1982
  1026
        } \
icculus@1982
  1027
    }
icculus@1982
  1028
icculus@1982
  1029
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1030
    case 8:
icculus@1982
  1031
        div2_stereo(Uint8);
slouken@1895
  1032
        break;
slouken@1895
  1033
    case 16:
icculus@1982
  1034
        div2_stereo(Uint16);
icculus@1982
  1035
        break;
icculus@1982
  1036
    case 32:
icculus@1982
  1037
        div2_stereo(Uint32);
slouken@1895
  1038
        break;
slouken@1895
  1039
    }
icculus@1982
  1040
slouken@1985
  1041
#undef div2_stereo
icculus@1982
  1042
slouken@1895
  1043
    cvt->len_cvt /= 2;
slouken@1895
  1044
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1045
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1046
    }
slouken@942
  1047
}
slouken@942
  1048
slouken@942
  1049
slouken@942
  1050
/* Convert rate down by multiple of 2, for quad */
icculus@1982
  1051
static void SDLCALL
icculus@1982
  1052
SDL_RateDIV2_c4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1053
{
slouken@1895
  1054
    int i;
slouken@942
  1055
slouken@942
  1056
#ifdef DEBUG_CONVERT
icculus@1982
  1057
    fprintf(stderr, "Converting audio rate / 2 (quad)\n");
slouken@942
  1058
#endif
icculus@1982
  1059
slouken@1985
  1060
#define div2_quad(type) { \
icculus@1982
  1061
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1062
        type *dst = (type *) cvt->buf; \
icculus@1982
  1063
        for (i = cvt->len_cvt / (sizeof (type) * 8); i; --i) { \
icculus@1982
  1064
            dst[0] = src[0]; \
icculus@1982
  1065
            dst[1] = src[1]; \
icculus@1982
  1066
            dst[2] = src[2]; \
icculus@1982
  1067
            dst[3] = src[3]; \
icculus@1982
  1068
            src += 8; \
icculus@1982
  1069
            dst += 4; \
icculus@1982
  1070
        } \
icculus@1982
  1071
    }
icculus@1982
  1072
icculus@1982
  1073
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1074
    case 8:
icculus@1982
  1075
        div2_quad(Uint8);
slouken@1895
  1076
        break;
slouken@1895
  1077
    case 16:
icculus@1982
  1078
        div2_quad(Uint16);
icculus@1982
  1079
        break;
icculus@1982
  1080
    case 32:
icculus@1982
  1081
        div2_quad(Uint32);
slouken@1895
  1082
        break;
slouken@1895
  1083
    }
icculus@1982
  1084
slouken@1985
  1085
#undef div2_quad
icculus@1982
  1086
slouken@1895
  1087
    cvt->len_cvt /= 2;
slouken@1895
  1088
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1089
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1090
    }
slouken@942
  1091
}
slouken@942
  1092
slouken@942
  1093
/* Convert rate down by multiple of 2, for 5.1 */
icculus@1982
  1094
static void SDLCALL
icculus@1982
  1095
SDL_RateDIV2_c6(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
  1096
{
slouken@1895
  1097
    int i;
slouken@942
  1098
slouken@942
  1099
#ifdef DEBUG_CONVERT
icculus@1982
  1100
    fprintf(stderr, "Converting audio rate / 2 (six channels)\n");
slouken@942
  1101
#endif
icculus@1982
  1102
slouken@1985
  1103
#define div2_chansix(type) { \
icculus@1982
  1104
        const type *src = (const type *) cvt->buf; \
icculus@1982
  1105
        type *dst = (type *) cvt->buf; \
icculus@1982
  1106
        for (i = cvt->len_cvt / (sizeof (type) * 12); i; --i) { \
icculus@1982
  1107
            dst[0] = src[0]; \
icculus@1982
  1108
            dst[1] = src[1]; \
icculus@1982
  1109
            dst[2] = src[2]; \
icculus@1982
  1110
            dst[3] = src[3]; \
icculus@1982
  1111
            dst[4] = src[4]; \
icculus@1982
  1112
            dst[5] = src[5]; \
icculus@1982
  1113
            src += 12; \
icculus@1982
  1114
            dst += 6; \
icculus@1982
  1115
        } \
icculus@1982
  1116
    }
icculus@1982
  1117
icculus@1982
  1118
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1119
    case 8:
icculus@1982
  1120
        div2_chansix(Uint8);
slouken@1895
  1121
        break;
slouken@1895
  1122
    case 16:
icculus@1982
  1123
        div2_chansix(Uint16);
icculus@1982
  1124
        break;
icculus@1982
  1125
    case 32:
icculus@1982
  1126
        div2_chansix(Uint32);
slouken@1895
  1127
        break;
slouken@1895
  1128
    }
icculus@1982
  1129
slouken@1985
  1130
#undef div_chansix
icculus@1982
  1131
slouken@1895
  1132
    cvt->len_cvt /= 2;
slouken@1895
  1133
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1134
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1135
    }
slouken@942
  1136
}
slouken@942
  1137
slouken@0
  1138
/* Very slow rate conversion routine */
icculus@1982
  1139
static void SDLCALL
icculus@1982
  1140
SDL_RateSLOW(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
  1141
{
slouken@1895
  1142
    double ipos;
slouken@1895
  1143
    int i, clen;
slouken@0
  1144
slouken@0
  1145
#ifdef DEBUG_CONVERT
slouken@1895
  1146
    fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0 / cvt->rate_incr);
slouken@0
  1147
#endif
slouken@1895
  1148
    clen = (int) ((double) cvt->len_cvt / cvt->rate_incr);
slouken@1895
  1149
    if (cvt->rate_incr > 1.0) {
icculus@1982
  1150
        switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1151
        case 8:
slouken@1895
  1152
            {
slouken@1895
  1153
                Uint8 *output;
slouken@0
  1154
slouken@1895
  1155
                output = cvt->buf;
slouken@1895
  1156
                ipos = 0.0;
slouken@1895
  1157
                for (i = clen; i; --i) {
slouken@1895
  1158
                    *output = cvt->buf[(int) ipos];
slouken@1895
  1159
                    ipos += cvt->rate_incr;
slouken@1895
  1160
                    output += 1;
slouken@1895
  1161
                }
slouken@1895
  1162
            }
slouken@1895
  1163
            break;
slouken@0
  1164
slouken@1895
  1165
        case 16:
slouken@1895
  1166
            {
slouken@1895
  1167
                Uint16 *output;
slouken@0
  1168
slouken@1895
  1169
                clen &= ~1;
slouken@1895
  1170
                output = (Uint16 *) cvt->buf;
slouken@1895
  1171
                ipos = 0.0;
slouken@1895
  1172
                for (i = clen / 2; i; --i) {
slouken@1895
  1173
                    *output = ((Uint16 *) cvt->buf)[(int) ipos];
slouken@1895
  1174
                    ipos += cvt->rate_incr;
slouken@1895
  1175
                    output += 1;
slouken@1895
  1176
                }
slouken@1895
  1177
            }
slouken@1895
  1178
            break;
icculus@1982
  1179
icculus@1982
  1180
        case 32:
icculus@1982
  1181
            {
icculus@1982
  1182
                /* !!! FIXME: need 32-bit converter here! */
slouken@2130
  1183
#ifdef DEBUG_CONVERT
icculus@1982
  1184
                fprintf(stderr, "FIXME: need 32-bit converter here!\n");
slouken@2130
  1185
#endif
icculus@1982
  1186
            }
slouken@1895
  1187
        }
slouken@1895
  1188
    } else {
icculus@1982
  1189
        switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1895
  1190
        case 8:
slouken@1895
  1191
            {
slouken@1895
  1192
                Uint8 *output;
slouken@0
  1193
slouken@1895
  1194
                output = cvt->buf + clen;
slouken@1895
  1195
                ipos = (double) cvt->len_cvt;
slouken@1895
  1196
                for (i = clen; i; --i) {
slouken@1895
  1197
                    ipos -= cvt->rate_incr;
slouken@1895
  1198
                    output -= 1;
slouken@1895
  1199
                    *output = cvt->buf[(int) ipos];
slouken@1895
  1200
                }
slouken@1895
  1201
            }
slouken@1895
  1202
            break;
slouken@0
  1203
slouken@1895
  1204
        case 16:
slouken@1895
  1205
            {
slouken@1895
  1206
                Uint16 *output;
slouken@0
  1207
slouken@1895
  1208
                clen &= ~1;
slouken@1895
  1209
                output = (Uint16 *) (cvt->buf + clen);
slouken@1895
  1210
                ipos = (double) cvt->len_cvt / 2;
slouken@1895
  1211
                for (i = clen / 2; i; --i) {
slouken@1895
  1212
                    ipos -= cvt->rate_incr;
slouken@1895
  1213
                    output -= 1;
slouken@1895
  1214
                    *output = ((Uint16 *) cvt->buf)[(int) ipos];
slouken@1895
  1215
                }
slouken@1895
  1216
            }
slouken@1895
  1217
            break;
icculus@1982
  1218
icculus@1982
  1219
        case 32:
icculus@1982
  1220
            {
icculus@1982
  1221
                /* !!! FIXME: need 32-bit converter here! */
slouken@2130
  1222
#ifdef DEBUG_CONVERT
icculus@1982
  1223
                fprintf(stderr, "FIXME: need 32-bit converter here!\n");
slouken@2130
  1224
#endif
icculus@1982
  1225
            }
slouken@1895
  1226
        }
slouken@1895
  1227
    }
icculus@1982
  1228
slouken@1895
  1229
    cvt->len_cvt = clen;
slouken@1895
  1230
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
  1231
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
  1232
    }
slouken@0
  1233
}
slouken@0
  1234
schnarf@2655
  1235
/* Perform proper resampling */
schnarf@2655
  1236
static void SDLCALL
schnarf@2655
  1237
SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format)
schnarf@2655
  1238
{
schnarf@2655
  1239
    int i, j;
schnarf@2655
  1240
schnarf@2655
  1241
#ifdef DEBUG_CONVERT
schnarf@2656
  1242
    printf("Converting audio rate via proper resampling (mono)\n");
schnarf@2655
  1243
#endif
schnarf@2655
  1244
schnarf@2655
  1245
#define zerostuff_mono(type) { \
schnarf@2655
  1246
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
schnarf@2655
  1247
        type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \
schnarf@2655
  1248
        for (i = cvt->len_cvt / sizeof (type); i; --i) { \
schnarf@2655
  1249
            src--; \
schnarf@2655
  1250
            dst[-1] = src[0]; \
schnarf@2655
  1251
			for( j = -cvt->len_mult; j < -1; ++j ) { \
schnarf@2655
  1252
				dst[j] = 0; \
schnarf@2655
  1253
			} \
schnarf@2655
  1254
            dst -= cvt->len_mult; \
schnarf@2655
  1255
        } \
schnarf@2655
  1256
    }
schnarf@2655
  1257
	
schnarf@2655
  1258
#define discard_mono(type) { \
schnarf@2655
  1259
        const type *src = (const type *) (cvt->buf); \
schnarf@2655
  1260
        type *dst = (type *) (cvt->buf); \
schnarf@2656
  1261
        for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
schnarf@2655
  1262
            dst[0] = src[0]; \
schnarf@2655
  1263
            src += cvt->len_div; \
schnarf@2655
  1264
            ++dst; \
schnarf@2655
  1265
        } \
schnarf@2655
  1266
    }
schnarf@2655
  1267
schnarf@2655
  1268
	// Step 1: Zero stuff the conversion buffer
schnarf@2656
  1269
#ifdef DEBUG_CONVERT
schnarf@2656
  1270
	printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
schnarf@2656
  1271
#endif
schnarf@2655
  1272
    switch (SDL_AUDIO_BITSIZE(format)) {
schnarf@2655
  1273
    case 8:
schnarf@2655
  1274
        zerostuff_mono(Uint8);
schnarf@2655
  1275
        break;
schnarf@2655
  1276
    case 16:
schnarf@2655
  1277
        zerostuff_mono(Uint16);
schnarf@2655
  1278
        break;
schnarf@2655
  1279
    case 32:
schnarf@2655
  1280
        zerostuff_mono(Uint32);
schnarf@2655
  1281
        break;
schnarf@2655
  1282
    }
schnarf@2655
  1283
	
schnarf@2655
  1284
	cvt->len_cvt *= cvt->len_mult;
schnarf@2655
  1285
schnarf@2655
  1286
	// Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
schnarf@2655
  1287
	
schnarf@2655
  1288
	// Step 3: Discard unnecessary samples
schnarf@2656
  1289
#ifdef DEBUG_CONVERT
schnarf@2656
  1290
	printf("Discarding samples by a factor of %u\n", cvt->len_div);
schnarf@2656
  1291
#endif
schnarf@2655
  1292
    switch (SDL_AUDIO_BITSIZE(format)) {
schnarf@2655
  1293
    case 8:
schnarf@2655
  1294
        discard_mono(Uint8);
schnarf@2655
  1295
        break;
schnarf@2655
  1296
    case 16:
schnarf@2655
  1297
        discard_mono(Uint16);
schnarf@2655
  1298
        break;
schnarf@2655
  1299
    case 32:
schnarf@2655
  1300
        discard_mono(Uint32);
schnarf@2655
  1301
        break;
schnarf@2655
  1302
    }
schnarf@2655
  1303
	
schnarf@2655
  1304
#undef zerostuff_mono
schnarf@2655
  1305
#undef discard_mono
schnarf@2655
  1306
schnarf@2655
  1307
    cvt->len_cvt /= cvt->len_div;
schnarf@2655
  1308
	
schnarf@2655
  1309
    if (cvt->filters[++cvt->filter_index]) {
schnarf@2655
  1310
        cvt->filters[cvt->filter_index] (cvt, format);
schnarf@2655
  1311
    }
schnarf@2655
  1312
}
schnarf@2655
  1313
slouken@1895
  1314
int
slouken@1895
  1315
SDL_ConvertAudio(SDL_AudioCVT * cvt)
slouken@0
  1316
{
slouken@1895
  1317
    /* Make sure there's data to convert */
slouken@1895
  1318
    if (cvt->buf == NULL) {
slouken@1895
  1319
        SDL_SetError("No buffer allocated for conversion");
slouken@1895
  1320
        return (-1);
slouken@1895
  1321
    }
slouken@1895
  1322
    /* Return okay if no conversion is necessary */
slouken@1895
  1323
    cvt->len_cvt = cvt->len;
slouken@1895
  1324
    if (cvt->filters[0] == NULL) {
slouken@1895
  1325
        return (0);
slouken@1895
  1326
    }
slouken@0
  1327
slouken@1895
  1328
    /* Set up the conversion and go! */
slouken@1895
  1329
    cvt->filter_index = 0;
slouken@1895
  1330
    cvt->filters[0] (cvt, cvt->src_format);
slouken@1895
  1331
    return (0);
slouken@0
  1332
}
slouken@0
  1333
icculus@1982
  1334
icculus@1982
  1335
static SDL_AudioFilter
icculus@1982
  1336
SDL_HandTunedTypeCVT(SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
  1337
{
icculus@1982
  1338
    /*
icculus@1982
  1339
     * Fill in any future conversions that are specialized to a
icculus@1982
  1340
     *  processor, platform, compiler, or library here.
icculus@1982
  1341
     */
icculus@1982
  1342
slouken@1985
  1343
    return NULL;                /* no specialized converter code available. */
icculus@1982
  1344
}
icculus@1982
  1345
icculus@1982
  1346
icculus@1982
  1347
/*
icculus@1982
  1348
 * Find a converter between two data types. We try to select a hand-tuned
icculus@1982
  1349
 *  asm/vectorized/optimized function first, and then fallback to an
icculus@1982
  1350
 *  autogenerated function that is customized to convert between two
icculus@1982
  1351
 *  specific data types.
icculus@1982
  1352
 */
icculus@1982
  1353
static int
icculus@1982
  1354
SDL_BuildAudioTypeCVT(SDL_AudioCVT * cvt,
icculus@1982
  1355
                      SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
  1356
{
icculus@1982
  1357
    if (src_fmt != dst_fmt) {
icculus@1982
  1358
        const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
icculus@1982
  1359
        const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
icculus@1982
  1360
        SDL_AudioFilter filter = SDL_HandTunedTypeCVT(src_fmt, dst_fmt);
icculus@1982
  1361
icculus@1982
  1362
        /* No hand-tuned converter? Try the autogenerated ones. */
icculus@1982
  1363
        if (filter == NULL) {
icculus@1982
  1364
            int i;
icculus@1982
  1365
            for (i = 0; sdl_audio_type_filters[i].filter != NULL; i++) {
icculus@1982
  1366
                const SDL_AudioTypeFilters *filt = &sdl_audio_type_filters[i];
icculus@1982
  1367
                if ((filt->src_fmt == src_fmt) && (filt->dst_fmt == dst_fmt)) {
icculus@1982
  1368
                    filter = filt->filter;
icculus@1982
  1369
                    break;
icculus@1982
  1370
                }
icculus@1982
  1371
            }
icculus@1982
  1372
icculus@1982
  1373
            if (filter == NULL) {
slouken@1985
  1374
                return -1;      /* Still no matching converter?! */
icculus@1982
  1375
            }
icculus@1982
  1376
        }
icculus@1982
  1377
icculus@1982
  1378
        /* Update (cvt) with filter details... */
icculus@1982
  1379
        cvt->filters[cvt->filter_index++] = filter;
icculus@1982
  1380
        if (src_bitsize < dst_bitsize) {
icculus@1982
  1381
            const int mult = (dst_bitsize / src_bitsize);
icculus@1982
  1382
            cvt->len_mult *= mult;
icculus@1982
  1383
            cvt->len_ratio *= mult;
icculus@1982
  1384
        } else if (src_bitsize > dst_bitsize) {
icculus@1982
  1385
            cvt->len_ratio /= (src_bitsize / dst_bitsize);
icculus@1982
  1386
        }
icculus@1982
  1387
slouken@1985
  1388
        return 1;               /* added a converter. */
icculus@1982
  1389
    }
icculus@1982
  1390
slouken@1985
  1391
    return 0;                   /* no conversion necessary. */
icculus@1982
  1392
}
icculus@1982
  1393
schnarf@2655
  1394
/* Generate the necessary IIR lowpass coefficients for resampling.
schnarf@2655
  1395
   Assume that the SDL_AudioCVT struct is already set up with
schnarf@2655
  1396
   the correct values for len_mult and len_div, and use the
schnarf@2655
  1397
   type of dst_format. Also assume the buffer is allocated.
schnarf@2655
  1398
   Note the buffer needs to be 6 units long.
schnarf@2655
  1399
   For now, use RBJ's cookbook coefficients. It might be more
schnarf@2655
  1400
   optimal to create a Butterworth filter, but this is more difficult.
schnarf@2655
  1401
*/
schnarf@2655
  1402
int SDL_BuildIIRLowpass(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
schnarf@2655
  1403
	float fc;			/* cutoff frequency */
schnarf@2655
  1404
	float coeff[6];		/* floating point iir coefficients b0, b1, b2, a0, a1, a2 */
schnarf@2655
  1405
	float scale;
schnarf@2655
  1406
	float w0, alpha, cosw0;
schnarf@2655
  1407
	
schnarf@2655
  1408
	/* The higher Q is, the higher CUTOFF can be. Need to find a good balance to avoid aliasing */
schnarf@2655
  1409
	static const float Q = 5.0f;
schnarf@2655
  1410
	static const float CUTOFF = 0.4f;
schnarf@2655
  1411
	
schnarf@2655
  1412
	fc = (cvt->len_mult > cvt->len_div) ? CUTOFF / (float)cvt->len_mult : CUTOFF / (float)cvt->len_div;
schnarf@2655
  1413
	
schnarf@2655
  1414
	w0 = 2.0f * M_PI * fc;
schnarf@2655
  1415
	cosw0 = cosf(w0);
schnarf@2655
  1416
	alpha = sin(w0) / (2.0f * Q);
schnarf@2655
  1417
	
schnarf@2655
  1418
	/* Compute coefficients, normalizing by a0 */
schnarf@2655
  1419
	scale = 1.0f / (1.0f + alpha);
schnarf@2655
  1420
	
schnarf@2655
  1421
	coeff[0] = (1.0f - cosw0) / 2.0f * scale;
schnarf@2655
  1422
	coeff[1] = (1.0f - cosw0) * scale;
schnarf@2655
  1423
	coeff[2] = coeff[0];
schnarf@2655
  1424
	
schnarf@2655
  1425
	coeff[3] = 1.0f;	/* a0 is normalized to 1 */
schnarf@2655
  1426
	coeff[4] = -2.0f * cosw0 * scale;
schnarf@2655
  1427
	coeff[5] = (1.0f - alpha) * scale;
schnarf@2655
  1428
	
schnarf@2656
  1429
	/* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */
schnarf@2656
  1430
	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
schnarf@2656
  1431
		float *cvt_coeff = (float *)cvt->coeff;
schnarf@2656
  1432
		int i;
schnarf@2656
  1433
		for(i = 0; i < 6; ++i) {
schnarf@2656
  1434
			cvt_coeff[i] = coeff[i];
schnarf@2656
  1435
		}
schnarf@2656
  1436
	} else {
schnarf@2656
  1437
	}
schnarf@2655
  1438
	
schnarf@2655
  1439
	/* Initialize the state buffer to all zeroes, and set initial position */
schnarf@2655
  1440
	memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4);
schnarf@2655
  1441
	cvt->state_pos = 0;
schnarf@2655
  1442
}
schnarf@2655
  1443
schnarf@2656
  1444
/* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */
schnarf@2656
  1445
int SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
schnarf@2656
  1446
	int i, n;
schnarf@2656
  1447
	
schnarf@2656
  1448
	n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
schnarf@2656
  1449
	
schnarf@2656
  1450
	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
schnarf@2656
  1451
		float *coeff = (float *)cvt->coeff;
schnarf@2656
  1452
		float *state = (float *)cvt->state_buf;
schnarf@2656
  1453
		float *buf = (float *)cvt->buf;
schnarf@2656
  1454
		float temp;
schnarf@2656
  1455
schnarf@2656
  1456
		
schnarf@2656
  1457
		for(i = 0; i < n; ++i) {
schnarf@2656
  1458
			/* y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a[2] * y[n-2] */
schnarf@2656
  1459
			temp = buf[n];
schnarf@2656
  1460
			if( cvt->state_pos ) {
schnarf@2656
  1461
				buf[n] = coeff[0] * buf[n] + coeff[1] * state[0] + coeff[2] * state[1] - coeff[4] * state[2] - coeff[5] * state[3];
schnarf@2656
  1462
				state[1] = temp;
schnarf@2656
  1463
				state[3] = buf[n];
schnarf@2656
  1464
				cvt->state_pos = 0;
schnarf@2656
  1465
			} else {
schnarf@2656
  1466
				buf[n] = coeff[0] * buf[n] + coeff[1] * state[1] + coeff[2] * state[0] - coeff[4] * state[3] - coeff[5] * state[2];
schnarf@2656
  1467
				state[0] = temp;
schnarf@2656
  1468
				state[2] = buf[n];
schnarf@2656
  1469
				cvt->state_pos = 1;
schnarf@2656
  1470
			}
schnarf@2656
  1471
		}
schnarf@2656
  1472
	} else {
schnarf@2656
  1473
	}
schnarf@2656
  1474
}
schnarf@2656
  1475
schnarf@2655
  1476
/* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */
schnarf@2655
  1477
int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
schnarf@2655
  1478
	int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
schnarf@2655
  1479
	int m = cvt->len_sinc;
schnarf@2655
  1480
	int i, j;
schnarf@2655
  1481
	
schnarf@2655
  1482
	/* Note: this makes use of the symmetry of the sinc filter.
schnarf@2655
  1483
	   We can also make a big optimization here by taking advantage
schnarf@2655
  1484
	   of the fact that the signal is zero stuffed, so we can do
schnarf@2655
  1485
	   significantly fewer multiplications and additions.
schnarf@2655
  1486
	*/
schnarf@2655
  1487
#define filter_sinc(type, shift_bits) { \
schnarf@2656
  1488
			type *sinc = (type *)cvt->coeff; \
schnarf@2655
  1489
			type *state = (type *)cvt->state_buf; \
schnarf@2655
  1490
			type *buf = (type *)cvt->buf; \
schnarf@2655
  1491
			for(i = 0; i < n; ++i) { \
schnarf@2655
  1492
				state[cvt->state_pos++] = buf[i] >> shift_bits; \
schnarf@2655
  1493
				if(cvt->state_pos == m) cvt->state_pos = 0; \
schnarf@2655
  1494
				buf[i] = 0; \
schnarf@2655
  1495
				for(j = 0; j < m;  ++j) { \
schnarf@2655
  1496
					buf[i] += state[j] * sinc[j]; \
schnarf@2655
  1497
				} \
schnarf@2655
  1498
			} \
schnarf@2655
  1499
		}
schnarf@2656
  1500
	
schnarf@2656
  1501
	/* If it's floating point, we don't need to do any shifting */
schnarf@2656
  1502
	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
schnarf@2656
  1503
		float *sinc = (float *)cvt->coeff;
schnarf@2656
  1504
		float *state = (float *)cvt->state_buf;
schnarf@2656
  1505
		float *buf = (float *)cvt->buf;
schnarf@2656
  1506
		
schnarf@2656
  1507
		for(i = 0; i < n; ++i) {
schnarf@2656
  1508
			state[cvt->state_pos++] = buf[i];
schnarf@2656
  1509
			if(cvt->state_pos == m) cvt->state_pos = 0;
schnarf@2656
  1510
			buf[i] = 0.0f;
schnarf@2656
  1511
			for(j = 0; j < m; ++j) {
schnarf@2656
  1512
				buf[i] += state[j] * sinc[j];
schnarf@2656
  1513
			}
schnarf@2656
  1514
		}
schnarf@2656
  1515
	} else {
schnarf@2656
  1516
		switch (SDL_AUDIO_BITSIZE(format)) {
schnarf@2656
  1517
			case 8:
schnarf@2656
  1518
				filter_sinc(Uint8, 4);
schnarf@2656
  1519
				break;
schnarf@2656
  1520
			case 16:
schnarf@2656
  1521
				filter_sinc(Uint16, 8);
schnarf@2656
  1522
				break;
schnarf@2656
  1523
			case 32:
schnarf@2656
  1524
				filter_sinc(Uint32, 16);
schnarf@2656
  1525
				break;
schnarf@2656
  1526
		}
schnarf@2655
  1527
	}
schnarf@2655
  1528
	
schnarf@2655
  1529
#undef filter_sinc
schnarf@2655
  1530
			
schnarf@2655
  1531
}
schnarf@2655
  1532
schnarf@2655
  1533
/* Generate the necessary windowed sinc filter for resampling.
schnarf@2655
  1534
   Assume that the SDL_AudioCVT struct is already set up with
schnarf@2655
  1535
   the correct values for len_mult and len_div, and use the
schnarf@2655
  1536
   type of dst_format. Also assume the buffer is allocated.
schnarf@2655
  1537
   Note the buffer needs to be m+1 units long.
schnarf@2655
  1538
*/
schnarf@2655
  1539
int
schnarf@2655
  1540
SDL_BuildWindowedSinc(SDL_AudioCVT * cvt, SDL_AudioFormat format, unsigned int m) {
schnarf@2655
  1541
	float fScale;		/* scale factor for fixed point */
schnarf@2655
  1542
	float *fSinc;		/* floating point sinc buffer, to be converted to fixed point */
schnarf@2655
  1543
	float fc;			/* cutoff frequency */
schnarf@2655
  1544
	float two_pi_fc, two_pi_over_m, four_pi_over_m, m_over_two;
schnarf@2655
  1545
	float norm_sum, norm_fact;
schnarf@2655
  1546
	unsigned int i;
schnarf@2655
  1547
schnarf@2655
  1548
	/* Check that the buffer is allocated */
schnarf@2656
  1549
	if( cvt->coeff == NULL ) {
schnarf@2655
  1550
		return -1;
schnarf@2655
  1551
	}
schnarf@2655
  1552
schnarf@2655
  1553
	/* Set the length */
schnarf@2655
  1554
	cvt->len_sinc = m;
schnarf@2655
  1555
	
schnarf@2655
  1556
	/* Allocate the floating point windowed sinc. */
schnarf@2655
  1557
	fSinc = (float *)malloc(m * sizeof(float));
schnarf@2655
  1558
	if( fSinc == NULL ) {
schnarf@2655
  1559
		return -1;
schnarf@2655
  1560
	}
schnarf@2655
  1561
	
schnarf@2655
  1562
	/* Set up the filter parameters */
schnarf@2655
  1563
	fc = (cvt->len_mult > cvt->len_div) ? 0.5f / (float)cvt->len_mult : 0.5f / (float)cvt->len_div;
schnarf@2655
  1564
	two_pi_fc = 2.0f * M_PI * fc;
schnarf@2655
  1565
	two_pi_over_m = 2.0f * M_PI / (float)m;
schnarf@2655
  1566
	four_pi_over_m = 2.0f * two_pi_over_m;
schnarf@2655
  1567
	m_over_two = (float)m / 2.0f;
schnarf@2655
  1568
	norm_sum = 0.0f;
schnarf@2655
  1569
	
schnarf@2655
  1570
	for(i = 0; i <= m; ++i ) {
schnarf@2655
  1571
		if( i == m/2 ) {
schnarf@2655
  1572
			fSinc[i] = two_pi_fc;
schnarf@2655
  1573
		} else {
schnarf@2655
  1574
			fSinc[i] = sinf(two_pi_fc * ((float)i - m_over_two)) / ((float)i - m_over_two);
schnarf@2655
  1575
			/* Apply blackman window */
schnarf@2655
  1576
			fSinc[i] *= 0.42f - 0.5f * cosf(two_pi_over_m * (float)i) + 0.08f * cosf(four_pi_over_m * (float)i);
schnarf@2655
  1577
		}
schnarf@2655
  1578
		norm_sum += abs(fSinc[i]);
schnarf@2655
  1579
	}
schnarf@2655
  1580
schnarf@2655
  1581
	/* Now normalize and convert to fixed point. We scale everything to half the precision
schnarf@2655
  1582
	   of whatever datatype we're using, for example, 16 bit data means we use 8 bits */
schnarf@2655
  1583
	
schnarf@2655
  1584
#define convert_fixed(type, size) { \
schnarf@2655
  1585
		norm_fact = size / norm_sum; \
schnarf@2656
  1586
		type *dst = (type *)cvt->coeff; \
schnarf@2655
  1587
		for( i = 0; i <= m; ++i ) { \
schnarf@2655
  1588
			dst[i] = (type)(fSinc[i] * norm_fact); \
schnarf@2655
  1589
		} \
schnarf@2655
  1590
	}
schnarf@2655
  1591
	
schnarf@2655
  1592
	/* If we're using floating point, we only need to normalize */
schnarf@2655
  1593
	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
schnarf@2656
  1594
		float *fDest = (float *)cvt->coeff;
schnarf@2655
  1595
		norm_fact = 1.0f / norm_sum;
schnarf@2655
  1596
		for(i = 0; i <= m; ++i) {
schnarf@2655
  1597
			fDest[i] = fSinc[i] * norm_fact;
schnarf@2655
  1598
		}
schnarf@2655
  1599
	} else {
schnarf@2655
  1600
		switch (SDL_AUDIO_BITSIZE(format)) {
schnarf@2655
  1601
			case 8:
schnarf@2655
  1602
				convert_fixed(Uint8, 0x0e);
schnarf@2655
  1603
				break;
schnarf@2655
  1604
			case 16:
schnarf@2655
  1605
				convert_fixed(Uint16, 0xfe);
schnarf@2655
  1606
				break;
schnarf@2655
  1607
			case 32:
schnarf@2655
  1608
				convert_fixed(Uint32, 0xfffe);
schnarf@2655
  1609
				break;
schnarf@2655
  1610
		}
schnarf@2655
  1611
	}
schnarf@2655
  1612
	
schnarf@2655
  1613
	/* Initialize the state buffer to all zeroes, and set initial position */
schnarf@2655
  1614
	memset(cvt->state_buf, 0, cvt->len_sinc * SDL_AUDIO_BITSIZE(format) / 4);
schnarf@2655
  1615
	cvt->state_pos = 0;
schnarf@2655
  1616
	
schnarf@2655
  1617
	/* Clean up */
schnarf@2655
  1618
#undef convert_fixed
schnarf@2655
  1619
	free(fSinc);
schnarf@2655
  1620
}
icculus@1982
  1621
schnarf@2656
  1622
/* This is used to reduce the resampling ratio */
schnarf@2656
  1623
inline int SDL_GCD(int a, int b) {
schnarf@2656
  1624
	int temp;
schnarf@2656
  1625
	while(b != 0) {
schnarf@2656
  1626
		temp = a % b;
schnarf@2656
  1627
		a = b;
schnarf@2656
  1628
		b = temp;
schnarf@2656
  1629
	}
schnarf@2656
  1630
	return a;
schnarf@2656
  1631
}
schnarf@2656
  1632
icculus@1982
  1633
icculus@1982
  1634
/* Creates a set of audio filters to convert from one format to another.
icculus@1982
  1635
   Returns -1 if the format conversion is not supported, 0 if there's
icculus@1982
  1636
   no conversion needed, or 1 if the audio filter is set up.
slouken@0
  1637
*/
slouken@1895
  1638
slouken@1895
  1639
int
slouken@1895
  1640
SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
icculus@1982
  1641
                  SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
icculus@1982
  1642
                  SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
slouken@0
  1643
{
icculus@1982
  1644
    /* there are no unsigned types over 16 bits, so catch this upfront. */
icculus@1982
  1645
    if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
icculus@1982
  1646
        return -1;
icculus@1982
  1647
    }
icculus@1982
  1648
    if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
icculus@1982
  1649
        return -1;
icculus@1982
  1650
    }
slouken@1985
  1651
#ifdef DEBUG_CONVERT
icculus@1982
  1652
    printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
slouken@1985
  1653
           src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
slouken@1985
  1654
#endif
icculus@1982
  1655
slouken@1895
  1656
    /* Start off with no conversion necessary */
icculus@1982
  1657
icculus@1982
  1658
    cvt->src_format = src_fmt;
icculus@1982
  1659
    cvt->dst_format = dst_fmt;
slouken@1895
  1660
    cvt->needed = 0;
slouken@1895
  1661
    cvt->filter_index = 0;
slouken@1895
  1662
    cvt->filters[0] = NULL;
slouken@1895
  1663
    cvt->len_mult = 1;
slouken@1895
  1664
    cvt->len_ratio = 1.0;
slouken@0
  1665
icculus@1982
  1666
    /* Convert data types, if necessary. Updates (cvt). */
icculus@1982
  1667
    if (SDL_BuildAudioTypeCVT(cvt, src_fmt, dst_fmt) == -1)
slouken@1985
  1668
        return -1;              /* shouldn't happen, but just in case... */
slouken@0
  1669
icculus@1982
  1670
    /* Channel conversion */
slouken@1895
  1671
    if (src_channels != dst_channels) {
slouken@1895
  1672
        if ((src_channels == 1) && (dst_channels > 1)) {
slouken@1895
  1673
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1674
            cvt->len_mult *= 2;
slouken@1895
  1675
            src_channels = 2;
slouken@1895
  1676
            cvt->len_ratio *= 2;
slouken@1895
  1677
        }
slouken@1895
  1678
        if ((src_channels == 2) && (dst_channels == 6)) {
slouken@1895
  1679
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
slouken@1895
  1680
            src_channels = 6;
slouken@1895
  1681
            cvt->len_mult *= 3;
slouken@1895
  1682
            cvt->len_ratio *= 3;
slouken@1895
  1683
        }
slouken@1895
  1684
        if ((src_channels == 2) && (dst_channels == 4)) {
slouken@1895
  1685
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
slouken@1895
  1686
            src_channels = 4;
slouken@1895
  1687
            cvt->len_mult *= 2;
slouken@1895
  1688
            cvt->len_ratio *= 2;
slouken@1895
  1689
        }
slouken@1895
  1690
        while ((src_channels * 2) <= dst_channels) {
slouken@1895
  1691
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1692
            cvt->len_mult *= 2;
slouken@1895
  1693
            src_channels *= 2;
slouken@1895
  1694
            cvt->len_ratio *= 2;
slouken@1895
  1695
        }
slouken@1895
  1696
        if ((src_channels == 6) && (dst_channels <= 2)) {
slouken@1895
  1697
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
slouken@1895
  1698
            src_channels = 2;
slouken@1895
  1699
            cvt->len_ratio /= 3;
slouken@1895
  1700
        }
slouken@1895
  1701
        if ((src_channels == 6) && (dst_channels == 4)) {
slouken@1895
  1702
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
slouken@1895
  1703
            src_channels = 4;
slouken@1895
  1704
            cvt->len_ratio /= 2;
slouken@1895
  1705
        }
slouken@1895
  1706
        /* This assumes that 4 channel audio is in the format:
slouken@1895
  1707
           Left {front/back} + Right {front/back}
slouken@1895
  1708
           so converting to L/R stereo works properly.
slouken@1895
  1709
         */
slouken@1895
  1710
        while (((src_channels % 2) == 0) &&
slouken@1895
  1711
               ((src_channels / 2) >= dst_channels)) {
slouken@1895
  1712
            cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
slouken@1895
  1713
            src_channels /= 2;
slouken@1895
  1714
            cvt->len_ratio /= 2;
slouken@1895
  1715
        }
slouken@1895
  1716
        if (src_channels != dst_channels) {
slouken@1895
  1717
            /* Uh oh.. */ ;
slouken@1895
  1718
        }
slouken@1895
  1719
    }
slouken@0
  1720
slouken@1895
  1721
    /* Do rate conversion */
schnarf@2656
  1722
	int rate_gcd;
schnarf@2656
  1723
	rate_gcd = SDL_GCD(src_rate, dst_rate);
schnarf@2656
  1724
	cvt->len_mult = dst_rate / rate_gcd;
schnarf@2656
  1725
	cvt->len_div = src_rate / rate_gcd;
schnarf@2656
  1726
	cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
schnarf@2656
  1727
	cvt->filters[cvt->filter_index++] = SDL_Resample;
schnarf@2656
  1728
	
schnarf@2656
  1729
    /*cvt->rate_incr = 0.0;
slouken@1895
  1730
    if ((src_rate / 100) != (dst_rate / 100)) {
slouken@1895
  1731
        Uint32 hi_rate, lo_rate;
slouken@1895
  1732
        int len_mult;
slouken@1895
  1733
        double len_ratio;
icculus@1982
  1734
        SDL_AudioFilter rate_cvt = NULL;
slouken@1895
  1735
slouken@1895
  1736
        if (src_rate > dst_rate) {
slouken@1895
  1737
            hi_rate = src_rate;
slouken@1895
  1738
            lo_rate = dst_rate;
slouken@1895
  1739
            switch (src_channels) {
slouken@1895
  1740
            case 1:
slouken@1895
  1741
                rate_cvt = SDL_RateDIV2;
slouken@1895
  1742
                break;
slouken@1895
  1743
            case 2:
slouken@1895
  1744
                rate_cvt = SDL_RateDIV2_c2;
slouken@1895
  1745
                break;
slouken@1895
  1746
            case 4:
slouken@1895
  1747
                rate_cvt = SDL_RateDIV2_c4;
slouken@1895
  1748
                break;
slouken@1895
  1749
            case 6:
slouken@1895
  1750
                rate_cvt = SDL_RateDIV2_c6;
slouken@1895
  1751
                break;
slouken@1895
  1752
            default:
slouken@1895
  1753
                return -1;
slouken@1895
  1754
            }
slouken@1895
  1755
            len_mult = 1;
slouken@1895
  1756
            len_ratio = 0.5;
slouken@1895
  1757
        } else {
slouken@1895
  1758
            hi_rate = dst_rate;
slouken@1895
  1759
            lo_rate = src_rate;
slouken@1895
  1760
            switch (src_channels) {
slouken@1895
  1761
            case 1:
slouken@1895
  1762
                rate_cvt = SDL_RateMUL2;
slouken@1895
  1763
                break;
slouken@1895
  1764
            case 2:
slouken@1895
  1765
                rate_cvt = SDL_RateMUL2_c2;
slouken@1895
  1766
                break;
slouken@1895
  1767
            case 4:
slouken@1895
  1768
                rate_cvt = SDL_RateMUL2_c4;
slouken@1895
  1769
                break;
slouken@1895
  1770
            case 6:
slouken@1895
  1771
                rate_cvt = SDL_RateMUL2_c6;
slouken@1895
  1772
                break;
slouken@1895
  1773
            default:
slouken@1895
  1774
                return -1;
slouken@1895
  1775
            }
slouken@1895
  1776
            len_mult = 2;
slouken@1895
  1777
            len_ratio = 2.0;
schnarf@2656
  1778
        }*/
slouken@1895
  1779
        /* If hi_rate = lo_rate*2^x then conversion is easy */
schnarf@2656
  1780
        /*while (((lo_rate * 2) / 100) <= (hi_rate / 100)) {
slouken@1895
  1781
            cvt->filters[cvt->filter_index++] = rate_cvt;
slouken@1895
  1782
            cvt->len_mult *= len_mult;
slouken@1895
  1783
            lo_rate *= 2;
slouken@1895
  1784
            cvt->len_ratio *= len_ratio;
schnarf@2656
  1785
        }*/
slouken@1895
  1786
        /* We may need a slow conversion here to finish up */
schnarf@2656
  1787
        /*if ((lo_rate / 100) != (hi_rate / 100)) {*/
slouken@0
  1788
#if 1
slouken@1895
  1789
            /* The problem with this is that if the input buffer is
slouken@1895
  1790
               say 1K, and the conversion rate is say 1.1, then the
slouken@1895
  1791
               output buffer is 1.1K, which may not be an acceptable
slouken@1895
  1792
               buffer size for the audio driver (not a power of 2)
slouken@1895
  1793
             */
slouken@1895
  1794
            /* For now, punt and hope the rate distortion isn't great.
slouken@1895
  1795
             */
slouken@0
  1796
#else
slouken@1895
  1797
            if (src_rate < dst_rate) {
slouken@1895
  1798
                cvt->rate_incr = (double) lo_rate / hi_rate;
slouken@1895
  1799
                cvt->len_mult *= 2;
slouken@1895
  1800
                cvt->len_ratio /= cvt->rate_incr;
slouken@1895
  1801
            } else {
slouken@1895
  1802
                cvt->rate_incr = (double) hi_rate / lo_rate;
slouken@1895
  1803
                cvt->len_ratio *= cvt->rate_incr;
slouken@1895
  1804
            }
slouken@1895
  1805
            cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
slouken@0
  1806
#endif
schnarf@2656
  1807
/*        }
schnarf@2656
  1808
    }*/
slouken@0
  1809
slouken@1895
  1810
    /* Set up the filter information */
slouken@1895
  1811
    if (cvt->filter_index != 0) {
slouken@1895
  1812
        cvt->needed = 1;
icculus@1982
  1813
        cvt->src_format = src_fmt;
icculus@1982
  1814
        cvt->dst_format = dst_fmt;
slouken@1895
  1815
        cvt->len = 0;
slouken@1895
  1816
        cvt->buf = NULL;
slouken@1895
  1817
        cvt->filters[cvt->filter_index] = NULL;
slouken@1895
  1818
    }
slouken@1895
  1819
    return (cvt->needed);
slouken@0
  1820
}
slouken@1895
  1821
slouken@1895
  1822
/* vi: set ts=4 sw=4 expandtab: */