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.
This commit is contained in:
James Legg 2014-02-21 13:57:53 +00:00
parent 5512eac69f
commit d3cf7360db
1 changed files with 47 additions and 7 deletions

View File

@ -39,7 +39,9 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
#ifdef DEBUG_CONVERT #ifdef DEBUG_CONVERT
fprintf(stderr, "Converting to mono\n"); fprintf(stderr, "Converting to mono\n");
#endif #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: case AUDIO_U8:
{ {
Uint8 *src, *dst; Uint8 *src, *dst;
@ -331,7 +333,9 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
fprintf(stderr, "Converting stereo to surround\n"); fprintf(stderr, "Converting stereo to surround\n");
#endif #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: case AUDIO_U8:
{ {
Uint8 *src, *dst, lf, rf, ce; Uint8 *src, *dst, lf, rf, ce;
@ -499,8 +503,8 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
case AUDIO_S32: case AUDIO_S32:
{ {
Sint32 lf, rf, ce; Sint32 lf, rf, ce;
const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt; const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3; Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 3);
if (SDL_AUDIO_ISBIGENDIAN(format)) { if (SDL_AUDIO_ISBIGENDIAN(format)) {
for (i = cvt->len_cvt / 8; i; --i) { for (i = cvt->len_cvt / 8; i; --i) {
@ -537,8 +541,8 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
case AUDIO_F32: case AUDIO_F32:
{ {
float lf, rf, ce; float lf, rf, ce;
const float *src = (const float *) cvt->buf + cvt->len_cvt; const float *src = (const float *) (cvt->buf + cvt->len_cvt);
float *dst = (float *) cvt->buf + cvt->len_cvt * 3; float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
if (SDL_AUDIO_ISBIGENDIAN(format)) { if (SDL_AUDIO_ISBIGENDIAN(format)) {
for (i = cvt->len_cvt / 8; i; --i) { 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"); fprintf(stderr, "Converting stereo to quad\n");
#endif #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: case AUDIO_U8:
{ {
Uint8 *src, *dst, lf, rf, ce; Uint8 *src, *dst, lf, rf, ce;
@ -762,6 +768,40 @@ SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
} }
} }
break; 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; cvt->len_cvt *= 2;
if (cvt->filters[++cvt->filter_index]) { if (cvt->filters[++cvt->filter_index]) {