audio_convert.c
author Ozkan Sezer <sezero@users.sourceforge.net>
Wed, 24 May 2017 11:28:05 -0400
changeset 599 f0d57c9b72d8
parent 483 9e761a594df1
permissions -rw-r--r--
timidity.c: fix potential buffer overrun in RWgets

(num_read check was off-by-one.) also simplify the procedure a bit.
(transplanted from 0c4026dd32742e8b7d33fb96d40fe3c03b02f90c)
icculus@141
     1
/*
icculus@141
     2
    SDL - Simple DirectMedia Layer
icculus@141
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
icculus@141
     4
icculus@141
     5
    This library is free software; you can redistribute it and/or
icculus@141
     6
    modify it under the terms of the GNU Library General Public
icculus@141
     7
    License as published by the Free Software Foundation; either
icculus@141
     8
    version 2 of the License, or (at your option) any later version.
icculus@141
     9
icculus@141
    10
    This library is distributed in the hope that it will be useful,
icculus@141
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
icculus@141
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
icculus@141
    13
    Library General Public License for more details.
icculus@141
    14
icculus@141
    15
    You should have received a copy of the GNU Library General Public
icculus@141
    16
    License along with this library; if not, write to the Free
icculus@141
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
icculus@141
    18
icculus@141
    19
    Sam Lantinga
icculus@141
    20
    slouken@devolution.com
icculus@141
    21
*/
icculus@141
    22
icculus@141
    23
/*
icculus@141
    24
 * This file was derived from SDL's SDL_audiocvt.c and is an attempt to
icculus@141
    25
 * address the shortcomings of it.
icculus@141
    26
 *
icculus@141
    27
 * Perhaps we can adapt some good filters from SoX?
icculus@141
    28
 */
icculus@141
    29
icculus@141
    30
#if HAVE_CONFIG_H
icculus@141
    31
#  include <config.h>
icculus@141
    32
#endif
icculus@141
    33
icculus@141
    34
#include "SDL.h"
icculus@141
    35
#include "SDL_sound.h"
icculus@141
    36
icculus@141
    37
#define __SDL_SOUND_INTERNAL__
icculus@141
    38
#include "SDL_sound_internal.h"
icculus@141
    39
icculus@141
    40
/* Functions for audio drivers to perform runtime conversion of audio format */
icculus@141
    41
icculus@141
    42
icculus@141
    43
/*
icculus@141
    44
 * Toggle endianness. This filter is, of course, only applied to 16-bit
icculus@141
    45
 * audio data.
icculus@141
    46
 */
icculus@141
    47
icculus@342
    48
static void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
    49
{
icculus@141
    50
    int i;
icculus@141
    51
    Uint8 *data, tmp;
icculus@141
    52
icculus@141
    53
    /* SNDDBG(("Converting audio endianness\n")); */
icculus@141
    54
icculus@141
    55
    data = cvt->buf;
icculus@141
    56
icculus@141
    57
    for (i = cvt->len_cvt / 2; i; --i)
icculus@141
    58
    {
icculus@141
    59
        tmp = data[0];
icculus@141
    60
        data[0] = data[1];
icculus@141
    61
        data[1] = tmp;
icculus@141
    62
        data += 2;
icculus@141
    63
    } /* for */
icculus@141
    64
icculus@141
    65
    *format = (*format ^ 0x1000);
icculus@141
    66
} /* Sound_ConvertEndian */
icculus@141
    67
icculus@141
    68
icculus@141
    69
/*
icculus@141
    70
 * Toggle signed/unsigned. Apparently this is done by toggling the most
icculus@141
    71
 * significant bit of each sample.
icculus@141
    72
 */
icculus@141
    73
icculus@342
    74
static void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
    75
{
icculus@141
    76
    int i;
icculus@141
    77
    Uint8 *data;
icculus@141
    78
icculus@141
    79
    /* SNDDBG(("Converting audio signedness\n")); */
icculus@141
    80
icculus@141
    81
    data = cvt->buf;
icculus@141
    82
icculus@141
    83
        /* 16-bit sound? */
icculus@141
    84
    if ((*format & 0xFF) == 16)
icculus@141
    85
    {
icculus@141
    86
            /* Little-endian? */
icculus@141
    87
        if ((*format & 0x1000) != 0x1000)
icculus@141
    88
            ++data;
icculus@141
    89
icculus@141
    90
        for (i = cvt->len_cvt / 2; i; --i)
icculus@141
    91
        {
icculus@141
    92
            *data ^= 0x80;
icculus@141
    93
            data += 2;
icculus@141
    94
        } /* for */
icculus@141
    95
    } /* if */
icculus@141
    96
    else
icculus@141
    97
    {
icculus@141
    98
        for (i = cvt->len_cvt; i; --i)
icculus@141
    99
            *data++ ^= 0x80;
icculus@141
   100
    } /* else */
icculus@141
   101
icculus@141
   102
    *format = (*format ^ 0x8000);
icculus@141
   103
} /* Sound_ConvertSign */
icculus@141
   104
icculus@141
   105
icculus@141
   106
/*
icculus@141
   107
 * Convert 16-bit to 8-bit. This is done by taking the most significant byte
icculus@141
   108
 * of each 16-bit sample.
icculus@141
   109
 */
icculus@141
   110
icculus@342
   111
static void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   112
{
icculus@141
   113
    int i;
icculus@141
   114
    Uint8 *src, *dst;
icculus@141
   115
icculus@141
   116
    /* SNDDBG(("Converting to 8-bit\n")); */
icculus@141
   117
icculus@141
   118
    src = cvt->buf;
icculus@141
   119
    dst = cvt->buf;
icculus@141
   120
icculus@141
   121
        /* Little-endian? */
icculus@141
   122
    if ((*format & 0x1000) != 0x1000)
icculus@141
   123
        ++src;
icculus@141
   124
icculus@141
   125
    for (i = cvt->len_cvt / 2; i; --i)
icculus@141
   126
    {
icculus@141
   127
        *dst = *src;
icculus@141
   128
        src += 2;
icculus@141
   129
        dst += 1;
icculus@141
   130
    } /* for */
icculus@141
   131
icculus@141
   132
    *format = ((*format & ~0x9010) | AUDIO_U8);
icculus@141
   133
    cvt->len_cvt /= 2;
icculus@141
   134
} /* Sound_Convert8 */
icculus@141
   135
icculus@141
   136
icculus@141
   137
/* Convert 8-bit to 16-bit - LSB */
icculus@141
   138
icculus@342
   139
static void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   140
{
icculus@141
   141
    int i;
icculus@141
   142
    Uint8 *src, *dst;
icculus@141
   143
icculus@141
   144
    /* SNDDBG(("Converting to 16-bit LSB\n")); */
icculus@141
   145
icculus@141
   146
    src = cvt->buf + cvt->len_cvt;
icculus@141
   147
    dst = cvt->buf + cvt->len_cvt * 2;
icculus@141
   148
icculus@141
   149
    for (i = cvt->len_cvt; i; --i)
icculus@141
   150
    {
icculus@141
   151
        src -= 1;
icculus@141
   152
        dst -= 2;
icculus@141
   153
        dst[1] = *src;
icculus@141
   154
        dst[0] = 0;
icculus@141
   155
    } /* for */
icculus@141
   156
icculus@141
   157
    *format = ((*format & ~0x0008) | AUDIO_U16LSB);
icculus@141
   158
    cvt->len_cvt *= 2;
icculus@141
   159
} /* Sound_Convert16LSB */
icculus@141
   160
icculus@141
   161
icculus@141
   162
/* Convert 8-bit to 16-bit - MSB */
icculus@141
   163
icculus@342
   164
static void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   165
{
icculus@141
   166
    int i;
icculus@141
   167
    Uint8 *src, *dst;
icculus@141
   168
icculus@141
   169
    /* SNDDBG(("Converting to 16-bit MSB\n")); */
icculus@141
   170
icculus@141
   171
    src = cvt->buf + cvt->len_cvt;
icculus@141
   172
    dst = cvt->buf + cvt->len_cvt * 2;
icculus@141
   173
icculus@141
   174
    for (i = cvt->len_cvt; i; --i)
icculus@141
   175
    {
icculus@141
   176
        src -= 1;
icculus@141
   177
        dst -= 2;
icculus@141
   178
        dst[0] = *src;
icculus@141
   179
        dst[1] = 0;
icculus@141
   180
    } /* for */
icculus@141
   181
icculus@141
   182
    *format = ((*format & ~0x0008) | AUDIO_U16MSB);
icculus@141
   183
    cvt->len_cvt *= 2;
icculus@141
   184
} /* Sound_Convert16MSB */
icculus@141
   185
icculus@141
   186
icculus@141
   187
/* Duplicate a mono channel to both stereo channels */
icculus@141
   188
icculus@342
   189
static void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   190
{
icculus@141
   191
    int i;
icculus@141
   192
icculus@141
   193
    /* SNDDBG(("Converting to stereo\n")); */
icculus@141
   194
icculus@141
   195
        /* 16-bit sound? */
icculus@141
   196
    if ((*format & 0xFF) == 16)
icculus@141
   197
    {
icculus@141
   198
        Uint16 *src, *dst;
icculus@141
   199
icculus@141
   200
        src = (Uint16 *) (cvt->buf + cvt->len_cvt);
icculus@141
   201
        dst = (Uint16 *) (cvt->buf + cvt->len_cvt * 2);
icculus@141
   202
icculus@141
   203
        for (i = cvt->len_cvt/2; i; --i)
icculus@141
   204
        {
icculus@141
   205
            dst -= 2;
icculus@141
   206
            src -= 1;
icculus@141
   207
            dst[0] = src[0];
icculus@141
   208
            dst[1] = src[0];
icculus@141
   209
        } /* for */
icculus@141
   210
    } /* if */
icculus@141
   211
    else
icculus@141
   212
    {
icculus@141
   213
        Uint8 *src, *dst;
icculus@141
   214
icculus@141
   215
        src = cvt->buf + cvt->len_cvt;
icculus@141
   216
        dst = cvt->buf + cvt->len_cvt * 2;
icculus@141
   217
icculus@141
   218
        for (i = cvt->len_cvt; i; --i)
icculus@141
   219
        {
icculus@141
   220
            dst -= 2;
icculus@141
   221
            src -= 1;
icculus@141
   222
            dst[0] = src[0];
icculus@141
   223
            dst[1] = src[0];
icculus@141
   224
        } /* for */
icculus@141
   225
    } /* else */
icculus@141
   226
icculus@141
   227
    cvt->len_cvt *= 2;
icculus@141
   228
} /* Sound_ConvertStereo */
icculus@141
   229
icculus@141
   230
icculus@141
   231
/* Effectively mix right and left channels into a single channel */
icculus@141
   232
icculus@342
   233
static void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   234
{
icculus@141
   235
    int i;
icculus@141
   236
    Sint32 sample;
icculus@141
   237
    Uint8 *u_src, *u_dst;
icculus@141
   238
    Sint8 *s_src, *s_dst;
icculus@141
   239
icculus@141
   240
    /* SNDDBG(("Converting to mono\n")); */
icculus@141
   241
icculus@141
   242
    switch (*format)
icculus@141
   243
    {
icculus@141
   244
        case AUDIO_U8:
icculus@141
   245
            u_src = cvt->buf;
icculus@141
   246
            u_dst = cvt->buf;
icculus@141
   247
icculus@141
   248
            for (i = cvt->len_cvt / 2; i; --i)
icculus@141
   249
            {
icculus@141
   250
                sample = u_src[0] + u_src[1];
icculus@141
   251
                *u_dst = (sample > 255) ? 255 : sample;
icculus@141
   252
                u_src += 2;
icculus@141
   253
                u_dst += 1;
icculus@141
   254
            } /* for */
icculus@141
   255
            break;
icculus@141
   256
icculus@141
   257
        case AUDIO_S8:
icculus@141
   258
            s_src = (Sint8 *) cvt->buf;
icculus@141
   259
            s_dst = (Sint8 *) cvt->buf;
icculus@141
   260
icculus@141
   261
            for (i = cvt->len_cvt / 2; i; --i)
icculus@141
   262
            {
icculus@141
   263
                sample = s_src[0] + s_src[1];
icculus@141
   264
                if (sample > 127)
icculus@141
   265
                    *s_dst = 127;
icculus@141
   266
                else if (sample < -128)
icculus@141
   267
                    *s_dst = -128;
icculus@141
   268
                else
icculus@141
   269
                    *s_dst = sample;
icculus@141
   270
icculus@141
   271
                s_src += 2;
icculus@141
   272
                s_dst += 1;
icculus@141
   273
            } /* for */
icculus@141
   274
            break;
icculus@141
   275
icculus@141
   276
        case AUDIO_U16MSB:
icculus@141
   277
            u_src = cvt->buf;
icculus@141
   278
            u_dst = cvt->buf;
icculus@141
   279
icculus@141
   280
            for (i = cvt->len_cvt / 4; i; --i)
icculus@141
   281
            {
icculus@141
   282
                sample = (Uint16) ((u_src[0] << 8) | u_src[1])
icculus@141
   283
                       + (Uint16) ((u_src[2] << 8) | u_src[3]);
icculus@141
   284
                if (sample > 65535)
icculus@141
   285
                {
icculus@141
   286
                    u_dst[0] = 0xFF;
icculus@141
   287
                    u_dst[1] = 0xFF;
icculus@141
   288
                } /* if */
icculus@141
   289
                else
icculus@141
   290
                {
icculus@141
   291
                    u_dst[1] = (sample & 0xFF);
icculus@141
   292
                    sample >>= 8;
icculus@141
   293
                    u_dst[0] = (sample & 0xFF);
icculus@141
   294
                } /* else */
icculus@141
   295
                u_src += 4;
icculus@141
   296
                u_dst += 2;
icculus@141
   297
            } /* for */
icculus@141
   298
            break;
icculus@141
   299
icculus@141
   300
        case AUDIO_U16LSB:
icculus@141
   301
            u_src = cvt->buf;
icculus@141
   302
            u_dst = cvt->buf;
icculus@141
   303
icculus@141
   304
            for (i = cvt->len_cvt / 4; i; --i)
icculus@141
   305
            {
icculus@141
   306
                sample = (Uint16) ((u_src[1] << 8) | u_src[0])
icculus@141
   307
                       + (Uint16) ((u_src[3] << 8) | u_src[2]);
icculus@141
   308
                if (sample > 65535)
icculus@141
   309
                {
icculus@141
   310
                    u_dst[0] = 0xFF;
icculus@141
   311
                    u_dst[1] = 0xFF;
icculus@141
   312
                } /* if */
icculus@141
   313
                else
icculus@141
   314
                {
icculus@141
   315
                    u_dst[0] = (sample & 0xFF);
icculus@141
   316
                    sample >>= 8;
icculus@141
   317
                    u_dst[1] = (sample & 0xFF);
icculus@141
   318
                } /* else */
icculus@141
   319
                u_src += 4;
icculus@141
   320
                u_dst += 2;
icculus@141
   321
            } /* for */
icculus@141
   322
            break;
icculus@141
   323
icculus@141
   324
        case AUDIO_S16MSB:
icculus@141
   325
            u_src = cvt->buf;
icculus@141
   326
            u_dst = cvt->buf;
icculus@141
   327
icculus@141
   328
            for (i = cvt->len_cvt / 4; i; --i)
icculus@141
   329
            {
icculus@141
   330
                sample = (Sint16) ((u_src[0] << 8) | u_src[1])
icculus@141
   331
                       + (Sint16) ((u_src[2] << 8) | u_src[3]);
icculus@141
   332
                if (sample > 32767)
icculus@141
   333
                {
icculus@141
   334
                    u_dst[0] = 0x7F;
icculus@141
   335
                    u_dst[1] = 0xFF;
icculus@141
   336
                } /* if */
icculus@141
   337
                else if (sample < -32768)
icculus@141
   338
                {
icculus@141
   339
                    u_dst[0] = 0x80;
icculus@141
   340
                    u_dst[1] = 0x00;
icculus@141
   341
                } /* else if */
icculus@141
   342
                else
icculus@141
   343
                {
icculus@141
   344
                    u_dst[1] = (sample & 0xFF);
icculus@141
   345
                    sample >>= 8;
icculus@141
   346
                    u_dst[0] = (sample & 0xFF);
icculus@141
   347
                } /* else */
icculus@141
   348
                u_src += 4;
icculus@141
   349
                u_dst += 2;
icculus@141
   350
            } /* for */
icculus@141
   351
            break;
icculus@141
   352
icculus@141
   353
        case AUDIO_S16LSB:
icculus@141
   354
            u_src = cvt->buf;
icculus@141
   355
            u_dst = cvt->buf;
icculus@141
   356
icculus@141
   357
            for (i = cvt->len_cvt / 4; i; --i)
icculus@141
   358
            {
icculus@141
   359
                sample = (Sint16) ((u_src[1] << 8) | u_src[0])
icculus@141
   360
                       + (Sint16) ((u_src[3] << 8) | u_src[2]);
icculus@141
   361
                if (sample > 32767)
icculus@141
   362
                {
icculus@141
   363
                    u_dst[1] = 0x7F;
icculus@141
   364
                    u_dst[0] = 0xFF;
icculus@141
   365
                } /* if */
icculus@141
   366
                else if (sample < -32768)
icculus@141
   367
                {
icculus@141
   368
                    u_dst[1] = 0x80;
icculus@141
   369
                    u_dst[0] = 0x00;
icculus@141
   370
                } /* else if */
icculus@141
   371
                else
icculus@141
   372
                {
icculus@141
   373
                    u_dst[0] = (sample & 0xFF);
icculus@141
   374
                    sample >>= 8;
icculus@141
   375
                    u_dst[1] = (sample & 0xFF);
icculus@141
   376
                } /* else */
icculus@141
   377
                u_src += 4;
icculus@141
   378
                u_dst += 2;
icculus@141
   379
            } /* for */
icculus@141
   380
            break;
icculus@141
   381
    } /* switch */
icculus@141
   382
icculus@141
   383
    cvt->len_cvt /= 2;
icculus@141
   384
} /* Sound_ConvertMono */
icculus@141
   385
icculus@141
   386
icculus@141
   387
/* Convert rate up by multiple of 2 */
icculus@141
   388
icculus@342
   389
static void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   390
{
icculus@141
   391
    int i;
icculus@141
   392
    Uint8 *src, *dst;
icculus@141
   393
icculus@141
   394
    /* SNDDBG(("Converting audio rate * 2\n")); */
icculus@141
   395
icculus@141
   396
    src = cvt->buf + cvt->len_cvt;
icculus@141
   397
    dst = cvt->buf + cvt->len_cvt*2;
icculus@141
   398
icculus@141
   399
        /* 8- or 16-bit sound? */
icculus@141
   400
    switch (*format & 0xFF)
icculus@141
   401
    {
icculus@141
   402
        case 8:
icculus@141
   403
            for (i = cvt->len_cvt; i; --i)
icculus@141
   404
            {
icculus@141
   405
                src -= 1;
icculus@141
   406
                dst -= 2;
icculus@141
   407
                dst[0] = src[0];
icculus@141
   408
                dst[1] = src[0];
icculus@141
   409
            } /* for */
icculus@141
   410
            break;
icculus@141
   411
icculus@141
   412
        case 16:
icculus@141
   413
            for (i = cvt->len_cvt / 2; i; --i)
icculus@141
   414
            {
icculus@141
   415
                src -= 2;
icculus@141
   416
                dst -= 4;
icculus@141
   417
                dst[0] = src[0];
icculus@141
   418
                dst[1] = src[1];
icculus@141
   419
                dst[2] = src[0];
icculus@141
   420
                dst[3] = src[1];
icculus@141
   421
            } /* for */
icculus@141
   422
            break;
icculus@141
   423
    } /* switch */
icculus@141
   424
icculus@141
   425
    cvt->len_cvt *= 2;
icculus@141
   426
} /* Sound_RateMUL2 */
icculus@141
   427
icculus@141
   428
icculus@141
   429
/* Convert rate down by multiple of 2 */
icculus@141
   430
icculus@342
   431
static void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   432
{
icculus@141
   433
    int i;
icculus@141
   434
    Uint8 *src, *dst;
icculus@141
   435
icculus@141
   436
    /* SNDDBG(("Converting audio rate / 2\n")); */
icculus@141
   437
icculus@141
   438
    src = cvt->buf;
icculus@141
   439
    dst = cvt->buf;
icculus@141
   440
icculus@141
   441
        /* 8- or 16-bit sound? */
icculus@141
   442
    switch (*format & 0xFF)
icculus@141
   443
    {
icculus@141
   444
        case 8:
icculus@141
   445
            for (i = cvt->len_cvt / 2; i; --i)
icculus@141
   446
            {
icculus@141
   447
                dst[0] = src[0];
icculus@141
   448
                src += 2;
icculus@141
   449
                dst += 1;
icculus@141
   450
            } /* for */
icculus@141
   451
            break;
icculus@141
   452
icculus@141
   453
        case 16:
icculus@141
   454
            for (i = cvt->len_cvt / 4; i; --i)
icculus@141
   455
            {
icculus@141
   456
                dst[0] = src[0];
icculus@141
   457
                dst[1] = src[1];
icculus@141
   458
                src += 4;
icculus@141
   459
                dst += 2;
icculus@141
   460
            }
icculus@141
   461
            break;
icculus@141
   462
    } /* switch */
icculus@141
   463
icculus@141
   464
    cvt->len_cvt /= 2;
icculus@141
   465
} /* Sound_RateDIV2 */
icculus@141
   466
icculus@141
   467
icculus@141
   468
/* Very slow rate conversion routine */
icculus@141
   469
icculus@342
   470
static void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format)
icculus@141
   471
{
icculus@141
   472
    double ipos;
icculus@141
   473
    int i, clen;
icculus@141
   474
    Uint8 *output8;
icculus@141
   475
    Uint16 *output16;
icculus@141
   476
icculus@141
   477
    /* SNDDBG(("Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr)); */
icculus@141
   478
icculus@141
   479
    clen = (int) ((double) cvt->len_cvt / cvt->rate_incr);
icculus@141
   480
icculus@141
   481
    if (cvt->rate_incr > 1.0)
icculus@141
   482
    {
icculus@141
   483
            /* 8- or 16-bit sound? */
icculus@141
   484
        switch (*format & 0xFF)
icculus@141
   485
        {
icculus@141
   486
            case 8:
icculus@141
   487
                output8 = cvt->buf;
icculus@141
   488
icculus@141
   489
                ipos = 0.0;
icculus@141
   490
                for (i = clen; i; --i)
icculus@141
   491
                {
icculus@141
   492
                    *output8 = cvt->buf[(int) ipos];
icculus@141
   493
                    ipos += cvt->rate_incr;
icculus@141
   494
                    output8 += 1;
icculus@141
   495
                } /* for */
icculus@141
   496
                break;
icculus@141
   497
icculus@141
   498
            case 16:
icculus@141
   499
                output16 = (Uint16 *) cvt->buf;
icculus@141
   500
icculus@141
   501
                clen &= ~1;
icculus@141
   502
                ipos = 0.0;
icculus@141
   503
                for (i = clen / 2; i; --i)
icculus@141
   504
                {
icculus@141
   505
                    *output16 = ((Uint16 *) cvt->buf)[(int) ipos];
icculus@141
   506
                    ipos += cvt->rate_incr;
icculus@141
   507
                    output16 += 1;
icculus@141
   508
                } /* for */
icculus@141
   509
                break;
icculus@141
   510
        } /* switch */
icculus@141
   511
    } /* if */
icculus@141
   512
    else
icculus@141
   513
    {
icculus@141
   514
            /* 8- or 16-bit sound */
icculus@141
   515
        switch (*format & 0xFF)
icculus@141
   516
        {
icculus@141
   517
            case 8:
icculus@141
   518
                output8 = cvt->buf + clen;
icculus@141
   519
icculus@141
   520
                ipos = (double) cvt->len_cvt;
icculus@141
   521
                for (i = clen; i; --i)
icculus@141
   522
                {
icculus@141
   523
                    ipos -= cvt->rate_incr;
icculus@141
   524
                    output8 -= 1;
icculus@141
   525
                    *output8 = cvt->buf[(int) ipos];
icculus@141
   526
                } /* for */
icculus@141
   527
                break;
icculus@141
   528
icculus@141
   529
            case 16:
icculus@141
   530
                clen &= ~1;
icculus@141
   531
                output16 = (Uint16 *) (cvt->buf + clen);
icculus@141
   532
                ipos = (double) cvt->len_cvt / 2;
icculus@141
   533
                for (i = clen / 2; i; --i)
icculus@141
   534
                {
icculus@141
   535
                    ipos -= cvt->rate_incr;
icculus@141
   536
                    output16 -= 1;
icculus@141
   537
                    *output16 = ((Uint16 *) cvt->buf)[(int) ipos];
icculus@141
   538
                } /* for */
icculus@141
   539
                break;
icculus@141
   540
        } /* switch */
icculus@141
   541
    } /* else */
icculus@141
   542
icculus@141
   543
    cvt->len_cvt = clen;
icculus@141
   544
} /* Sound_RateSLOW */
icculus@141
   545
icculus@141
   546
icculus@141
   547
int Sound_ConvertAudio(Sound_AudioCVT *cvt)
icculus@141
   548
{
icculus@141
   549
    Uint16 format;
icculus@141
   550
icculus@141
   551
        /* Make sure there's data to convert */
icculus@141
   552
    if (cvt->buf == NULL)
icculus@141
   553
    {
icculus@387
   554
        __Sound_SetError("No buffer allocated for conversion");
icculus@141
   555
        return(-1);
icculus@141
   556
    } /* if */
icculus@141
   557
icculus@141
   558
        /* Return okay if no conversion is necessary */
icculus@141
   559
    cvt->len_cvt = cvt->len;
icculus@141
   560
    if (cvt->filters[0] == NULL)
icculus@141
   561
        return(0);
icculus@141
   562
icculus@141
   563
        /* Set up the conversion and go! */
icculus@141
   564
    format = cvt->src_format;
icculus@141
   565
    for (cvt->filter_index = 0; cvt->filters[cvt->filter_index];
icculus@141
   566
         cvt->filter_index++)
icculus@141
   567
    {
icculus@141
   568
        cvt->filters[cvt->filter_index](cvt, &format);
icculus@141
   569
    }
icculus@141
   570
    return(0);
icculus@141
   571
} /* Sound_ConvertAudio */
icculus@141
   572
icculus@141
   573
icculus@141
   574
/*
icculus@141
   575
 * Creates a set of audio filters to convert from one format to another. 
icculus@141
   576
 * Returns -1 if the format conversion is not supported, or 1 if the
icculus@141
   577
 * audio filter is set up.
icculus@141
   578
 */
icculus@141
   579
icculus@141
   580
int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
icculus@141
   581
                        Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
icculus@382
   582
                        Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
icculus@382
   583
                        Uint32 dst_size)
icculus@141
   584
{
icculus@141
   585
        /* Start off with no conversion necessary */
icculus@141
   586
    cvt->needed = 0;
icculus@141
   587
    cvt->filter_index = 0;
icculus@141
   588
    cvt->filters[0] = NULL;
icculus@141
   589
    cvt->len_mult = 1;
icculus@141
   590
    cvt->len_ratio = 1.0;
icculus@141
   591
icculus@141
   592
        /* First filter:  Endian conversion from src to dst */
icculus@141
   593
    if ((src_format & 0x1000) != (dst_format & 0x1000) &&
icculus@141
   594
       ((src_format & 0xff) != 8))
icculus@141
   595
    {
icculus@141
   596
        SNDDBG(("Adding filter: Sound_ConvertEndian\n"));
icculus@141
   597
        cvt->filters[cvt->filter_index++] = Sound_ConvertEndian;
icculus@141
   598
    } /* if */
icculus@141
   599
	
icculus@141
   600
        /* Second filter: Sign conversion -- signed/unsigned */
icculus@141
   601
    if ((src_format & 0x8000) != (dst_format & 0x8000))
icculus@141
   602
    {
icculus@141
   603
        SNDDBG(("Adding filter: Sound_ConvertSign\n"));
icculus@141
   604
        cvt->filters[cvt->filter_index++] = Sound_ConvertSign;
icculus@141
   605
    } /* if */
icculus@141
   606
icculus@141
   607
        /* Next filter:  Convert 16 bit <--> 8 bit PCM. */
icculus@141
   608
    if ((src_format & 0xFF) != (dst_format & 0xFF))
icculus@141
   609
    {
icculus@141
   610
        switch (dst_format & 0x10FF)
icculus@141
   611
        {
icculus@141
   612
            case AUDIO_U8:
icculus@141
   613
                SNDDBG(("Adding filter: Sound_Convert8\n"));
icculus@141
   614
                cvt->filters[cvt->filter_index++] = Sound_Convert8;
icculus@141
   615
                cvt->len_ratio /= 2;
icculus@141
   616
                break;
icculus@141
   617
icculus@141
   618
            case AUDIO_U16LSB:
icculus@141
   619
                SNDDBG(("Adding filter: Sound_Convert16LSB\n"));
icculus@141
   620
                cvt->filters[cvt->filter_index++] = Sound_Convert16LSB;
icculus@141
   621
                cvt->len_mult *= 2;
icculus@141
   622
                cvt->len_ratio *= 2;
icculus@141
   623
                break;
icculus@141
   624
icculus@141
   625
            case AUDIO_U16MSB:
icculus@141
   626
                SNDDBG(("Adding filter: Sound_Convert16MSB\n"));
icculus@141
   627
                cvt->filters[cvt->filter_index++] = Sound_Convert16MSB;
icculus@141
   628
                cvt->len_mult *= 2;
icculus@141
   629
                cvt->len_ratio *= 2;
icculus@141
   630
                break;
icculus@141
   631
        } /* switch */
icculus@141
   632
    } /* if */
icculus@141
   633
icculus@141
   634
        /* Next filter:  Mono/Stereo conversion */
icculus@141
   635
    if (src_channels != dst_channels)
icculus@141
   636
    {
icculus@141
   637
        while ((src_channels * 2) <= dst_channels)
icculus@141
   638
        {
icculus@141
   639
            SNDDBG(("Adding filter: Sound_ConvertStereo\n"));
icculus@141
   640
            cvt->filters[cvt->filter_index++] = Sound_ConvertStereo;
icculus@141
   641
            cvt->len_mult *= 2;
icculus@141
   642
            src_channels *= 2;
icculus@141
   643
            cvt->len_ratio *= 2;
icculus@141
   644
        } /* while */
icculus@141
   645
icculus@141
   646
        /* This assumes that 4 channel audio is in the format:
icculus@141
   647
         *     Left {front/back} + Right {front/back}
icculus@141
   648
         * so converting to L/R stereo works properly.
icculus@141
   649
         */
icculus@141
   650
        while (((src_channels % 2) == 0) &&
icculus@141
   651
               ((src_channels / 2) >= dst_channels))
icculus@141
   652
        {
icculus@141
   653
            SNDDBG(("Adding filter: Sound_ConvertMono\n"));
icculus@141
   654
            cvt->filters[cvt->filter_index++] = Sound_ConvertMono;
icculus@141
   655
            src_channels /= 2;
icculus@141
   656
            cvt->len_ratio /= 2;
icculus@141
   657
        } /* while */
icculus@141
   658
icculus@141
   659
        if ( src_channels != dst_channels ) {
icculus@141
   660
            /* Uh oh.. */;
icculus@141
   661
        } /* if */
icculus@141
   662
    } /* if */
icculus@141
   663
icculus@141
   664
    /* Do rate conversion */
icculus@141
   665
    cvt->rate_incr = 0.0;
icculus@141
   666
    if ((src_rate / 100) != (dst_rate / 100))
icculus@141
   667
    {
icculus@141
   668
        Uint32 hi_rate, lo_rate;
icculus@141
   669
        int len_mult;
icculus@141
   670
        double len_ratio;
icculus@141
   671
        void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format);
icculus@141
   672
icculus@141
   673
        if (src_rate > dst_rate)
icculus@141
   674
        {
icculus@141
   675
            hi_rate = src_rate;
icculus@141
   676
            lo_rate = dst_rate;
icculus@141
   677
            SNDDBG(("Adding filter: Sound_RateDIV2\n"));
icculus@141
   678
            rate_cvt = Sound_RateDIV2;
icculus@141
   679
            len_mult = 1;
icculus@141
   680
            len_ratio = 0.5;
icculus@141
   681
        } /* if */
icculus@141
   682
        else
icculus@141
   683
        {
icculus@141
   684
            hi_rate = dst_rate;
icculus@141
   685
            lo_rate = src_rate;
icculus@141
   686
            SNDDBG(("Adding filter: Sound_RateMUL2\n"));
icculus@141
   687
            rate_cvt = Sound_RateMUL2;
icculus@141
   688
            len_mult = 2;
icculus@141
   689
            len_ratio = 2.0;
icculus@141
   690
        } /* else */
icculus@141
   691
icculus@141
   692
            /* If hi_rate = lo_rate*2^x then conversion is easy */
icculus@141
   693
        while (((lo_rate * 2) / 100) <= (hi_rate / 100))
icculus@141
   694
        {
icculus@141
   695
            cvt->filters[cvt->filter_index++] = rate_cvt;
icculus@141
   696
            cvt->len_mult *= len_mult;
icculus@141
   697
            lo_rate *= 2;
icculus@141
   698
            cvt->len_ratio *= len_ratio;
icculus@141
   699
        } /* while */
icculus@141
   700
icculus@141
   701
            /* We may need a slow conversion here to finish up */
icculus@141
   702
        if ((lo_rate / 100) != (hi_rate / 100))
icculus@141
   703
        {
icculus@141
   704
            if (src_rate < dst_rate)
icculus@141
   705
            {
icculus@141
   706
                cvt->rate_incr = (double) lo_rate / hi_rate;
icculus@141
   707
                cvt->len_mult *= 2;
icculus@141
   708
                cvt->len_ratio /= cvt->rate_incr;
icculus@141
   709
            } /* if */
icculus@141
   710
            else
icculus@141
   711
            {
icculus@141
   712
                cvt->rate_incr = (double) hi_rate / lo_rate;
icculus@141
   713
                cvt->len_ratio *= cvt->rate_incr;
icculus@141
   714
            } /* else */
icculus@141
   715
            SNDDBG(("Adding filter: Sound_RateSLOW\n"));
icculus@141
   716
            cvt->filters[cvt->filter_index++] = Sound_RateSLOW;
icculus@141
   717
        } /* if */
icculus@141
   718
    } /* if */
icculus@141
   719
icculus@141
   720
        /* Set up the filter information */
icculus@141
   721
    if (cvt->filter_index != 0)
icculus@141
   722
    {
icculus@141
   723
        cvt->needed = 1;
icculus@141
   724
        cvt->src_format = src_format;
icculus@141
   725
        cvt->dst_format = dst_format;
icculus@141
   726
        cvt->len = 0;
icculus@141
   727
        cvt->buf = NULL;
icculus@141
   728
        cvt->filters[cvt->filter_index] = NULL;
icculus@141
   729
    } /* if */
icculus@141
   730
icculus@141
   731
    return(cvt->needed);
icculus@141
   732
} /* Sound_BuildAudioCVT */
icculus@465
   733
icculus@465
   734
/* end of audio_convert.c ... */
icculus@465
   735