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