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