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