Fixed bug 3876 - Resampling of certain sounds adds heavy distortion
authorSam Lantinga <slouken@libsdl.org>
Wed, 18 Oct 2017 19:30:47 -0700
changeset 1163337aca00967db
parent 11632 385312bd6594
child 11634 ced7925b7a95
Fixed bug 3876 - Resampling of certain sounds adds heavy distortion

Simon Hug

Patch that adds [-1, 1] clamping to the scalar audio type conversions.

This may come from the SDL_Convert_F32_to_X_Scalar functions. They don't clamp the float value to [-1, 1] and when they cast it to the target integer it may be too large or too small for the type and get truncated, causing horrible noise.

The attached patch throws clamping in, but I don't know if that's the preferred way to fix this. For x86 (without SSE) the compiler (I tested MSVC) seems to throw a horrible amount of x87 code in it. It's a bit better with SSE, but probably still quite the performance hit. And SSE2 uses a branchless approach with maxss and minss.
src/audio/SDL_audiotypecvt.c
     1.1 --- a/src/audio/SDL_audiotypecvt.c	Wed Oct 18 19:26:36 2017 -0700
     1.2 +++ b/src/audio/SDL_audiotypecvt.c	Wed Oct 18 19:30:47 2017 -0700
     1.3 @@ -170,7 +170,14 @@
     1.4      LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8");
     1.5  
     1.6      for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
     1.7 -        *dst = (Sint8) (*src * 127.0f);
     1.8 +        const float sample = *src;
     1.9 +        if (sample > 1.0f) {
    1.10 +            *dst = 127;
    1.11 +        } else if (sample < -1.0f) {
    1.12 +            *dst = -127;
    1.13 +        } else {
    1.14 +            *dst = (Sint8)(sample * 127.0f);
    1.15 +        }
    1.16      }
    1.17  
    1.18      cvt->len_cvt /= 4;
    1.19 @@ -189,7 +196,14 @@
    1.20      LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8");
    1.21  
    1.22      for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
    1.23 -        *dst = (Uint8) ((*src + 1.0f) * 127.0f);
    1.24 +        const float sample = *src;
    1.25 +        if (sample > 1.0f) {
    1.26 +            *dst = 255;
    1.27 +        } else if (sample < -1.0f) {
    1.28 +            *dst = 0;
    1.29 +        } else {
    1.30 +            *dst = (Uint8)((sample + 1.0f) * 127.0f);
    1.31 +        }
    1.32      }
    1.33  
    1.34      cvt->len_cvt /= 4;
    1.35 @@ -208,7 +222,14 @@
    1.36      LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16");
    1.37  
    1.38      for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
    1.39 -        *dst = (Sint16) (*src * 32767.0f);
    1.40 +        const float sample = *src;
    1.41 +        if (sample > 1.0f) {
    1.42 +            *dst = 32767;
    1.43 +        } else if (sample < -1.0f) {
    1.44 +            *dst = -32767;
    1.45 +        } else {
    1.46 +            *dst = (Sint16)(sample * 32767.0f);
    1.47 +        }
    1.48      }
    1.49  
    1.50      cvt->len_cvt /= 2;
    1.51 @@ -227,7 +248,14 @@
    1.52      LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16");
    1.53  
    1.54      for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
    1.55 -        *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
    1.56 +        const float sample = *src;
    1.57 +        if (sample > 1.0f) {
    1.58 +            *dst = 65534;
    1.59 +        } else if (sample < -1.0f) {
    1.60 +            *dst = 0;
    1.61 +        } else {
    1.62 +            *dst = (Uint16)((sample + 1.0f) * 32767.0f);
    1.63 +        }
    1.64      }
    1.65  
    1.66      cvt->len_cvt /= 2;
    1.67 @@ -246,7 +274,14 @@
    1.68      LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32");
    1.69  
    1.70      for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
    1.71 -        *dst = (Sint32) (((double) *src) * 2147483647.0);
    1.72 +        const float sample = *src;
    1.73 +        if (sample > 1.0f) {
    1.74 +            *dst = 2147483647;
    1.75 +        } else if (sample < -1.0f) {
    1.76 +            *dst = -2147483647;
    1.77 +        } else {
    1.78 +            *dst = (Sint32)((double)sample * 2147483647.0);
    1.79 +        }
    1.80      }
    1.81  
    1.82      if (cvt->filters[++cvt->filter_index]) {