src/audio/SDL_audiocvt.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 26 May 2015 21:19:23 -0400
changeset 9649 d7762e30ba24
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
Stack hint should look for 0, not -1, and not care about environment variables.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@2728
    22
slouken@0
    23
/* Functions for audio drivers to perform runtime conversion of audio format */
slouken@0
    24
slouken@0
    25
#include "SDL_audio.h"
icculus@1982
    26
#include "SDL_audio_c.h"
slouken@0
    27
icculus@6281
    28
#include "SDL_assert.h"
icculus@6281
    29
icculus@3021
    30
/* #define DEBUG_CONVERT */
slouken@2716
    31
slouken@0
    32
/* Effectively mix right and left channels into a single channel */
icculus@1982
    33
static void SDLCALL
icculus@1982
    34
SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
    35
{
slouken@1895
    36
    int i;
slouken@1895
    37
    Sint32 sample;
slouken@0
    38
slouken@0
    39
#ifdef DEBUG_CONVERT
slouken@1895
    40
    fprintf(stderr, "Converting to mono\n");
slouken@0
    41
#endif
jlegg@8235
    42
	switch (format & (SDL_AUDIO_MASK_SIGNED |
jlegg@8235
    43
                      SDL_AUDIO_MASK_BITSIZE |
jlegg@8235
    44
                      SDL_AUDIO_MASK_DATATYPE)) {
slouken@1895
    45
    case AUDIO_U8:
slouken@1895
    46
        {
slouken@1895
    47
            Uint8 *src, *dst;
slouken@0
    48
slouken@1895
    49
            src = cvt->buf;
slouken@1895
    50
            dst = cvt->buf;
slouken@1895
    51
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    52
                sample = src[0] + src[1];
slouken@2042
    53
                *dst = (Uint8) (sample / 2);
slouken@1895
    54
                src += 2;
slouken@1895
    55
                dst += 1;
slouken@1895
    56
            }
slouken@1895
    57
        }
slouken@1895
    58
        break;
slouken@0
    59
slouken@1895
    60
    case AUDIO_S8:
slouken@1895
    61
        {
slouken@1895
    62
            Sint8 *src, *dst;
slouken@0
    63
slouken@1895
    64
            src = (Sint8 *) cvt->buf;
slouken@1895
    65
            dst = (Sint8 *) cvt->buf;
slouken@1895
    66
            for (i = cvt->len_cvt / 2; i; --i) {
slouken@1895
    67
                sample = src[0] + src[1];
slouken@2042
    68
                *dst = (Sint8) (sample / 2);
slouken@1895
    69
                src += 2;
slouken@1895
    70
                dst += 1;
slouken@1895
    71
            }
slouken@1895
    72
        }
slouken@1895
    73
        break;
slouken@0
    74
slouken@1895
    75
    case AUDIO_U16:
slouken@1895
    76
        {
slouken@1895
    77
            Uint8 *src, *dst;
slouken@0
    78
slouken@1895
    79
            src = cvt->buf;
slouken@1895
    80
            dst = cvt->buf;
icculus@1982
    81
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
    82
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
    83
                    sample = (Uint16) ((src[0] << 8) | src[1]) +
slouken@1895
    84
                        (Uint16) ((src[2] << 8) | src[3]);
slouken@2042
    85
                    sample /= 2;
slouken@2042
    86
                    dst[1] = (sample & 0xFF);
slouken@2042
    87
                    sample >>= 8;
slouken@2042
    88
                    dst[0] = (sample & 0xFF);
slouken@1895
    89
                    src += 4;
slouken@1895
    90
                    dst += 2;
slouken@1895
    91
                }
slouken@1895
    92
            } else {
slouken@1895
    93
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
    94
                    sample = (Uint16) ((src[1] << 8) | src[0]) +
slouken@1895
    95
                        (Uint16) ((src[3] << 8) | src[2]);
slouken@2042
    96
                    sample /= 2;
slouken@2042
    97
                    dst[0] = (sample & 0xFF);
slouken@2042
    98
                    sample >>= 8;
slouken@2042
    99
                    dst[1] = (sample & 0xFF);
slouken@1895
   100
                    src += 4;
slouken@1895
   101
                    dst += 2;
slouken@1895
   102
                }
slouken@1895
   103
            }
slouken@1895
   104
        }
slouken@1895
   105
        break;
slouken@0
   106
slouken@1895
   107
    case AUDIO_S16:
slouken@1895
   108
        {
slouken@1895
   109
            Uint8 *src, *dst;
slouken@0
   110
slouken@1895
   111
            src = cvt->buf;
slouken@1895
   112
            dst = cvt->buf;
icculus@1982
   113
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   114
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   115
                    sample = (Sint16) ((src[0] << 8) | src[1]) +
slouken@1895
   116
                        (Sint16) ((src[2] << 8) | src[3]);
slouken@2042
   117
                    sample /= 2;
slouken@2042
   118
                    dst[1] = (sample & 0xFF);
slouken@2042
   119
                    sample >>= 8;
slouken@2042
   120
                    dst[0] = (sample & 0xFF);
slouken@1895
   121
                    src += 4;
slouken@1895
   122
                    dst += 2;
slouken@1895
   123
                }
slouken@1895
   124
            } else {
slouken@1895
   125
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   126
                    sample = (Sint16) ((src[1] << 8) | src[0]) +
slouken@1895
   127
                        (Sint16) ((src[3] << 8) | src[2]);
slouken@2042
   128
                    sample /= 2;
slouken@2042
   129
                    dst[0] = (sample & 0xFF);
slouken@2042
   130
                    sample >>= 8;
slouken@2042
   131
                    dst[1] = (sample & 0xFF);
slouken@1895
   132
                    src += 4;
slouken@1895
   133
                    dst += 2;
slouken@1895
   134
                }
slouken@1895
   135
            }
slouken@1895
   136
        }
slouken@1895
   137
        break;
icculus@1982
   138
icculus@1982
   139
    case AUDIO_S32:
icculus@1982
   140
        {
icculus@1982
   141
            const Uint32 *src = (const Uint32 *) cvt->buf;
icculus@1982
   142
            Uint32 *dst = (Uint32 *) cvt->buf;
icculus@1982
   143
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   144
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   145
                    const Sint64 added =
slouken@1985
   146
                        (((Sint64) (Sint32) SDL_SwapBE32(src[0])) +
slouken@1985
   147
                         ((Sint64) (Sint32) SDL_SwapBE32(src[1])));
icculus@2078
   148
                    *(dst++) = SDL_SwapBE32((Uint32) ((Sint32) (added / 2)));
icculus@1982
   149
                }
icculus@1982
   150
            } else {
icculus@1982
   151
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@1982
   152
                    const Sint64 added =
slouken@1985
   153
                        (((Sint64) (Sint32) SDL_SwapLE32(src[0])) +
slouken@1985
   154
                         ((Sint64) (Sint32) SDL_SwapLE32(src[1])));
icculus@2078
   155
                    *(dst++) = SDL_SwapLE32((Uint32) ((Sint32) (added / 2)));
icculus@1982
   156
                }
icculus@1982
   157
            }
icculus@1982
   158
        }
icculus@1982
   159
        break;
icculus@1982
   160
icculus@1982
   161
    case AUDIO_F32:
icculus@1982
   162
        {
icculus@2014
   163
            const float *src = (const float *) cvt->buf;
icculus@2014
   164
            float *dst = (float *) cvt->buf;
icculus@1982
   165
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   166
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@2049
   167
                    const float src1 = SDL_SwapFloatBE(src[0]);
icculus@2049
   168
                    const float src2 = SDL_SwapFloatBE(src[1]);
icculus@1982
   169
                    const double added = ((double) src1) + ((double) src2);
icculus@2049
   170
                    const float halved = (float) (added * 0.5);
icculus@2049
   171
                    *(dst++) = SDL_SwapFloatBE(halved);
icculus@1982
   172
                }
icculus@1982
   173
            } else {
icculus@1982
   174
                for (i = cvt->len_cvt / 8; i; --i, src += 2) {
icculus@2049
   175
                    const float src1 = SDL_SwapFloatLE(src[0]);
icculus@2049
   176
                    const float src2 = SDL_SwapFloatLE(src[1]);
icculus@1982
   177
                    const double added = ((double) src1) + ((double) src2);
icculus@2049
   178
                    const float halved = (float) (added * 0.5);
icculus@2049
   179
                    *(dst++) = SDL_SwapFloatLE(halved);
icculus@1982
   180
                }
icculus@1982
   181
            }
icculus@1982
   182
        }
icculus@1982
   183
        break;
slouken@1895
   184
    }
icculus@1982
   185
slouken@1895
   186
    cvt->len_cvt /= 2;
slouken@1895
   187
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   188
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   189
    }
slouken@0
   190
}
slouken@0
   191
icculus@1982
   192
slouken@942
   193
/* Discard top 4 channels */
icculus@1982
   194
static void SDLCALL
icculus@1982
   195
SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   196
{
slouken@1895
   197
    int i;
slouken@942
   198
slouken@942
   199
#ifdef DEBUG_CONVERT
icculus@1982
   200
    fprintf(stderr, "Converting down from 6 channels to stereo\n");
slouken@942
   201
#endif
slouken@942
   202
slouken@1985
   203
#define strip_chans_6_to_2(type) \
icculus@1982
   204
    { \
icculus@1982
   205
        const type *src = (const type *) cvt->buf; \
icculus@1982
   206
        type *dst = (type *) cvt->buf; \
icculus@1982
   207
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   208
            dst[0] = src[0]; \
icculus@1982
   209
            dst[1] = src[1]; \
icculus@1982
   210
            src += 6; \
icculus@1982
   211
            dst += 2; \
icculus@1982
   212
        } \
icculus@1982
   213
    }
slouken@942
   214
icculus@1982
   215
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   216
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   217
    case 8:
slouken@1985
   218
        strip_chans_6_to_2(Uint8);
slouken@1985
   219
        break;
slouken@1985
   220
    case 16:
slouken@1985
   221
        strip_chans_6_to_2(Uint16);
slouken@1985
   222
        break;
slouken@1985
   223
    case 32:
slouken@1985
   224
        strip_chans_6_to_2(Uint32);
slouken@1985
   225
        break;
icculus@1982
   226
    }
slouken@942
   227
slouken@1985
   228
#undef strip_chans_6_to_2
slouken@942
   229
slouken@1895
   230
    cvt->len_cvt /= 3;
slouken@1895
   231
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   232
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   233
    }
slouken@942
   234
}
slouken@942
   235
slouken@942
   236
slouken@942
   237
/* Discard top 2 channels of 6 */
icculus@1982
   238
static void SDLCALL
icculus@1982
   239
SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   240
{
slouken@1895
   241
    int i;
slouken@942
   242
slouken@942
   243
#ifdef DEBUG_CONVERT
slouken@1895
   244
    fprintf(stderr, "Converting 6 down to quad\n");
slouken@942
   245
#endif
slouken@942
   246
slouken@1985
   247
#define strip_chans_6_to_4(type) \
icculus@1982
   248
    { \
icculus@1982
   249
        const type *src = (const type *) cvt->buf; \
icculus@1982
   250
        type *dst = (type *) cvt->buf; \
icculus@1982
   251
        for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
icculus@1982
   252
            dst[0] = src[0]; \
icculus@1982
   253
            dst[1] = src[1]; \
icculus@1982
   254
            dst[2] = src[2]; \
icculus@1982
   255
            dst[3] = src[3]; \
icculus@1982
   256
            src += 6; \
icculus@1982
   257
            dst += 4; \
icculus@1982
   258
        } \
icculus@1982
   259
    }
slouken@942
   260
icculus@1982
   261
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   262
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   263
    case 8:
slouken@1985
   264
        strip_chans_6_to_4(Uint8);
slouken@1985
   265
        break;
slouken@1985
   266
    case 16:
slouken@1985
   267
        strip_chans_6_to_4(Uint16);
slouken@1985
   268
        break;
slouken@1985
   269
    case 32:
slouken@1985
   270
        strip_chans_6_to_4(Uint32);
slouken@1985
   271
        break;
icculus@1982
   272
    }
slouken@942
   273
slouken@1985
   274
#undef strip_chans_6_to_4
slouken@942
   275
icculus@1982
   276
    cvt->len_cvt /= 6;
icculus@1982
   277
    cvt->len_cvt *= 4;
slouken@1895
   278
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   279
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   280
    }
slouken@942
   281
}
slouken@0
   282
slouken@0
   283
/* Duplicate a mono channel to both stereo channels */
icculus@1982
   284
static void SDLCALL
icculus@1982
   285
SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@0
   286
{
slouken@1895
   287
    int i;
slouken@0
   288
slouken@0
   289
#ifdef DEBUG_CONVERT
slouken@1895
   290
    fprintf(stderr, "Converting to stereo\n");
slouken@0
   291
#endif
slouken@0
   292
slouken@1985
   293
#define dup_chans_1_to_2(type) \
icculus@1982
   294
    { \
icculus@1982
   295
        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
icculus@1982
   296
        type *dst = (type *) (cvt->buf + cvt->len_cvt * 2); \
slouken@6210
   297
        for (i = cvt->len_cvt / sizeof(type); i; --i) { \
slouken@6210
   298
            src -= 1; \
icculus@1982
   299
            dst -= 2; \
icculus@7410
   300
            dst[0] = dst[1] = *src; \
icculus@1982
   301
        } \
icculus@1982
   302
    }
slouken@0
   303
icculus@1982
   304
    /* this function only cares about typesize, and data as a block of bits. */
icculus@1982
   305
    switch (SDL_AUDIO_BITSIZE(format)) {
slouken@1985
   306
    case 8:
slouken@1985
   307
        dup_chans_1_to_2(Uint8);
slouken@1985
   308
        break;
slouken@1985
   309
    case 16:
slouken@1985
   310
        dup_chans_1_to_2(Uint16);
slouken@1985
   311
        break;
slouken@1985
   312
    case 32:
slouken@1985
   313
        dup_chans_1_to_2(Uint32);
slouken@1985
   314
        break;
slouken@1895
   315
    }
icculus@1982
   316
slouken@1985
   317
#undef dup_chans_1_to_2
icculus@1982
   318
slouken@1895
   319
    cvt->len_cvt *= 2;
slouken@1895
   320
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   321
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   322
    }
slouken@0
   323
}
slouken@0
   324
slouken@942
   325
slouken@942
   326
/* Duplicate a stereo channel to a pseudo-5.1 stream */
icculus@1982
   327
static void SDLCALL
icculus@1982
   328
SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   329
{
slouken@1895
   330
    int i;
slouken@942
   331
slouken@942
   332
#ifdef DEBUG_CONVERT
slouken@1895
   333
    fprintf(stderr, "Converting stereo to surround\n");
slouken@942
   334
#endif
slouken@942
   335
jlegg@8235
   336
    switch (format & (SDL_AUDIO_MASK_SIGNED  |
jlegg@8235
   337
                      SDL_AUDIO_MASK_BITSIZE |
jlegg@8235
   338
                      SDL_AUDIO_MASK_DATATYPE)) {
slouken@1895
   339
    case AUDIO_U8:
slouken@1895
   340
        {
slouken@1895
   341
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   342
slouken@1895
   343
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   344
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 3);
slouken@1895
   345
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   346
                dst -= 6;
slouken@1895
   347
                src -= 2;
slouken@1895
   348
                lf = src[0];
slouken@1895
   349
                rf = src[1];
slouken@1895
   350
                ce = (lf / 2) + (rf / 2);
slouken@1895
   351
                dst[0] = lf;
slouken@1895
   352
                dst[1] = rf;
slouken@1895
   353
                dst[2] = lf - ce;
slouken@1895
   354
                dst[3] = rf - ce;
slouken@1895
   355
                dst[4] = ce;
slouken@1895
   356
                dst[5] = ce;
slouken@1895
   357
            }
slouken@1895
   358
        }
slouken@1895
   359
        break;
slouken@942
   360
slouken@1895
   361
    case AUDIO_S8:
slouken@1895
   362
        {
slouken@1895
   363
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   364
slouken@1895
   365
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   366
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 3;
slouken@1895
   367
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   368
                dst -= 6;
slouken@1895
   369
                src -= 2;
slouken@1895
   370
                lf = src[0];
slouken@1895
   371
                rf = src[1];
slouken@1895
   372
                ce = (lf / 2) + (rf / 2);
slouken@1895
   373
                dst[0] = lf;
slouken@1895
   374
                dst[1] = rf;
slouken@1895
   375
                dst[2] = lf - ce;
slouken@1895
   376
                dst[3] = rf - ce;
slouken@1895
   377
                dst[4] = ce;
slouken@1895
   378
                dst[5] = ce;
slouken@1895
   379
            }
slouken@1895
   380
        }
slouken@1895
   381
        break;
slouken@942
   382
slouken@1895
   383
    case AUDIO_U16:
slouken@1895
   384
        {
slouken@1895
   385
            Uint8 *src, *dst;
slouken@1895
   386
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   387
slouken@1895
   388
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   389
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   390
icculus@1982
   391
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   392
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   393
                    dst -= 12;
slouken@1895
   394
                    src -= 4;
slouken@1895
   395
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   396
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   397
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   398
                    rr = lf - ce;
slouken@1895
   399
                    lr = rf - ce;
slouken@1895
   400
                    dst[1] = (lf & 0xFF);
slouken@1895
   401
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   402
                    dst[3] = (rf & 0xFF);
slouken@1895
   403
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   404
slouken@1895
   405
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   406
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   407
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   408
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   409
slouken@1895
   410
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   411
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   412
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   413
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   414
                }
slouken@1895
   415
            } else {
slouken@1895
   416
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   417
                    dst -= 12;
slouken@1895
   418
                    src -= 4;
slouken@1895
   419
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   420
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   421
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   422
                    rr = lf - ce;
slouken@1895
   423
                    lr = rf - ce;
slouken@1895
   424
                    dst[0] = (lf & 0xFF);
slouken@1895
   425
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   426
                    dst[2] = (rf & 0xFF);
slouken@1895
   427
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   428
slouken@1895
   429
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   430
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   431
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   432
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   433
slouken@1895
   434
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   435
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   436
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   437
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   438
                }
slouken@1895
   439
            }
slouken@1895
   440
        }
slouken@1895
   441
        break;
slouken@942
   442
slouken@1895
   443
    case AUDIO_S16:
slouken@1895
   444
        {
slouken@1895
   445
            Uint8 *src, *dst;
slouken@1895
   446
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   447
slouken@1895
   448
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   449
            dst = cvt->buf + cvt->len_cvt * 3;
slouken@942
   450
icculus@1982
   451
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   452
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   453
                    dst -= 12;
slouken@1895
   454
                    src -= 4;
slouken@1895
   455
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   456
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   457
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   458
                    rr = lf - ce;
slouken@1895
   459
                    lr = rf - ce;
slouken@1895
   460
                    dst[1] = (lf & 0xFF);
slouken@1895
   461
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   462
                    dst[3] = (rf & 0xFF);
slouken@1895
   463
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   464
slouken@1895
   465
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   466
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   467
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   468
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   469
slouken@1895
   470
                    dst[1 + 8] = (ce & 0xFF);
slouken@1895
   471
                    dst[0 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   472
                    dst[3 + 8] = (ce & 0xFF);
slouken@1895
   473
                    dst[2 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   474
                }
slouken@1895
   475
            } else {
slouken@1895
   476
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   477
                    dst -= 12;
slouken@1895
   478
                    src -= 4;
slouken@1895
   479
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   480
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   481
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   482
                    rr = lf - ce;
slouken@1895
   483
                    lr = rf - ce;
slouken@1895
   484
                    dst[0] = (lf & 0xFF);
slouken@1895
   485
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   486
                    dst[2] = (rf & 0xFF);
slouken@1895
   487
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   488
slouken@1895
   489
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   490
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   491
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   492
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@942
   493
slouken@1895
   494
                    dst[0 + 8] = (ce & 0xFF);
slouken@1895
   495
                    dst[1 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   496
                    dst[2 + 8] = (ce & 0xFF);
slouken@1895
   497
                    dst[3 + 8] = ((ce >> 8) & 0xFF);
slouken@1895
   498
                }
slouken@1895
   499
            }
slouken@1895
   500
        }
slouken@1895
   501
        break;
icculus@1982
   502
icculus@1982
   503
    case AUDIO_S32:
icculus@1982
   504
        {
icculus@1982
   505
            Sint32 lf, rf, ce;
jlegg@8235
   506
            const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
jlegg@8235
   507
            Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 3);
icculus@1982
   508
icculus@1982
   509
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   510
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   511
                    dst -= 6;
icculus@1982
   512
                    src -= 2;
icculus@1982
   513
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   514
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   515
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   516
                    dst[0] = SDL_SwapBE32((Uint32) lf);
icculus@1982
   517
                    dst[1] = SDL_SwapBE32((Uint32) rf);
icculus@1982
   518
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   519
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   520
                    dst[4] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   521
                    dst[5] = SDL_SwapBE32((Uint32) ce);
icculus@1982
   522
                }
icculus@1982
   523
            } else {
icculus@1982
   524
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   525
                    dst -= 6;
icculus@1982
   526
                    src -= 2;
icculus@1982
   527
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   528
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   529
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   530
                    dst[0] = src[0];
icculus@1982
   531
                    dst[1] = src[1];
icculus@1982
   532
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   533
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   534
                    dst[4] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   535
                    dst[5] = SDL_SwapLE32((Uint32) ce);
icculus@1982
   536
                }
icculus@1982
   537
            }
icculus@1982
   538
        }
icculus@1982
   539
        break;
icculus@1982
   540
icculus@1982
   541
    case AUDIO_F32:
icculus@1982
   542
        {
icculus@1982
   543
            float lf, rf, ce;
jlegg@8235
   544
            const float *src = (const float *) (cvt->buf + cvt->len_cvt);
jlegg@8235
   545
            float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
icculus@1982
   546
icculus@1982
   547
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   548
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   549
                    dst -= 6;
icculus@1982
   550
                    src -= 2;
icculus@2014
   551
                    lf = SDL_SwapFloatBE(src[0]);
icculus@2014
   552
                    rf = SDL_SwapFloatBE(src[1]);
icculus@1982
   553
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   554
                    dst[0] = src[0];
icculus@1982
   555
                    dst[1] = src[1];
icculus@2014
   556
                    dst[2] = SDL_SwapFloatBE(lf - ce);
icculus@2014
   557
                    dst[3] = SDL_SwapFloatBE(rf - ce);
icculus@2014
   558
                    dst[4] = dst[5] = SDL_SwapFloatBE(ce);
icculus@1982
   559
                }
icculus@1982
   560
            } else {
icculus@1982
   561
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   562
                    dst -= 6;
icculus@1982
   563
                    src -= 2;
icculus@2014
   564
                    lf = SDL_SwapFloatLE(src[0]);
icculus@2014
   565
                    rf = SDL_SwapFloatLE(src[1]);
icculus@1982
   566
                    ce = (lf * 0.5f) + (rf * 0.5f);
icculus@1982
   567
                    dst[0] = src[0];
icculus@1982
   568
                    dst[1] = src[1];
icculus@2014
   569
                    dst[2] = SDL_SwapFloatLE(lf - ce);
icculus@2014
   570
                    dst[3] = SDL_SwapFloatLE(rf - ce);
icculus@2014
   571
                    dst[4] = dst[5] = SDL_SwapFloatLE(ce);
icculus@1982
   572
                }
icculus@1982
   573
            }
icculus@1982
   574
        }
icculus@1982
   575
        break;
icculus@1982
   576
slouken@1895
   577
    }
slouken@1895
   578
    cvt->len_cvt *= 3;
slouken@1895
   579
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   580
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   581
    }
slouken@942
   582
}
slouken@942
   583
slouken@942
   584
slouken@942
   585
/* Duplicate a stereo channel to a pseudo-4.0 stream */
icculus@1982
   586
static void SDLCALL
icculus@1982
   587
SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
slouken@942
   588
{
slouken@1895
   589
    int i;
slouken@942
   590
slouken@942
   591
#ifdef DEBUG_CONVERT
slouken@1895
   592
    fprintf(stderr, "Converting stereo to quad\n");
slouken@942
   593
#endif
slouken@942
   594
jlegg@8235
   595
    switch (format & (SDL_AUDIO_MASK_SIGNED |
jlegg@8235
   596
                      SDL_AUDIO_MASK_BITSIZE |
jlegg@8235
   597
                      SDL_AUDIO_MASK_DATATYPE)) {
slouken@1895
   598
    case AUDIO_U8:
slouken@1895
   599
        {
slouken@1895
   600
            Uint8 *src, *dst, lf, rf, ce;
slouken@942
   601
slouken@1895
   602
            src = (Uint8 *) (cvt->buf + cvt->len_cvt);
slouken@1895
   603
            dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 2);
slouken@1895
   604
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   605
                dst -= 4;
slouken@1895
   606
                src -= 2;
slouken@1895
   607
                lf = src[0];
slouken@1895
   608
                rf = src[1];
slouken@1895
   609
                ce = (lf / 2) + (rf / 2);
slouken@1895
   610
                dst[0] = lf;
slouken@1895
   611
                dst[1] = rf;
slouken@1895
   612
                dst[2] = lf - ce;
slouken@1895
   613
                dst[3] = rf - ce;
slouken@1895
   614
            }
slouken@1895
   615
        }
slouken@1895
   616
        break;
slouken@942
   617
slouken@1895
   618
    case AUDIO_S8:
slouken@1895
   619
        {
slouken@1895
   620
            Sint8 *src, *dst, lf, rf, ce;
slouken@942
   621
slouken@1895
   622
            src = (Sint8 *) cvt->buf + cvt->len_cvt;
slouken@1895
   623
            dst = (Sint8 *) cvt->buf + cvt->len_cvt * 2;
slouken@1895
   624
            for (i = cvt->len_cvt; i; --i) {
slouken@1895
   625
                dst -= 4;
slouken@1895
   626
                src -= 2;
slouken@1895
   627
                lf = src[0];
slouken@1895
   628
                rf = src[1];
slouken@1895
   629
                ce = (lf / 2) + (rf / 2);
slouken@1895
   630
                dst[0] = lf;
slouken@1895
   631
                dst[1] = rf;
slouken@1895
   632
                dst[2] = lf - ce;
slouken@1895
   633
                dst[3] = rf - ce;
slouken@1895
   634
            }
slouken@1895
   635
        }
slouken@1895
   636
        break;
slouken@942
   637
slouken@1895
   638
    case AUDIO_U16:
slouken@1895
   639
        {
slouken@1895
   640
            Uint8 *src, *dst;
slouken@1895
   641
            Uint16 lf, rf, ce, lr, rr;
slouken@942
   642
slouken@1895
   643
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   644
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   645
icculus@1982
   646
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   647
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   648
                    dst -= 8;
slouken@1895
   649
                    src -= 4;
slouken@1895
   650
                    lf = (Uint16) ((src[0] << 8) | src[1]);
slouken@1895
   651
                    rf = (Uint16) ((src[2] << 8) | src[3]);
slouken@1895
   652
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   653
                    rr = lf - ce;
slouken@1895
   654
                    lr = rf - ce;
slouken@1895
   655
                    dst[1] = (lf & 0xFF);
slouken@1895
   656
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   657
                    dst[3] = (rf & 0xFF);
slouken@1895
   658
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   659
slouken@1895
   660
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   661
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   662
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   663
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   664
                }
slouken@1895
   665
            } else {
slouken@1895
   666
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   667
                    dst -= 8;
slouken@1895
   668
                    src -= 4;
slouken@1895
   669
                    lf = (Uint16) ((src[1] << 8) | src[0]);
slouken@1895
   670
                    rf = (Uint16) ((src[3] << 8) | src[2]);
slouken@1895
   671
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   672
                    rr = lf - ce;
slouken@1895
   673
                    lr = rf - ce;
slouken@1895
   674
                    dst[0] = (lf & 0xFF);
slouken@1895
   675
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   676
                    dst[2] = (rf & 0xFF);
slouken@1895
   677
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   678
slouken@1895
   679
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   680
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   681
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   682
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   683
                }
slouken@1895
   684
            }
slouken@1895
   685
        }
slouken@1895
   686
        break;
slouken@942
   687
slouken@1895
   688
    case AUDIO_S16:
slouken@1895
   689
        {
slouken@1895
   690
            Uint8 *src, *dst;
slouken@1895
   691
            Sint16 lf, rf, ce, lr, rr;
slouken@942
   692
slouken@1895
   693
            src = cvt->buf + cvt->len_cvt;
slouken@1895
   694
            dst = cvt->buf + cvt->len_cvt * 2;
slouken@942
   695
icculus@1982
   696
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
slouken@1895
   697
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   698
                    dst -= 8;
slouken@1895
   699
                    src -= 4;
slouken@1895
   700
                    lf = (Sint16) ((src[0] << 8) | src[1]);
slouken@1895
   701
                    rf = (Sint16) ((src[2] << 8) | src[3]);
slouken@1895
   702
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   703
                    rr = lf - ce;
slouken@1895
   704
                    lr = rf - ce;
slouken@1895
   705
                    dst[1] = (lf & 0xFF);
slouken@1895
   706
                    dst[0] = ((lf >> 8) & 0xFF);
slouken@1895
   707
                    dst[3] = (rf & 0xFF);
slouken@1895
   708
                    dst[2] = ((rf >> 8) & 0xFF);
slouken@942
   709
slouken@1895
   710
                    dst[1 + 4] = (lr & 0xFF);
slouken@1895
   711
                    dst[0 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   712
                    dst[3 + 4] = (rr & 0xFF);
slouken@1895
   713
                    dst[2 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   714
                }
slouken@1895
   715
            } else {
slouken@1895
   716
                for (i = cvt->len_cvt / 4; i; --i) {
slouken@1895
   717
                    dst -= 8;
slouken@1895
   718
                    src -= 4;
slouken@1895
   719
                    lf = (Sint16) ((src[1] << 8) | src[0]);
slouken@1895
   720
                    rf = (Sint16) ((src[3] << 8) | src[2]);
slouken@1895
   721
                    ce = (lf / 2) + (rf / 2);
slouken@1895
   722
                    rr = lf - ce;
slouken@1895
   723
                    lr = rf - ce;
slouken@1895
   724
                    dst[0] = (lf & 0xFF);
slouken@1895
   725
                    dst[1] = ((lf >> 8) & 0xFF);
slouken@1895
   726
                    dst[2] = (rf & 0xFF);
slouken@1895
   727
                    dst[3] = ((rf >> 8) & 0xFF);
slouken@942
   728
slouken@1895
   729
                    dst[0 + 4] = (lr & 0xFF);
slouken@1895
   730
                    dst[1 + 4] = ((lr >> 8) & 0xFF);
slouken@1895
   731
                    dst[2 + 4] = (rr & 0xFF);
slouken@1895
   732
                    dst[3 + 4] = ((rr >> 8) & 0xFF);
slouken@1895
   733
                }
slouken@1895
   734
            }
slouken@1895
   735
        }
slouken@1895
   736
        break;
slouken@942
   737
icculus@1982
   738
    case AUDIO_S32:
icculus@1982
   739
        {
icculus@1982
   740
            const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
icculus@1982
   741
            Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 2);
icculus@1982
   742
            Sint32 lf, rf, ce;
slouken@942
   743
icculus@1982
   744
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
icculus@1982
   745
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   746
                    dst -= 4;
icculus@1982
   747
                    src -= 2;
icculus@1982
   748
                    lf = (Sint32) SDL_SwapBE32(src[0]);
icculus@1982
   749
                    rf = (Sint32) SDL_SwapBE32(src[1]);
icculus@1982
   750
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   751
                    dst[0] = src[0];
icculus@1982
   752
                    dst[1] = src[1];
icculus@1982
   753
                    dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
icculus@1982
   754
                    dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
icculus@1982
   755
                }
icculus@1982
   756
            } else {
icculus@1982
   757
                for (i = cvt->len_cvt / 8; i; --i) {
icculus@1982
   758
                    dst -= 4;
icculus@1982
   759
                    src -= 2;
icculus@1982
   760
                    lf = (Sint32) SDL_SwapLE32(src[0]);
icculus@1982
   761
                    rf = (Sint32) SDL_SwapLE32(src[1]);
icculus@1982
   762
                    ce = (lf / 2) + (rf / 2);
icculus@1982
   763
                    dst[0] = src[0];
icculus@1982
   764
                    dst[1] = src[1];
icculus@1982
   765
                    dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
icculus@1982
   766
                    dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
icculus@1982
   767
                }
icculus@1982
   768
            }
slouken@1895
   769
        }
slouken@1895
   770
        break;
jlegg@8235
   771
jlegg@8235
   772
    case AUDIO_F32:
jlegg@8235
   773
        {
jlegg@8235
   774
            const float *src = (const float *) (cvt->buf + cvt->len_cvt);
jlegg@8235
   775
            float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
jlegg@8235
   776
            float lf, rf, ce;
jlegg@8235
   777
jlegg@8235
   778
            if (SDL_AUDIO_ISBIGENDIAN(format)) {
jlegg@8235
   779
                for (i = cvt->len_cvt / 8; i; --i) {
jlegg@8235
   780
                    dst -= 4;
jlegg@8235
   781
                    src -= 2;
jlegg@8235
   782
                    lf = SDL_SwapFloatBE(src[0]);
jlegg@8235
   783
                    rf = SDL_SwapFloatBE(src[1]);
jlegg@8235
   784
                    ce = (lf / 2) + (rf / 2);
jlegg@8235
   785
                    dst[0] = src[0];
jlegg@8235
   786
                    dst[1] = src[1];
jlegg@8235
   787
                    dst[2] = SDL_SwapFloatBE(lf - ce);
jlegg@8235
   788
                    dst[3] = SDL_SwapFloatBE(rf - ce);
jlegg@8235
   789
                }
jlegg@8235
   790
            } else {
jlegg@8235
   791
                for (i = cvt->len_cvt / 8; i; --i) {
jlegg@8235
   792
                    dst -= 4;
jlegg@8235
   793
                    src -= 2;
jlegg@8235
   794
                    lf = SDL_SwapFloatLE(src[0]);
jlegg@8235
   795
                    rf = SDL_SwapFloatLE(src[1]);
jlegg@8235
   796
                    ce = (lf / 2) + (rf / 2);
jlegg@8235
   797
                    dst[0] = src[0];
jlegg@8235
   798
                    dst[1] = src[1];
jlegg@8235
   799
                    dst[2] = SDL_SwapFloatLE(lf - ce);
jlegg@8235
   800
                    dst[3] = SDL_SwapFloatLE(rf - ce);
jlegg@8235
   801
                }
jlegg@8235
   802
            }
jlegg@8235
   803
        }
jlegg@8235
   804
        break;
slouken@1895
   805
    }
slouken@1895
   806
    cvt->len_cvt *= 2;
slouken@1895
   807
    if (cvt->filters[++cvt->filter_index]) {
slouken@1895
   808
        cvt->filters[cvt->filter_index] (cvt, format);
slouken@1895
   809
    }
slouken@0
   810
}
slouken@0
   811
slouken@0
   812
slouken@1895
   813
int
slouken@1895
   814
SDL_ConvertAudio(SDL_AudioCVT * cvt)
slouken@0
   815
{
icculus@3021
   816
    /* !!! FIXME: (cvt) should be const; stack-copy it here. */
icculus@3021
   817
    /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
icculus@3021
   818
slouken@1895
   819
    /* Make sure there's data to convert */
slouken@1895
   820
    if (cvt->buf == NULL) {
slouken@1895
   821
        SDL_SetError("No buffer allocated for conversion");
slouken@1895
   822
        return (-1);
slouken@1895
   823
    }
slouken@1895
   824
    /* Return okay if no conversion is necessary */
slouken@1895
   825
    cvt->len_cvt = cvt->len;
slouken@1895
   826
    if (cvt->filters[0] == NULL) {
slouken@1895
   827
        return (0);
slouken@1895
   828
    }
slouken@0
   829
slouken@1895
   830
    /* Set up the conversion and go! */
slouken@1895
   831
    cvt->filter_index = 0;
slouken@1895
   832
    cvt->filters[0] (cvt, cvt->src_format);
slouken@1895
   833
    return (0);
slouken@0
   834
}
slouken@0
   835
icculus@1982
   836
icculus@1982
   837
static SDL_AudioFilter
icculus@1982
   838
SDL_HandTunedTypeCVT(SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
   839
{
icculus@1982
   840
    /*
icculus@1982
   841
     * Fill in any future conversions that are specialized to a
icculus@1982
   842
     *  processor, platform, compiler, or library here.
icculus@1982
   843
     */
icculus@1982
   844
slouken@1985
   845
    return NULL;                /* no specialized converter code available. */
icculus@1982
   846
}
icculus@1982
   847
icculus@1982
   848
icculus@1982
   849
/*
icculus@1982
   850
 * Find a converter between two data types. We try to select a hand-tuned
icculus@1982
   851
 *  asm/vectorized/optimized function first, and then fallback to an
icculus@1982
   852
 *  autogenerated function that is customized to convert between two
icculus@1982
   853
 *  specific data types.
icculus@1982
   854
 */
icculus@1982
   855
static int
icculus@1982
   856
SDL_BuildAudioTypeCVT(SDL_AudioCVT * cvt,
icculus@1982
   857
                      SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
icculus@1982
   858
{
icculus@1982
   859
    if (src_fmt != dst_fmt) {
icculus@1982
   860
        const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
icculus@1982
   861
        const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
icculus@1982
   862
        SDL_AudioFilter filter = SDL_HandTunedTypeCVT(src_fmt, dst_fmt);
icculus@1982
   863
icculus@1982
   864
        /* No hand-tuned converter? Try the autogenerated ones. */
icculus@1982
   865
        if (filter == NULL) {
icculus@1982
   866
            int i;
icculus@1982
   867
            for (i = 0; sdl_audio_type_filters[i].filter != NULL; i++) {
icculus@1982
   868
                const SDL_AudioTypeFilters *filt = &sdl_audio_type_filters[i];
icculus@1982
   869
                if ((filt->src_fmt == src_fmt) && (filt->dst_fmt == dst_fmt)) {
icculus@1982
   870
                    filter = filt->filter;
icculus@1982
   871
                    break;
icculus@1982
   872
                }
icculus@1982
   873
            }
icculus@1982
   874
icculus@1982
   875
            if (filter == NULL) {
slouken@3491
   876
                SDL_SetError("No conversion available for these formats");
slouken@3491
   877
                return -1;
icculus@1982
   878
            }
icculus@1982
   879
        }
icculus@1982
   880
icculus@1982
   881
        /* Update (cvt) with filter details... */
icculus@1982
   882
        cvt->filters[cvt->filter_index++] = filter;
icculus@1982
   883
        if (src_bitsize < dst_bitsize) {
icculus@1982
   884
            const int mult = (dst_bitsize / src_bitsize);
icculus@1982
   885
            cvt->len_mult *= mult;
icculus@1982
   886
            cvt->len_ratio *= mult;
icculus@1982
   887
        } else if (src_bitsize > dst_bitsize) {
icculus@1982
   888
            cvt->len_ratio /= (src_bitsize / dst_bitsize);
icculus@1982
   889
        }
icculus@1982
   890
slouken@1985
   891
        return 1;               /* added a converter. */
icculus@1982
   892
    }
icculus@1982
   893
slouken@1985
   894
    return 0;                   /* no conversion necessary. */
icculus@1982
   895
}
icculus@1982
   896
icculus@3021
   897
icculus@3021
   898
static SDL_AudioFilter
icculus@3021
   899
SDL_HandTunedResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
icculus@3021
   900
                         int src_rate, int dst_rate)
slouken@2716
   901
{
icculus@3021
   902
    /*
icculus@3021
   903
     * Fill in any future conversions that are specialized to a
icculus@3021
   904
     *  processor, platform, compiler, or library here.
icculus@3021
   905
     */
slouken@2716
   906
icculus@3021
   907
    return NULL;                /* no specialized converter code available. */
icculus@3021
   908
}
slouken@2716
   909
icculus@3021
   910
static int
icculus@3021
   911
SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
icculus@3021
   912
{
icculus@3021
   913
    int retval = 0;
slouken@2716
   914
icculus@3021
   915
    /* If we only built with the arbitrary resamplers, ignore multiples. */
icculus@3021
   916
#if !LESS_RESAMPLERS
icculus@3021
   917
    int lo, hi;
icculus@3021
   918
    int div;
slouken@2716
   919
icculus@6281
   920
    SDL_assert(src_rate != 0);
icculus@6281
   921
    SDL_assert(dst_rate != 0);
icculus@6281
   922
    SDL_assert(src_rate != dst_rate);
slouken@2716
   923
icculus@3021
   924
    if (src_rate < dst_rate) {
icculus@3021
   925
        lo = src_rate;
icculus@3021
   926
        hi = dst_rate;
icculus@3021
   927
    } else {
icculus@3021
   928
        lo = dst_rate;
icculus@3021
   929
        hi = src_rate;
icculus@3021
   930
    }
slouken@2716
   931
icculus@3021
   932
    /* zero means "not a supported multiple" ... we only do 2x and 4x. */
icculus@3021
   933
    if ((hi % lo) != 0)
slouken@3040
   934
        return 0;               /* not a multiple. */
slouken@2716
   935
icculus@3021
   936
    div = hi / lo;
icculus@3021
   937
    retval = ((div == 2) || (div == 4)) ? div : 0;
icculus@3021
   938
#endif
icculus@3021
   939
icculus@3021
   940
    return retval;
icculus@3021
   941
}
icculus@3021
   942
icculus@3021
   943
static int
icculus@3021
   944
SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
icculus@3021
   945
                          int src_rate, int dst_rate)
icculus@3021
   946
{
icculus@3021
   947
    if (src_rate != dst_rate) {
icculus@3021
   948
        SDL_AudioFilter filter = SDL_HandTunedResampleCVT(cvt, dst_channels,
icculus@3021
   949
                                                          src_rate, dst_rate);
icculus@3021
   950
icculus@3021
   951
        /* No hand-tuned converter? Try the autogenerated ones. */
icculus@3021
   952
        if (filter == NULL) {
icculus@3021
   953
            int i;
icculus@3021
   954
            const int upsample = (src_rate < dst_rate) ? 1 : 0;
slouken@3040
   955
            const int multiple =
slouken@3040
   956
                SDL_FindFrequencyMultiple(src_rate, dst_rate);
icculus@3021
   957
icculus@3021
   958
            for (i = 0; sdl_audio_rate_filters[i].filter != NULL; i++) {
icculus@3021
   959
                const SDL_AudioRateFilters *filt = &sdl_audio_rate_filters[i];
icculus@3021
   960
                if ((filt->fmt == cvt->dst_format) &&
icculus@3021
   961
                    (filt->channels == dst_channels) &&
icculus@3021
   962
                    (filt->upsample == upsample) &&
icculus@3021
   963
                    (filt->multiple == multiple)) {
icculus@3021
   964
                    filter = filt->filter;
icculus@3021
   965
                    break;
icculus@3021
   966
                }
icculus@3021
   967
            }
icculus@3021
   968
icculus@3021
   969
            if (filter == NULL) {
slouken@3491
   970
                SDL_SetError("No conversion available for these rates");
slouken@3491
   971
                return -1;
icculus@3021
   972
            }
slouken@2716
   973
        }
slouken@2716
   974
icculus@3021
   975
        /* Update (cvt) with filter details... */
icculus@3021
   976
        cvt->filters[cvt->filter_index++] = filter;
icculus@3021
   977
        if (src_rate < dst_rate) {
icculus@3021
   978
            const double mult = ((double) dst_rate) / ((double) src_rate);
slouken@3032
   979
            cvt->len_mult *= (int) SDL_ceil(mult);
icculus@3021
   980
            cvt->len_ratio *= mult;
icculus@3021
   981
        } else {
icculus@3021
   982
            cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
slouken@2716
   983
        }
icculus@3021
   984
icculus@3021
   985
        return 1;               /* added a converter. */
slouken@2716
   986
    }
slouken@2716
   987
icculus@3021
   988
    return 0;                   /* no conversion necessary. */
slouken@2716
   989
}
icculus@1982
   990
icculus@1982
   991
icculus@1982
   992
/* Creates a set of audio filters to convert from one format to another.
icculus@1982
   993
   Returns -1 if the format conversion is not supported, 0 if there's
icculus@1982
   994
   no conversion needed, or 1 if the audio filter is set up.
slouken@0
   995
*/
slouken@1895
   996
slouken@1895
   997
int
slouken@1895
   998
SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
icculus@1982
   999
                  SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
icculus@1982
  1000
                  SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
slouken@0
  1001
{
icculus@3021
  1002
    /*
icculus@3021
  1003
     * !!! FIXME: reorder filters based on which grow/shrink the buffer.
icculus@3021
  1004
     * !!! FIXME: ideally, we should do everything that shrinks the buffer
icculus@3021
  1005
     * !!! FIXME: first, so we don't have to process as many bytes in a given
icculus@3021
  1006
     * !!! FIXME: filter and abuse the CPU cache less. This might not be as
icculus@3021
  1007
     * !!! FIXME: good in practice as it sounds in theory, though.
icculus@3021
  1008
     */
icculus@3021
  1009
aschiffler@6819
  1010
    /* Sanity check target pointer */
aschiffler@6819
  1011
    if (cvt == NULL) {
icculus@7037
  1012
        return SDL_InvalidParamError("cvt");
aschiffler@6819
  1013
    }
slouken@7191
  1014
slouken@3491
  1015
    /* there are no unsigned types over 16 bits, so catch this up front. */
icculus@1982
  1016
    if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
icculus@7037
  1017
        return SDL_SetError("Invalid source format");
icculus@1982
  1018
    }
icculus@1982
  1019
    if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
icculus@7037
  1020
        return SDL_SetError("Invalid destination format");
icculus@1982
  1021
    }
icculus@3021
  1022
icculus@3021
  1023
    /* prevent possible divisions by zero, etc. */
aschiffler@6819
  1024
    if ((src_channels == 0) || (dst_channels == 0)) {
icculus@7037
  1025
        return SDL_SetError("Source or destination channels is zero");
aschiffler@6819
  1026
    }
icculus@3021
  1027
    if ((src_rate == 0) || (dst_rate == 0)) {
icculus@7037
  1028
        return SDL_SetError("Source or destination rate is zero");
icculus@3021
  1029
    }
slouken@1985
  1030
#ifdef DEBUG_CONVERT
icculus@1982
  1031
    printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
slouken@1985
  1032
           src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
slouken@1985
  1033
#endif
icculus@1982
  1034
slouken@1895
  1035
    /* Start off with no conversion necessary */
icculus@2879
  1036
    SDL_zerop(cvt);
icculus@1982
  1037
    cvt->src_format = src_fmt;
icculus@1982
  1038
    cvt->dst_format = dst_fmt;
slouken@1895
  1039
    cvt->needed = 0;
slouken@1895
  1040
    cvt->filter_index = 0;
slouken@1895
  1041
    cvt->filters[0] = NULL;
slouken@1895
  1042
    cvt->len_mult = 1;
slouken@1895
  1043
    cvt->len_ratio = 1.0;
icculus@3021
  1044
    cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
slouken@0
  1045
icculus@1982
  1046
    /* Convert data types, if necessary. Updates (cvt). */
icculus@3021
  1047
    if (SDL_BuildAudioTypeCVT(cvt, src_fmt, dst_fmt) == -1) {
slouken@1985
  1048
        return -1;              /* shouldn't happen, but just in case... */
icculus@3021
  1049
    }
slouken@0
  1050
icculus@1982
  1051
    /* Channel conversion */
slouken@1895
  1052
    if (src_channels != dst_channels) {
slouken@1895
  1053
        if ((src_channels == 1) && (dst_channels > 1)) {
slouken@1895
  1054
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1055
            cvt->len_mult *= 2;
slouken@1895
  1056
            src_channels = 2;
slouken@1895
  1057
            cvt->len_ratio *= 2;
slouken@1895
  1058
        }
slouken@1895
  1059
        if ((src_channels == 2) && (dst_channels == 6)) {
slouken@1895
  1060
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
slouken@1895
  1061
            src_channels = 6;
slouken@1895
  1062
            cvt->len_mult *= 3;
slouken@1895
  1063
            cvt->len_ratio *= 3;
slouken@1895
  1064
        }
slouken@1895
  1065
        if ((src_channels == 2) && (dst_channels == 4)) {
slouken@1895
  1066
            cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
slouken@1895
  1067
            src_channels = 4;
slouken@1895
  1068
            cvt->len_mult *= 2;
slouken@1895
  1069
            cvt->len_ratio *= 2;
slouken@1895
  1070
        }
slouken@1895
  1071
        while ((src_channels * 2) <= dst_channels) {
slouken@1895
  1072
            cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
slouken@1895
  1073
            cvt->len_mult *= 2;
slouken@1895
  1074
            src_channels *= 2;
slouken@1895
  1075
            cvt->len_ratio *= 2;
slouken@1895
  1076
        }
slouken@1895
  1077
        if ((src_channels == 6) && (dst_channels <= 2)) {
slouken@1895
  1078
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
slouken@1895
  1079
            src_channels = 2;
slouken@1895
  1080
            cvt->len_ratio /= 3;
slouken@1895
  1081
        }
slouken@1895
  1082
        if ((src_channels == 6) && (dst_channels == 4)) {
slouken@1895
  1083
            cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
slouken@1895
  1084
            src_channels = 4;
slouken@1895
  1085
            cvt->len_ratio /= 2;
slouken@1895
  1086
        }
slouken@1895
  1087
        /* This assumes that 4 channel audio is in the format:
slouken@1895
  1088
           Left {front/back} + Right {front/back}
slouken@1895
  1089
           so converting to L/R stereo works properly.
slouken@1895
  1090
         */
slouken@1895
  1091
        while (((src_channels % 2) == 0) &&
slouken@1895
  1092
               ((src_channels / 2) >= dst_channels)) {
slouken@1895
  1093
            cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
slouken@1895
  1094
            src_channels /= 2;
slouken@1895
  1095
            cvt->len_ratio /= 2;
slouken@1895
  1096
        }
slouken@1895
  1097
        if (src_channels != dst_channels) {
slouken@1895
  1098
            /* Uh oh.. */ ;
slouken@1895
  1099
        }
slouken@1895
  1100
    }
slouken@0
  1101
icculus@3021
  1102
    /* Do rate conversion, if necessary. Updates (cvt). */
slouken@3040
  1103
    if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) ==
slouken@3040
  1104
        -1) {
icculus@3021
  1105
        return -1;              /* shouldn't happen, but just in case... */
slouken@2716
  1106
    }
slouken@2716
  1107
slouken@1895
  1108
    /* Set up the filter information */
slouken@1895
  1109
    if (cvt->filter_index != 0) {
slouken@1895
  1110
        cvt->needed = 1;
icculus@1982
  1111
        cvt->src_format = src_fmt;
icculus@1982
  1112
        cvt->dst_format = dst_fmt;
slouken@1895
  1113
        cvt->len = 0;
slouken@1895
  1114
        cvt->buf = NULL;
slouken@1895
  1115
        cvt->filters[cvt->filter_index] = NULL;
slouken@1895
  1116
    }
slouken@1895
  1117
    return (cvt->needed);
slouken@0
  1118
}
slouken@1895
  1119
slouken@2716
  1120
slouken@1895
  1121
/* vi: set ts=4 sw=4 expandtab: */