audio: Improvements in channel conversion code.

This commit is contained in:
Ryan C. Gordon
2017-01-08 16:18:49 -05:00
parent 35166609d5
commit 38854e0333
2 changed files with 48 additions and 40 deletions

View File

@@ -31,7 +31,7 @@
/* Effectively mix right and left channels into a single channel */
static void SDLCALL
SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
@@ -51,20 +51,22 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
/* Discard top 4 channels */
/* Convert from 5.1 to stereo. Average left and right, discard subwoofer. */
static void SDLCALL
SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6 channels", "stereo");
LOG_DEBUG_CONVERT("5.1", "stereo");
SDL_assert(format == AUDIO_F32SYS);
/* this assumes FL+FR+FC+subwoof+BL+BR layout. */
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
dst[0] = src[0];
dst[1] = src[1];
const double front_center = (double) src[2];
dst[0] = (float) ((src[0] + front_center + src[4]) / 3.0); /* left */
dst[1] = (float) ((src[1] + front_center + src[5]) / 3.0); /* right */
}
cvt->len_cvt /= 3;
@@ -74,22 +76,25 @@ SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
/* Discard top 2 channels of 6 */
/* Convert from 5.1 to quad */
static void SDLCALL
SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6 channels", "quad");
LOG_DEBUG_CONVERT("5.1", "quad");
SDL_assert(format == AUDIO_F32SYS);
/* assumes quad is FL+FR+BL+BR layout and 5.1 is FL+FR+FC+subwoof+BL+BR */
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
/* FIXME: this is a good candidate for SIMD. */
const double front_center = (double) src[2];
dst[0] = (float) ((src[0] + front_center) * 0.5); /* FL */
dst[1] = (float) ((src[1] + front_center) * 0.5); /* FR */
dst[2] = (float) ((src[4] + front_center) * 0.5); /* BL */
dst[3] = (float) ((src[5] + front_center) * 0.5); /* BR */
}
cvt->len_cvt /= 6;
@@ -99,9 +104,10 @@ SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
}
/* Duplicate a mono channel to both stereo channels */
static void SDLCALL
SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
@@ -125,7 +131,7 @@ SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
/* Duplicate a stereo channel to a pseudo-5.1 stream */
static void SDLCALL
SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
int i;
float lf, rf, ce;
@@ -140,12 +146,13 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
src -= 2;
lf = src[0];
rf = src[1];
ce = (lf * 0.5f) + (rf * 0.5f);
dst[0] = src[0];
dst[1] = src[1];
dst[2] = lf - ce;
dst[3] = rf - ce;
dst[4] = dst[5] = ce;
ce = (lf + rf) * 0.5f;
dst[0] = lf + (lf - ce); /* FL */
dst[1] = rf + (rf - ce); /* FR */
dst[2] = ce; /* FC */
dst[3] = ce; /* !!! FIXME: wrong! This is the subwoofer. */
dst[4] = lf; /* BL */
dst[5] = rf; /* BR */
}
cvt->len_cvt *= 3;
@@ -157,11 +164,11 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
/* Duplicate a stereo channel to a pseudo-4.0 stream */
static void SDLCALL
SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
float lf, rf, ce;
float lf, rf;
int i;
LOG_DEBUG_CONVERT("stereo", "quad");
@@ -172,11 +179,10 @@ SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
src -= 2;
lf = src[0];
rf = src[1];
ce = (lf / 2) + (rf / 2);
dst[0] = src[0];
dst[1] = src[1];
dst[2] = lf - ce;
dst[3] = rf - ce;
dst[0] = lf; /* FL */
dst[1] = rf; /* FR */
dst[2] = lf; /* BL */
dst[3] = rf; /* BR */
}
cvt->len_cvt *= 2;
@@ -536,36 +542,36 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
/* Channel conversion */
if (src_channels != dst_channels) {
if ((src_channels == 1) && (dst_channels > 1)) {
cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
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;
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
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;
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
src_channels = 4;
cvt->len_mult *= 2;
cvt->len_ratio *= 2;
}
while ((src_channels * 2) <= dst_channels) {
cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
cvt->len_mult *= 2;
src_channels *= 2;
cvt->len_ratio *= 2;
}
if ((src_channels == 6) && (dst_channels <= 2)) {
cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
src_channels = 2;
cvt->len_ratio /= 3;
}
if ((src_channels == 6) && (dst_channels == 4)) {
cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
src_channels = 4;
cvt->len_ratio /= 2;
}
@@ -575,7 +581,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
*/
while (((src_channels % 2) == 0) &&
((src_channels / 2) >= dst_channels)) {
cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToMono;
src_channels /= 2;
cvt->len_ratio /= 2;
}