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