src/audio/SDL_audiotypecvt.c
author Ryan C. Gordon
Thu, 05 Jan 2017 19:12:20 -0500
changeset 10756 073957aca821
parent 10737 3406a0f8b041
child 10799 234f71894a52
permissions -rw-r--r--
audio: More effort to improve and simplify audio resamplers.
icculus@1982
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@5535
     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@5535
     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@5535
    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.
icculus@1982
    20
*/
icculus@1982
    21
icculus@8093
    22
#include "../SDL_internal.h"
icculus@1982
    23
#include "SDL_audio.h"
icculus@1982
    24
#include "SDL_audio_c.h"
icculus@10575
    25
#include "SDL_assert.h"
icculus@1982
    26
icculus@1982
    27
#define DIVBY127 0.0078740157480315f
icculus@1982
    28
#define DIVBY32767 3.05185094759972e-05f
icculus@1982
    29
#define DIVBY2147483647 4.6566128752458e-10f
icculus@1982
    30
icculus@10575
    31
void SDLCALL
icculus@10575
    32
SDL_Convert_S8_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
    33
{
icculus@10575
    34
    const Uint8 *src = ((const Uint8 *) (cvt->buf + cvt->len_cvt)) - 1;
icculus@10575
    35
    float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
icculus@1982
    36
    int i;
icculus@1982
    37
icculus@10575
    38
    LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32");
icculus@1982
    39
icculus@1982
    40
    for (i = cvt->len_cvt / sizeof (Uint8); i; --i, --src, --dst) {
icculus@10575
    41
        *dst = (((float) ((Sint8) *src)) * DIVBY127);
icculus@1982
    42
    }
icculus@1982
    43
icculus@1982
    44
    cvt->len_cvt *= 4;
icculus@1982
    45
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
    46
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@1982
    47
    }
icculus@1982
    48
}
icculus@1982
    49
icculus@10575
    50
void SDLCALL
icculus@10575
    51
SDL_Convert_U8_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
    52
{
icculus@10575
    53
    const Uint8 *src = ((const Uint8 *) (cvt->buf + cvt->len_cvt)) - 1;
icculus@10575
    54
    float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
icculus@1982
    55
    int i;
icculus@1982
    56
icculus@10575
    57
    LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32");
icculus@1982
    58
icculus@1982
    59
    for (i = cvt->len_cvt / sizeof (Uint8); i; --i, --src, --dst) {
icculus@10575
    60
        *dst = ((((float) *src) * DIVBY127) - 1.0f);
icculus@1982
    61
    }
icculus@1982
    62
icculus@1982
    63
    cvt->len_cvt *= 4;
icculus@1982
    64
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
    65
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@1982
    66
    }
icculus@1982
    67
}
icculus@1982
    68
icculus@10575
    69
void SDLCALL
icculus@10575
    70
SDL_Convert_S16_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
    71
{
icculus@10575
    72
    const Sint16 *src = ((const Sint16 *) (cvt->buf + cvt->len_cvt)) - 1;
icculus@10575
    73
    float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
icculus@1982
    74
    int i;
icculus@1982
    75
icculus@10575
    76
    LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32");
icculus@1982
    77
icculus@10575
    78
    for (i = cvt->len_cvt / sizeof (Sint16); i; --i, --src, --dst) {
icculus@10575
    79
        *dst = (((float) *src) * DIVBY32767);
icculus@1982
    80
    }
icculus@1982
    81
icculus@1982
    82
    cvt->len_cvt *= 2;
icculus@1982
    83
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
    84
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@1982
    85
    }
icculus@1982
    86
}
icculus@1982
    87
icculus@10575
    88
void SDLCALL
icculus@10575
    89
SDL_Convert_U16_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
    90
{
icculus@10575
    91
    const Uint16 *src = ((const Uint16 *) (cvt->buf + cvt->len_cvt)) - 1;
icculus@10575
    92
    float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
icculus@1982
    93
    int i;
icculus@1982
    94
icculus@10575
    95
    LOG_DEBUG_CONVERT("AUDIO_U16", "AUDIO_F32");
icculus@1982
    96
icculus@1982
    97
    for (i = cvt->len_cvt / sizeof (Uint16); i; --i, --src, --dst) {
icculus@10575
    98
        *dst = ((((float) *src) * DIVBY32767) - 1.0f);
icculus@1982
    99
    }
icculus@1982
   100
icculus@1982
   101
    cvt->len_cvt *= 2;
icculus@1982
   102
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   103
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@1982
   104
    }
icculus@1982
   105
}
icculus@1982
   106
icculus@10575
   107
void SDLCALL
icculus@10575
   108
SDL_Convert_S32_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
   109
{
icculus@10575
   110
    const Uint32 *src = (const Uint32 *) cvt->buf;
icculus@10575
   111
    float *dst = (float *) cvt->buf;
icculus@1982
   112
    int i;
icculus@1982
   113
icculus@10575
   114
    LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32");
icculus@1982
   115
icculus@10575
   116
    for (i = cvt->len_cvt / sizeof (Sint32); i; --i, ++src, ++dst) {
icculus@10575
   117
        *dst = (((float) *src) * DIVBY2147483647);
icculus@1982
   118
    }
icculus@1982
   119
icculus@1982
   120
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   121
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@1982
   122
    }
icculus@1982
   123
}
icculus@1982
   124
icculus@10575
   125
void SDLCALL
icculus@10575
   126
SDL_Convert_F32_to_S8(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
   127
{
icculus@10575
   128
    const float *src = (const float *) cvt->buf;
icculus@10575
   129
    Sint8 *dst = (Sint8 *) cvt->buf;
icculus@1982
   130
    int i;
icculus@1982
   131
icculus@10575
   132
    LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8");
icculus@1982
   133
icculus@10575
   134
    for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
icculus@10575
   135
        *dst = (Sint8) (*src * 127.0f);
icculus@1982
   136
    }
icculus@1982
   137
icculus@1982
   138
    cvt->len_cvt /= 4;
icculus@1982
   139
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   140
        cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
icculus@1982
   141
    }
icculus@1982
   142
}
icculus@1982
   143
icculus@10575
   144
void SDLCALL
icculus@10575
   145
SDL_Convert_F32_to_U8(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
   146
{
icculus@10575
   147
    const float *src = (const float *) cvt->buf;
icculus@10575
   148
    Uint8 *dst = (Uint8 *) cvt->buf;
icculus@1982
   149
    int i;
icculus@1982
   150
icculus@10575
   151
    LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8");
icculus@1982
   152
icculus@10575
   153
    for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
icculus@10575
   154
        *dst = (Uint8) ((*src + 1.0f) * 127.0f);
icculus@1982
   155
    }
icculus@1982
   156
icculus@1982
   157
    cvt->len_cvt /= 4;
icculus@1982
   158
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   159
        cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
icculus@1982
   160
    }
icculus@1982
   161
}
icculus@1982
   162
icculus@10575
   163
void SDLCALL
icculus@10575
   164
SDL_Convert_F32_to_S16(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
   165
{
icculus@10575
   166
    const float *src = (const float *) cvt->buf;
icculus@10575
   167
    Sint16 *dst = (Sint16 *) cvt->buf;
icculus@1982
   168
    int i;
icculus@1982
   169
icculus@10575
   170
    LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16");
icculus@1982
   171
icculus@1982
   172
    for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
icculus@10575
   173
        *dst = (Sint16) (*src * 32767.0f);
icculus@1982
   174
    }
icculus@1982
   175
icculus@1982
   176
    cvt->len_cvt /= 2;
icculus@1982
   177
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   178
        cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
icculus@1982
   179
    }
icculus@1982
   180
}
icculus@1982
   181
icculus@10575
   182
void SDLCALL
icculus@10575
   183
SDL_Convert_F32_to_U16(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@1982
   184
{
icculus@10575
   185
    const float *src = (const float *) cvt->buf;
icculus@10575
   186
    Uint16 *dst = (Uint16 *) cvt->buf;
icculus@1982
   187
    int i;
icculus@1982
   188
icculus@10575
   189
    LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16");
icculus@1982
   190
icculus@1982
   191
    for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
icculus@10575
   192
        *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
icculus@1982
   193
    }
icculus@1982
   194
icculus@1982
   195
    cvt->len_cvt /= 2;
icculus@1982
   196
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   197
        cvt->filters[cvt->filter_index](cvt, AUDIO_U16SYS);
icculus@3021
   198
    }
icculus@3021
   199
}
icculus@3021
   200
icculus@10575
   201
void SDLCALL
icculus@10575
   202
SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
icculus@3021
   203
{
icculus@10575
   204
    const float *src = (const float *) cvt->buf;
icculus@10575
   205
    Sint32 *dst = (Sint32 *) cvt->buf;
icculus@10575
   206
    int i;
icculus@3021
   207
icculus@10575
   208
    LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32");
icculus@3021
   209
icculus@10575
   210
    for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
icculus@10575
   211
        *dst = (Sint32) (*src * 2147483647.0);
icculus@3021
   212
    }
icculus@3021
   213
icculus@3021
   214
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   215
        cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
icculus@3021
   216
    }
icculus@3021
   217
}
icculus@3021
   218
icculus@10575
   219
void
icculus@10575
   220
SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
icculus@3021
   221
{
icculus@10575
   222
    const int srcsize = cvt->len_cvt - (64 * channels);
icculus@10756
   223
    const int dstsize = (int) ((((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr)) * (channels*4);
icculus@3021
   224
    register int eps = 0;
icculus@10708
   225
    float *dst = ((float *) (cvt->buf + dstsize)) - channels;
icculus@10708
   226
    const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
icculus@10575
   227
    const float *target = ((const float *) cvt->buf);
icculus@10575
   228
    const size_t cpy = sizeof (float) * channels;
icculus@10756
   229
    float sample[8];
icculus@10575
   230
    float last_sample[8];
icculus@10575
   231
    int i;
icculus@3021
   232
slouken@3032
   233
#if DEBUG_CONVERT
icculus@10575
   234
    fprintf(stderr, "Upsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels);
icculus@3021
   235
#endif
icculus@3021
   236
icculus@10575
   237
    SDL_assert(channels <= 8);
icculus@3021
   238
icculus@10756
   239
    for (i = 0; i < channels; i++) {
icculus@10756
   240
        sample[i] = (float) ((((double) src[i]) + ((double) src[i - channels])) * 0.5);
icculus@10756
   241
    }
icculus@10575
   242
    SDL_memcpy(last_sample, src, cpy);
icculus@3021
   243
slouken@10608
   244
    while (dst > target) {
icculus@10575
   245
        SDL_memcpy(dst, sample, cpy);
icculus@10708
   246
        dst -= channels;
icculus@3021
   247
        eps += srcsize;
icculus@3021
   248
        if ((eps << 1) >= dstsize) {
icculus@10756
   249
            if (src > target) {
icculus@10756
   250
                src -= channels;
icculus@10756
   251
                for (i = 0; i < channels; i++) {
icculus@10756
   252
                    sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
icculus@10756
   253
                }
icculus@10756
   254
            } else {
icculus@10756
   255
icculus@10575
   256
            }
icculus@10756
   257
            SDL_memcpy(last_sample, src, cpy);
icculus@3021
   258
            eps -= dstsize;
icculus@3021
   259
        }
icculus@3021
   260
    }
icculus@3021
   261
icculus@3021
   262
    cvt->len_cvt = dstsize;
icculus@3021
   263
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   264
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@3021
   265
    }
icculus@3021
   266
}
icculus@3021
   267
icculus@10575
   268
void
icculus@10575
   269
SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
icculus@3021
   270
{
icculus@10575
   271
    const int srcsize = cvt->len_cvt - (64 * channels);
icculus@10575
   272
    const int dstsize = (int) (((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr) * (channels*4);
icculus@10575
   273
    register int eps = 0;
icculus@10575
   274
    float *dst = (float *) cvt->buf;
icculus@10575
   275
    const float *src = (float *) cvt->buf;
icculus@10575
   276
    const float *target = (const float *) (cvt->buf + dstsize);
icculus@10575
   277
    const size_t cpy = sizeof (float) * channels;
icculus@10575
   278
    float last_sample[8];
icculus@10575
   279
    float sample[8];
icculus@10575
   280
    int i;
icculus@3021
   281
slouken@3032
   282
#if DEBUG_CONVERT
icculus@10575
   283
    fprintf(stderr, "Downsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels);
icculus@3021
   284
#endif
icculus@3021
   285
icculus@10575
   286
    SDL_assert(channels <= 8);
icculus@3021
   287
icculus@10575
   288
    SDL_memcpy(sample, src, cpy);
icculus@10575
   289
    SDL_memcpy(last_sample, src, cpy);
icculus@3021
   290
icculus@3602
   291
    while (dst < target) {
icculus@10711
   292
        src += channels;
icculus@10575
   293
        eps += dstsize;
icculus@10575
   294
        if ((eps << 1) >= srcsize) {
icculus@10575
   295
            SDL_memcpy(dst, sample, cpy);
icculus@10711
   296
            dst += channels;
icculus@10575
   297
            for (i = 0; i < channels; i++) {
icculus@10575
   298
                sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
icculus@10575
   299
            }
icculus@10756
   300
            SDL_memcpy(last_sample, src, cpy);
icculus@10575
   301
            eps -= srcsize;
icculus@10575
   302
        }
icculus@3021
   303
    }
icculus@3021
   304
icculus@3021
   305
    cvt->len_cvt = dstsize;
icculus@3021
   306
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   307
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@3021
   308
    }
icculus@3021
   309
}
icculus@3021
   310
icculus@10575
   311
void
icculus@10756
   312
SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels)
icculus@3021
   313
{
icculus@10756
   314
    const int multiple = (int) cvt->rate_incr;
icculus@10756
   315
    const int dstsize = cvt->len_cvt * multiple;
icculus@10756
   316
    float *buf = (float *) cvt->buf;
icculus@10756
   317
    float *dst = ((float *) (cvt->buf + dstsize)) - channels;
icculus@10575
   318
    const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
icculus@10756
   319
    const float *target = buf + channels;
icculus@10575
   320
    const size_t cpy = sizeof (float) * channels;
icculus@10575
   321
    float last_sample[8];
icculus@10575
   322
    int i;
icculus@3021
   323
slouken@3032
   324
#if DEBUG_CONVERT
icculus@10756
   325
    fprintf(stderr, "Upsample (x%d), %d channels.\n", multiple, channels);
icculus@3021
   326
#endif
icculus@3021
   327
icculus@10575
   328
    SDL_assert(channels <= 8);
icculus@10756
   329
icculus@10575
   330
    SDL_memcpy(last_sample, src, cpy);
icculus@3021
   331
slouken@10608
   332
    while (dst > target) {
icculus@10756
   333
        SDL_assert(src >= buf);
icculus@10756
   334
icculus@10575
   335
        for (i = 0; i < channels; i++) {
icculus@10575
   336
            dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
icculus@10575
   337
        }
icculus@10575
   338
        dst -= channels;
icculus@10756
   339
icculus@10756
   340
        for (i = 1; i < multiple; i++) {
icculus@10756
   341
            SDL_memcpy(dst, dst + channels, cpy);
icculus@10756
   342
            dst -= channels;
icculus@10756
   343
        }
icculus@10756
   344
icculus@10575
   345
        src -= channels;
icculus@10756
   346
        if (src > buf) {
icculus@10756
   347
            SDL_memcpy(last_sample, src - channels, cpy);
icculus@10756
   348
        }
icculus@3021
   349
    }
icculus@3021
   350
icculus@3021
   351
    cvt->len_cvt = dstsize;
icculus@3021
   352
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   353
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@3021
   354
    }
icculus@3021
   355
}
icculus@3021
   356
icculus@10575
   357
void
icculus@10756
   358
SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels)
icculus@3021
   359
{
icculus@10756
   360
    const int multiple = (int) (1.0 / cvt->rate_incr);
icculus@10575
   361
    const int dstsize = cvt->len_cvt / multiple;
icculus@3021
   362
    float *dst = (float *) cvt->buf;
icculus@3021
   363
    const float *src = (float *) cvt->buf;
icculus@3021
   364
    const float *target = (const float *) (cvt->buf + dstsize);
icculus@10575
   365
    const size_t cpy = sizeof (float) * channels;
icculus@10575
   366
    float last_sample[8];
icculus@10575
   367
    int i;
icculus@3021
   368
slouken@3032
   369
#if DEBUG_CONVERT
icculus@10575
   370
    fprintf(stderr, "Downsample (x%d), %d channels.\n", multiple, channels);
icculus@3021
   371
#endif
icculus@3021
   372
icculus@10575
   373
    SDL_assert(channels <= 8);
icculus@10575
   374
    SDL_memcpy(last_sample, src, cpy);
icculus@3021
   375
icculus@3602
   376
    while (dst < target) {
icculus@10575
   377
        for (i = 0; i < channels; i++) {
icculus@10575
   378
            dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
icculus@10575
   379
        }
icculus@10575
   380
        dst += channels;
icculus@3021
   381
icculus@10575
   382
        SDL_memcpy(last_sample, src, cpy);
icculus@10575
   383
        src += (channels * multiple);
icculus@3021
   384
    }
icculus@3021
   385
icculus@3021
   386
    cvt->len_cvt = dstsize;
icculus@3021
   387
    if (cvt->filters[++cvt->filter_index]) {
icculus@10575
   388
        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
icculus@3021
   389
    }
icculus@3021
   390
}
icculus@3021
   391
slouken@1985
   392
/* vi: set ts=4 sw=4 expandtab: */