diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index c90512af1..3abe64b1b 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -391,6 +391,8 @@ int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained) switch ( desired->channels ) { case 1: /* Mono */ case 2: /* Stereo */ + case 4: /* surround */ + case 6: /* surround with center and lfe */ break; default: SDL_SetError("1 (mono) and 2 (stereo) channels supported"); diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 82a514a04..ead404eef 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -175,6 +175,244 @@ void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format) } } +/* Discard top 4 channels */ +void SDL_ConvertStrip(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Sint32 lsample, rsample; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting down to stereo\n"); +#endif + switch (format&0x8018) { + + case AUDIO_U8: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + for ( i=cvt->len_cvt/6; i; --i ) { + lsample = src[0]; + rsample = src[1]; + dst[0] = lsample; + dst[1] = rsample; + src += 6; + dst += 2; + } + } + break; + + case AUDIO_S8: { + Sint8 *src, *dst; + + src = (Sint8 *)cvt->buf; + dst = (Sint8 *)cvt->buf; + for ( i=cvt->len_cvt/6; i; --i ) { + lsample = src[0]; + rsample = src[1]; + dst[0] = lsample; + dst[1] = rsample; + src += 6; + dst += 2; + } + } + break; + + case AUDIO_U16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/12; i; --i ) { + lsample = (Uint16)((src[0]<<8)|src[1]); + rsample = (Uint16)((src[2]<<8)|src[3]); + dst[1] = (lsample&0xFF); + lsample >>= 8; + dst[0] = (lsample&0xFF); + dst[3] = (rsample&0xFF); + rsample >>= 8; + dst[2] = (rsample&0xFF); + src += 12; + dst += 4; + } + } else { + for ( i=cvt->len_cvt/12; i; --i ) { + lsample = (Uint16)((src[1]<<8)|src[0]); + rsample = (Uint16)((src[3]<<8)|src[2]); + dst[0] = (lsample&0xFF); + lsample >>= 8; + dst[1] = (lsample&0xFF); + dst[2] = (rsample&0xFF); + rsample >>= 8; + dst[3] = (rsample&0xFF); + src += 12; + dst += 4; + } + } + } + break; + + case AUDIO_S16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/12; i; --i ) { + lsample = (Sint16)((src[0]<<8)|src[1]); + rsample = (Sint16)((src[2]<<8)|src[3]); + dst[1] = (lsample&0xFF); + lsample >>= 8; + dst[0] = (lsample&0xFF); + dst[3] = (rsample&0xFF); + rsample >>= 8; + dst[2] = (rsample&0xFF); + src += 12; + dst += 4; + } + } else { + for ( i=cvt->len_cvt/12; i; --i ) { + lsample = (Sint16)((src[1]<<8)|src[0]); + rsample = (Sint16)((src[3]<<8)|src[2]); + dst[0] = (lsample&0xFF); + lsample >>= 8; + dst[1] = (lsample&0xFF); + dst[2] = (rsample&0xFF); + rsample >>= 8; + dst[3] = (rsample&0xFF); + src += 12; + dst += 4; + } + } + } + break; + } + cvt->len_cvt /= 3; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + +/* Discard top 2 channels of 6 */ +void SDL_ConvertStrip_2(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Sint32 lsample, rsample; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting 6 down to quad\n"); +#endif + switch (format&0x8018) { + + case AUDIO_U8: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + for ( i=cvt->len_cvt/4; i; --i ) { + lsample = src[0]; + rsample = src[1]; + dst[0] = lsample; + dst[1] = rsample; + src += 4; + dst += 2; + } + } + break; + + case AUDIO_S8: { + Sint8 *src, *dst; + + src = (Sint8 *)cvt->buf; + dst = (Sint8 *)cvt->buf; + for ( i=cvt->len_cvt/4; i; --i ) { + lsample = src[0]; + rsample = src[1]; + dst[0] = lsample; + dst[1] = rsample; + src += 4; + dst += 2; + } + } + break; + + case AUDIO_U16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/8; i; --i ) { + lsample = (Uint16)((src[0]<<8)|src[1]); + rsample = (Uint16)((src[2]<<8)|src[3]); + dst[1] = (lsample&0xFF); + lsample >>= 8; + dst[0] = (lsample&0xFF); + dst[3] = (rsample&0xFF); + rsample >>= 8; + dst[2] = (rsample&0xFF); + src += 8; + dst += 4; + } + } else { + for ( i=cvt->len_cvt/8; i; --i ) { + lsample = (Uint16)((src[1]<<8)|src[0]); + rsample = (Uint16)((src[3]<<8)|src[2]); + dst[0] = (lsample&0xFF); + lsample >>= 8; + dst[1] = (lsample&0xFF); + dst[2] = (rsample&0xFF); + rsample >>= 8; + dst[3] = (rsample&0xFF); + src += 8; + dst += 4; + } + } + } + break; + + case AUDIO_S16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/8; i; --i ) { + lsample = (Sint16)((src[0]<<8)|src[1]); + rsample = (Sint16)((src[2]<<8)|src[3]); + dst[1] = (lsample&0xFF); + lsample >>= 8; + dst[0] = (lsample&0xFF); + dst[3] = (rsample&0xFF); + rsample >>= 8; + dst[2] = (rsample&0xFF); + src += 8; + dst += 4; + } + } else { + for ( i=cvt->len_cvt/8; i; --i ) { + lsample = (Sint16)((src[1]<<8)|src[0]); + rsample = (Sint16)((src[3]<<8)|src[2]); + dst[0] = (lsample&0xFF); + lsample >>= 8; + dst[1] = (lsample&0xFF); + dst[2] = (rsample&0xFF); + rsample >>= 8; + dst[3] = (rsample&0xFF); + src += 8; + dst += 4; + } + } + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} /* Duplicate a mono channel to both stereo channels */ void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format) @@ -213,6 +451,337 @@ void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format) } } + +/* Duplicate a stereo channel to a pseudo-5.1 stream */ +void SDL_ConvertSurround(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting stereo to surround\n"); +#endif + switch (format&0x8018) { + + case AUDIO_U8: { + Uint8 *src, *dst, lf, rf, ce; + + src = (Uint8 *)(cvt->buf+cvt->len_cvt); + dst = (Uint8 *)(cvt->buf+cvt->len_cvt*3); + for ( i=cvt->len_cvt; i; --i ) { + dst -= 6; + src -= 2; + lf = src[0]; + rf = src[1]; + ce = (lf/2) + (rf/2); + dst[0] = lf; + dst[1] = rf; + dst[2] = lf - ce; + dst[3] = rf - ce; + dst[4] = ce; + dst[5] = ce; + } + } + break; + + case AUDIO_S8: { + Sint8 *src, *dst, lf, rf, ce; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*3; + for ( i=cvt->len_cvt; i; --i ) { + dst -= 6; + src -= 2; + lf = src[0]; + rf = src[1]; + ce = (lf/2) + (rf/2); + dst[0] = lf; + dst[1] = rf; + dst[2] = lf - ce; + dst[3] = rf - ce; + dst[4] = ce; + dst[5] = ce; + } + } + break; + + case AUDIO_U16: { + Uint8 *src, *dst; + Uint16 lf, rf, ce, lr, rr; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*3; + + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 12; + src -= 4; + lf = (Uint16)((src[0]<<8)|src[1]); + rf = (Uint16)((src[2]<<8)|src[3]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[1] = (lf&0xFF); + dst[0] = ((lf>>8)&0xFF); + dst[3] = (rf&0xFF); + dst[2] = ((rf>>8)&0xFF); + + dst[1+4] = (lr&0xFF); + dst[0+4] = ((lr>>8)&0xFF); + dst[3+4] = (rr&0xFF); + dst[2+4] = ((rr>>8)&0xFF); + + dst[1+8] = (ce&0xFF); + dst[0+8] = ((ce>>8)&0xFF); + dst[3+8] = (ce&0xFF); + dst[2+8] = ((ce>>8)&0xFF); + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 12; + src -= 4; + lf = (Uint16)((src[1]<<8)|src[0]); + rf = (Uint16)((src[3]<<8)|src[2]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[0] = (lf&0xFF); + dst[1] = ((lf>>8)&0xFF); + dst[2] = (rf&0xFF); + dst[3] = ((rf>>8)&0xFF); + + dst[0+4] = (lr&0xFF); + dst[1+4] = ((lr>>8)&0xFF); + dst[2+4] = (rr&0xFF); + dst[3+4] = ((rr>>8)&0xFF); + + dst[0+8] = (ce&0xFF); + dst[1+8] = ((ce>>8)&0xFF); + dst[2+8] = (ce&0xFF); + dst[3+8] = ((ce>>8)&0xFF); + } + } + } + break; + + case AUDIO_S16: { + Uint8 *src, *dst; + Sint16 lf, rf, ce, lr, rr; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*3; + + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 12; + src -= 4; + lf = (Sint16)((src[0]<<8)|src[1]); + rf = (Sint16)((src[2]<<8)|src[3]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[1] = (lf&0xFF); + dst[0] = ((lf>>8)&0xFF); + dst[3] = (rf&0xFF); + dst[2] = ((rf>>8)&0xFF); + + dst[1+4] = (lr&0xFF); + dst[0+4] = ((lr>>8)&0xFF); + dst[3+4] = (rr&0xFF); + dst[2+4] = ((rr>>8)&0xFF); + + dst[1+8] = (ce&0xFF); + dst[0+8] = ((ce>>8)&0xFF); + dst[3+8] = (ce&0xFF); + dst[2+8] = ((ce>>8)&0xFF); + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 12; + src -= 4; + lf = (Sint16)((src[1]<<8)|src[0]); + rf = (Sint16)((src[3]<<8)|src[2]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[0] = (lf&0xFF); + dst[1] = ((lf>>8)&0xFF); + dst[2] = (rf&0xFF); + dst[3] = ((rf>>8)&0xFF); + + dst[0+4] = (lr&0xFF); + dst[1+4] = ((lr>>8)&0xFF); + dst[2+4] = (rr&0xFF); + dst[3+4] = ((rr>>8)&0xFF); + + dst[0+8] = (ce&0xFF); + dst[1+8] = ((ce>>8)&0xFF); + dst[2+8] = (ce&0xFF); + dst[3+8] = ((ce>>8)&0xFF); + } + } + } + break; + } + cvt->len_cvt *= 3; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + +/* Duplicate a stereo channel to a pseudo-4.0 stream */ +void SDL_ConvertSurround_4(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting stereo to quad\n"); +#endif + switch (format&0x8018) { + + case AUDIO_U8: { + Uint8 *src, *dst, lf, rf, ce; + + src = (Uint8 *)(cvt->buf+cvt->len_cvt); + dst = (Uint8 *)(cvt->buf+cvt->len_cvt*2); + for ( i=cvt->len_cvt; i; --i ) { + dst -= 4; + src -= 2; + lf = src[0]; + rf = src[1]; + ce = (lf/2) + (rf/2); + dst[0] = lf; + dst[1] = rf; + dst[2] = lf - ce; + dst[3] = rf - ce; + } + } + break; + + case AUDIO_S8: { + Sint8 *src, *dst, lf, rf, ce; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + for ( i=cvt->len_cvt; i; --i ) { + dst -= 4; + src -= 2; + lf = src[0]; + rf = src[1]; + ce = (lf/2) + (rf/2); + dst[0] = lf; + dst[1] = rf; + dst[2] = lf - ce; + dst[3] = rf - ce; + } + } + break; + + case AUDIO_U16: { + Uint8 *src, *dst; + Uint16 lf, rf, ce, lr, rr; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 8; + src -= 4; + lf = (Uint16)((src[0]<<8)|src[1]); + rf = (Uint16)((src[2]<<8)|src[3]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[1] = (lf&0xFF); + dst[0] = ((lf>>8)&0xFF); + dst[3] = (rf&0xFF); + dst[2] = ((rf>>8)&0xFF); + + dst[1+4] = (lr&0xFF); + dst[0+4] = ((lr>>8)&0xFF); + dst[3+4] = (rr&0xFF); + dst[2+4] = ((rr>>8)&0xFF); + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 8; + src -= 4; + lf = (Uint16)((src[1]<<8)|src[0]); + rf = (Uint16)((src[3]<<8)|src[2]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[0] = (lf&0xFF); + dst[1] = ((lf>>8)&0xFF); + dst[2] = (rf&0xFF); + dst[3] = ((rf>>8)&0xFF); + + dst[0+4] = (lr&0xFF); + dst[1+4] = ((lr>>8)&0xFF); + dst[2+4] = (rr&0xFF); + dst[3+4] = ((rr>>8)&0xFF); + } + } + } + break; + + case AUDIO_S16: { + Uint8 *src, *dst; + Sint16 lf, rf, ce, lr, rr; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 8; + src -= 4; + lf = (Sint16)((src[0]<<8)|src[1]); + rf = (Sint16)((src[2]<<8)|src[3]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[1] = (lf&0xFF); + dst[0] = ((lf>>8)&0xFF); + dst[3] = (rf&0xFF); + dst[2] = ((rf>>8)&0xFF); + + dst[1+4] = (lr&0xFF); + dst[0+4] = ((lr>>8)&0xFF); + dst[3+4] = (rr&0xFF); + dst[2+4] = ((rr>>8)&0xFF); + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + dst -= 8; + src -= 4; + lf = (Sint16)((src[1]<<8)|src[0]); + rf = (Sint16)((src[3]<<8)|src[2]); + ce = (lf/2) + (rf/2); + rr = lf - ce; + lr = rf - ce; + dst[0] = (lf&0xFF); + dst[1] = ((lf>>8)&0xFF); + dst[2] = (rf&0xFF); + dst[3] = ((rf>>8)&0xFF); + + dst[0+4] = (lr&0xFF); + dst[1+4] = ((lr>>8)&0xFF); + dst[2+4] = (rr&0xFF); + dst[3+4] = ((rr>>8)&0xFF); + } + } + } + break; + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + /* Convert 8-bit to 16-bit - LSB */ void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format) { @@ -374,6 +943,173 @@ void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format) } } + +/* Convert rate up by multiple of 2, for stereo */ +void SDL_RateMUL2_c2(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate * 2\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/2; i; --i ) { + src -= 2; + dst -= 4; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[0]; + dst[3] = src[1]; + } + break; + case 16: + for ( i=cvt->len_cvt/4; i; --i ) { + src -= 4; + dst -= 8; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[0]; + dst[5] = src[1]; + dst[6] = src[2]; + dst[7] = src[3]; + } + break; + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert rate up by multiple of 2, for quad */ +void SDL_RateMUL2_c4(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate * 2\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/4; i; --i ) { + src -= 4; + dst -= 8; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[0]; + dst[5] = src[1]; + dst[6] = src[2]; + dst[7] = src[3]; + } + break; + case 16: + for ( i=cvt->len_cvt/8; i; --i ) { + src -= 8; + dst -= 16; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[0]; + dst[9] = src[1]; + dst[10] = src[2]; + dst[11] = src[3]; + dst[12] = src[4]; + dst[13] = src[5]; + dst[14] = src[6]; + dst[15] = src[7]; + } + break; + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + +/* Convert rate up by multiple of 2, for 5.1 */ +void SDL_RateMUL2_c6(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate * 2\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/6; i; --i ) { + src -= 6; + dst -= 12; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[0]; + dst[7] = src[1]; + dst[8] = src[2]; + dst[9] = src[3]; + dst[10] = src[4]; + dst[11] = src[5]; + } + break; + case 16: + for ( i=cvt->len_cvt/12; i; --i ) { + src -= 12; + dst -= 24; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[8]; + dst[9] = src[9]; + dst[10] = src[10]; + dst[11] = src[11]; + dst[12] = src[0]; + dst[13] = src[1]; + dst[14] = src[2]; + dst[15] = src[3]; + dst[16] = src[4]; + dst[17] = src[5]; + dst[18] = src[6]; + dst[19] = src[7]; + dst[20] = src[8]; + dst[21] = src[9]; + dst[22] = src[10]; + dst[23] = src[11]; + } + break; + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + /* Convert rate down by multiple of 2 */ void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format) { @@ -408,6 +1144,137 @@ void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format) } } + +/* Convert rate down by multiple of 2, for stereo */ +void SDL_RateDIV2_c2(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate / 2\n"); +#endif + src = cvt->buf; + dst = cvt->buf; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/4; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + src += 4; + dst += 2; + } + break; + case 16: + for ( i=cvt->len_cvt/8; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + src += 8; + dst += 4; + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + +/* Convert rate down by multiple of 2, for quad */ +void SDL_RateDIV2_c4(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate / 2\n"); +#endif + src = cvt->buf; + dst = cvt->buf; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/8; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + src += 8; + dst += 4; + } + break; + case 16: + for ( i=cvt->len_cvt/16; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + src += 16; + dst += 8; + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert rate down by multiple of 2, for 5.1 */ +void SDL_RateDIV2_c6(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate / 2\n"); +#endif + src = cvt->buf; + dst = cvt->buf; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/12; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + src += 12; + dst += 6; + } + break; + case 16: + for ( i=cvt->len_cvt/24; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[8]; + dst[9] = src[9]; + dst[10] = src[10]; + dst[11] = src[11]; + src += 24; + dst += 12; + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + /* Very slow rate conversion routine */ void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format) { @@ -511,6 +1378,8 @@ int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, Uint16 src_format, Uint8 src_channels, int src_rate, Uint16 dst_format, Uint8 dst_channels, int dst_rate) { +/*printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n", + src_format, dst_format, src_channels, dst_channels, src_rate, dst_rate);*/ /* Start off with no conversion necessary */ cvt->needed = 0; cvt->filter_index = 0; @@ -554,6 +1423,29 @@ int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, /* Last filter: Mono/Stereo conversion */ if ( src_channels != dst_channels ) { + if ( (src_channels == 1) && (dst_channels > 1) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertStereo; + cvt->len_mult *= 2; + src_channels = 2; + cvt->len_ratio *= 2; + } + if ( (src_channels == 2) && + (dst_channels == 6) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertSurround; + src_channels = 6; + cvt->len_mult *= 3; + cvt->len_ratio *= 3; + } + if ( (src_channels == 2) && + (dst_channels == 4) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertSurround_4; + src_channels = 4; + cvt->len_mult *= 2; + cvt->len_ratio *= 2; + } while ( (src_channels*2) <= dst_channels ) { cvt->filters[cvt->filter_index++] = SDL_ConvertStereo; @@ -561,6 +1453,20 @@ int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, src_channels *= 2; cvt->len_ratio *= 2; } + if ( (src_channels == 6) && + (dst_channels <= 2) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertStrip; + src_channels = 2; + cvt->len_ratio /= 3; + } + if ( (src_channels == 6) && + (dst_channels == 4) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertStrip_2; + src_channels = 4; + cvt->len_ratio /= 2; + } /* This assumes that 4 channel audio is in the format: Left {front/back} + Right {front/back} so converting to L/R stereo works properly. @@ -588,13 +1494,25 @@ int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, if ( src_rate > dst_rate ) { hi_rate = src_rate; lo_rate = dst_rate; - rate_cvt = SDL_RateDIV2; + switch (src_channels) { + case 1: rate_cvt = SDL_RateDIV2; break; + case 2: rate_cvt = SDL_RateDIV2_c2; break; + case 4: rate_cvt = SDL_RateDIV2_c4; break; + case 6: rate_cvt = SDL_RateDIV2_c6; break; + default: return -1; + } len_mult = 1; len_ratio = 0.5; } else { hi_rate = dst_rate; lo_rate = src_rate; - rate_cvt = SDL_RateMUL2; + switch (src_channels) { + case 1: rate_cvt = SDL_RateMUL2; break; + case 2: rate_cvt = SDL_RateMUL2_c2; break; + case 4: rate_cvt = SDL_RateMUL2_c4; break; + case 6: rate_cvt = SDL_RateMUL2_c6; break; + default: return -1; + } len_mult = 2; len_ratio = 2.0; } diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index bc7e4634d..fa1771bee 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -163,13 +163,15 @@ static int LoadALSALibrary(void) { #endif /* ALSA_DYNAMIC */ -static const char *get_audio_device() +static const char *get_audio_device(int channels) { const char *device; device = getenv("AUDIODEV"); /* Is there a standard variable name? */ if ( device == NULL ) { - device = DEFAULT_DEVICE; + if (channels == 6) device = "surround51"; + else if (channels == 4) device = "surround40"; + else device = DEFAULT_DEVICE; } return device; } @@ -186,7 +188,7 @@ static int Audio_Available(void) if (LoadALSALibrary() < 0) { return available; } - status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if ( status >= 0 ) { available = 1; SDL_NAME(snd_pcm_close)(handle); @@ -319,7 +321,9 @@ static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec) Uint16 test_format; /* Open the audio device */ - status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + /* Name of device should depend on # channels in spec */ + status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + if ( status < 0 ) { SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status)); return(-1);