From d3cf7360dbd24f0bd0375c3e9675640244a9b3f1 Mon Sep 17 00:00:00 2001 From: James Legg Date: Fri, 21 Feb 2014 13:57:53 +0000 Subject: [PATCH] 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 | 54 ++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index b167b94a0f6a2..518735bfcc10f 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -39,7 +39,9 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) #ifdef DEBUG_CONVERT fprintf(stderr, "Converting to mono\n"); #endif - switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) { + switch (format & (SDL_AUDIO_MASK_SIGNED | + SDL_AUDIO_MASK_BITSIZE | + SDL_AUDIO_MASK_DATATYPE)) { case AUDIO_U8: { Uint8 *src, *dst; @@ -331,7 +333,9 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format) fprintf(stderr, "Converting stereo to surround\n"); #endif - switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) { + switch (format & (SDL_AUDIO_MASK_SIGNED | + SDL_AUDIO_MASK_BITSIZE | + SDL_AUDIO_MASK_DATATYPE)) { case AUDIO_U8: { Uint8 *src, *dst, lf, rf, ce; @@ -499,8 +503,8 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format) case AUDIO_S32: { Sint32 lf, rf, ce; - const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt; - Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3; + const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt); + Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 3); if (SDL_AUDIO_ISBIGENDIAN(format)) { for (i = cvt->len_cvt / 8; i; --i) { @@ -537,8 +541,8 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format) case AUDIO_F32: { float lf, rf, ce; - const float *src = (const float *) cvt->buf + cvt->len_cvt; - float *dst = (float *) cvt->buf + cvt->len_cvt * 3; + const float *src = (const float *) (cvt->buf + cvt->len_cvt); + float *dst = (float *) (cvt->buf + cvt->len_cvt * 3); if (SDL_AUDIO_ISBIGENDIAN(format)) { for (i = cvt->len_cvt / 8; i; --i) { @@ -588,7 +592,9 @@ SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format) fprintf(stderr, "Converting stereo to quad\n"); #endif - switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) { + switch (format & (SDL_AUDIO_MASK_SIGNED | + SDL_AUDIO_MASK_BITSIZE | + SDL_AUDIO_MASK_DATATYPE)) { case AUDIO_U8: { Uint8 *src, *dst, lf, rf, ce; @@ -762,6 +768,40 @@ SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format) } } break; + + case AUDIO_F32: + { + const float *src = (const float *) (cvt->buf + cvt->len_cvt); + float *dst = (float *) (cvt->buf + cvt->len_cvt * 2); + float lf, rf, ce; + + if (SDL_AUDIO_ISBIGENDIAN(format)) { + for (i = cvt->len_cvt / 8; i; --i) { + dst -= 4; + src -= 2; + lf = SDL_SwapFloatBE(src[0]); + rf = SDL_SwapFloatBE(src[1]); + ce = (lf / 2) + (rf / 2); + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = SDL_SwapFloatBE(lf - ce); + dst[3] = SDL_SwapFloatBE(rf - ce); + } + } else { + for (i = cvt->len_cvt / 8; i; --i) { + dst -= 4; + src -= 2; + lf = SDL_SwapFloatLE(src[0]); + rf = SDL_SwapFloatLE(src[1]); + ce = (lf / 2) + (rf / 2); + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = SDL_SwapFloatLE(lf - ce); + dst[3] = SDL_SwapFloatLE(rf - ce); + } + } + } + break; } cvt->len_cvt *= 2; if (cvt->filters[++cvt->filter_index]) {