Fix audio conversion when channel count changes
authorJames Legg
Fri, 21 Feb 2014 13:57:53 +0000
changeset 8235cc1d377f014a
parent 8234 80c193c7c8c8
child 8236 751605725282
Fix audio conversion when channel count changes

- Use the SDL_AUDIO_MASK_DATATYPE bit when selecting an implementation
where it matters. Previously two existing AUDIO_F32 cases had been
written, but were unreachable.
- Add AUDIO_F32 case for SDL_ConvertSurround_4.
- Fix incorrect pointer arithmetic causing the 2 to 6 channel
conversion for 4 byte audio formats to read and write beyond the end
of the buffer.
src/audio/SDL_audiocvt.c
     1.1 --- a/src/audio/SDL_audiocvt.c	Sat Feb 22 15:27:11 2014 -0800
     1.2 +++ b/src/audio/SDL_audiocvt.c	Fri Feb 21 13:57:53 2014 +0000
     1.3 @@ -39,7 +39,9 @@
     1.4  #ifdef DEBUG_CONVERT
     1.5      fprintf(stderr, "Converting to mono\n");
     1.6  #endif
     1.7 -    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
     1.8 +	switch (format & (SDL_AUDIO_MASK_SIGNED |
     1.9 +                      SDL_AUDIO_MASK_BITSIZE |
    1.10 +                      SDL_AUDIO_MASK_DATATYPE)) {
    1.11      case AUDIO_U8:
    1.12          {
    1.13              Uint8 *src, *dst;
    1.14 @@ -331,7 +333,9 @@
    1.15      fprintf(stderr, "Converting stereo to surround\n");
    1.16  #endif
    1.17  
    1.18 -    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
    1.19 +    switch (format & (SDL_AUDIO_MASK_SIGNED  |
    1.20 +                      SDL_AUDIO_MASK_BITSIZE |
    1.21 +                      SDL_AUDIO_MASK_DATATYPE)) {
    1.22      case AUDIO_U8:
    1.23          {
    1.24              Uint8 *src, *dst, lf, rf, ce;
    1.25 @@ -499,8 +503,8 @@
    1.26      case AUDIO_S32:
    1.27          {
    1.28              Sint32 lf, rf, ce;
    1.29 -            const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt;
    1.30 -            Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3;
    1.31 +            const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
    1.32 +            Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 3);
    1.33  
    1.34              if (SDL_AUDIO_ISBIGENDIAN(format)) {
    1.35                  for (i = cvt->len_cvt / 8; i; --i) {
    1.36 @@ -537,8 +541,8 @@
    1.37      case AUDIO_F32:
    1.38          {
    1.39              float lf, rf, ce;
    1.40 -            const float *src = (const float *) cvt->buf + cvt->len_cvt;
    1.41 -            float *dst = (float *) cvt->buf + cvt->len_cvt * 3;
    1.42 +            const float *src = (const float *) (cvt->buf + cvt->len_cvt);
    1.43 +            float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
    1.44  
    1.45              if (SDL_AUDIO_ISBIGENDIAN(format)) {
    1.46                  for (i = cvt->len_cvt / 8; i; --i) {
    1.47 @@ -588,7 +592,9 @@
    1.48      fprintf(stderr, "Converting stereo to quad\n");
    1.49  #endif
    1.50  
    1.51 -    switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
    1.52 +    switch (format & (SDL_AUDIO_MASK_SIGNED |
    1.53 +                      SDL_AUDIO_MASK_BITSIZE |
    1.54 +                      SDL_AUDIO_MASK_DATATYPE)) {
    1.55      case AUDIO_U8:
    1.56          {
    1.57              Uint8 *src, *dst, lf, rf, ce;
    1.58 @@ -762,6 +768,40 @@
    1.59              }
    1.60          }
    1.61          break;
    1.62 +
    1.63 +    case AUDIO_F32:
    1.64 +        {
    1.65 +            const float *src = (const float *) (cvt->buf + cvt->len_cvt);
    1.66 +            float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
    1.67 +            float lf, rf, ce;
    1.68 +
    1.69 +            if (SDL_AUDIO_ISBIGENDIAN(format)) {
    1.70 +                for (i = cvt->len_cvt / 8; i; --i) {
    1.71 +                    dst -= 4;
    1.72 +                    src -= 2;
    1.73 +                    lf = SDL_SwapFloatBE(src[0]);
    1.74 +                    rf = SDL_SwapFloatBE(src[1]);
    1.75 +                    ce = (lf / 2) + (rf / 2);
    1.76 +                    dst[0] = src[0];
    1.77 +                    dst[1] = src[1];
    1.78 +                    dst[2] = SDL_SwapFloatBE(lf - ce);
    1.79 +                    dst[3] = SDL_SwapFloatBE(rf - ce);
    1.80 +                }
    1.81 +            } else {
    1.82 +                for (i = cvt->len_cvt / 8; i; --i) {
    1.83 +                    dst -= 4;
    1.84 +                    src -= 2;
    1.85 +                    lf = SDL_SwapFloatLE(src[0]);
    1.86 +                    rf = SDL_SwapFloatLE(src[1]);
    1.87 +                    ce = (lf / 2) + (rf / 2);
    1.88 +                    dst[0] = src[0];
    1.89 +                    dst[1] = src[1];
    1.90 +                    dst[2] = SDL_SwapFloatLE(lf - ce);
    1.91 +                    dst[3] = SDL_SwapFloatLE(rf - ce);
    1.92 +                }
    1.93 +            }
    1.94 +        }
    1.95 +        break;
    1.96      }
    1.97      cvt->len_cvt *= 2;
    1.98      if (cvt->filters[++cvt->filter_index]) {