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