resampler: Refactor calc_map_table()

- Separate the cases with PA_RESAMPLER_NO_REMAP or PA_RESAMPLER_NO_REMIX
  set and remove redundant if-conditions.
- Fix C90 compiler warning due to mixing code and variable declaration.
- Do not repeatedly count number of left, right and center channels in
  the input channel map.

The logic of calc_map_table() remains unaltered.
This commit is contained in:
Stefan Huber 2013-02-07 14:03:16 +01:00 committed by Tanu Kaskinen
parent 8f009c8680
commit 1a40af9c3b

View file

@ -668,52 +668,43 @@ static void calc_map_table(pa_resampler *r) {
memset(m->map_table_i, 0, sizeof(m->map_table_i)); memset(m->map_table_i, 0, sizeof(m->map_table_i));
memset(ic_connected, 0, sizeof(ic_connected)); memset(ic_connected, 0, sizeof(ic_connected));
remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0; remix = (r->flags & (PA_RESAMPLER_NO_REMAP | PA_RESAMPLER_NO_REMIX)) == 0;
if (r->flags & PA_RESAMPLER_NO_REMAP) {
pa_assert(!remix);
for (oc = 0; oc < PA_MIN(n_ic, n_oc); oc++)
m->map_table_f[oc][oc] = 1.0f;
} else if (r->flags & PA_RESAMPLER_NO_REMIX) {
pa_assert(!remix);
for (oc = 0; oc < n_oc; oc++) { for (oc = 0; oc < n_oc; oc++) {
bool oc_connected = false;
pa_channel_position_t b = r->o_cm.map[oc]; pa_channel_position_t b = r->o_cm.map[oc];
for (ic = 0; ic < n_ic; ic++) { for (ic = 0; ic < n_ic; ic++) {
pa_channel_position_t a = r->i_cm.map[ic]; pa_channel_position_t a = r->i_cm.map[ic];
if (r->flags & PA_RESAMPLER_NO_REMAP) {
/* We shall not do any remapping. Hence, just check by index */
if (ic == oc)
m->map_table_f[oc][ic] = 1.0;
continue;
}
if (r->flags & PA_RESAMPLER_NO_REMIX) {
/* We shall not do any remixing. Hence, just check by name */ /* We shall not do any remixing. Hence, just check by name */
if (a == b) if (a == b)
m->map_table_f[oc][ic] = 1.0; m->map_table_f[oc][ic] = 1.0f;
continue;
} }
}
} else {
pa_assert(remix); /* OK, we shall do the full monty: upmixing and downmixing. Our
* algorithm is relatively simple, does not do spacialization, delay
/* OK, we shall do the full monty: upmixing and * elements or apply lowpass filters for LFE. Patches are always
* downmixing. Our algorithm is relatively simple, does * welcome, though. Oh, and it doesn't do any matrix decoding. (Which
* not do spacialization, delay elements or apply lowpass * probably wouldn't make any sense anyway.)
* filters for LFE. Patches are always welcome,
* though. Oh, and it doesn't do any matrix
* decoding. (Which probably wouldn't make any sense
* anyway.)
* *
* This code is not idempotent: downmixing an upmixed * This code is not idempotent: downmixing an upmixed stereo stream is
* stereo stream is not identical to the original. The * not identical to the original. The volume will not match, and the
* volume will not match, and the two channels will be a * two channels will be a linear combination of both.
* linear combination of both.
* *
* This is loosely based on random suggestions found on the * This is loosely based on random suggestions found on the Internet,
* Internet, such as this: * such as this:
* http://www.halfgaar.net/surround-sound-in-linux and the * http://www.halfgaar.net/surround-sound-in-linux and the alsa upmix
* alsa upmix plugin. * plugin.
* *
* The algorithm works basically like this: * The algorithm works basically like this:
* *
@ -734,44 +725,66 @@ static void calc_map_table(pa_resampler *r) {
* 5) Mix D:LFE * 5) Mix D:LFE
* If not connected, avg all S:* * If not connected, avg all S:*
* *
* 6) Make sure S:Left/S:Right is used: S:Left/S:Right: If * 6) Make sure S:Left/S:Right is used: S:Left/S:Right: If not
* not connected, mix into all D:left and all D:right * connected, mix into all D:left and all D:right channels. Gain is
* channels. Gain is 0.1, the current left and right * 0.1, the current left and right should be multiplied by 0.9.
* should be multiplied by 0.9.
* *
* 7) Make sure S:Center, S:LFE is used: * 7) Make sure S:Center, S:LFE is used:
* *
* S:Center, S:LFE: If not connected, mix into all * S:Center, S:LFE: If not connected, mix into all D:left, all
* D:left, all D:right, all D:center channels, gain is * D:right, all D:center channels, gain is 0.375. The current (as
* 0.375. The current (as result of 1..6) factors * result of 1..6) factors should be multiplied by 0.75. (Alt.
* should be multiplied by 0.75. (Alt. suggestion: 0.25 * suggestion: 0.25 vs. 0.5) If C-front is only mixed into
* vs. 0.5) If C-front is only mixed into * L-front/R-front if available, otherwise into all L/R channels.
* L-front/R-front if available, otherwise into all L/R * Similarly for C-rear.
* channels. Similarly for C-rear.
* *
* S: and D: shall relate to the source resp. destination channels. * S: and D: shall relate to the source resp. destination channels.
* *
* Rationale: 1, 2 are probably obvious. For 3: this * Rationale: 1, 2 are probably obvious. For 3: this copies front to
* copies front to rear if needed. For 4: we try to find * rear if needed. For 4: we try to find some suitable C source for C,
* some suitable C source for C, if we don't find any, we * if we don't find any, we avg L and R. For 5: LFE is mixed from all
* avg L and R. For 5: LFE is mixed from all channels. For * channels. For 6: the rear channels should not be dropped entirely,
* 6: the rear channels should not be dropped entirely, * however have only minimal impact. For 7: movies usually encode
* however have only minimal impact. For 7: movies usually * speech on the center channel. Thus we have to make sure this channel
* encode speech on the center channel. Thus we have to * is distributed to L and R if not available in the output. Also, LFE
* make sure this channel is distributed to L and R if not * is used to achieve a greater dynamic range, and thus we should try
* available in the output. Also, LFE is used to achieve a * to do our best to pass it to L+R.
* greater dynamic range, and thus we should try to do our
* best to pass it to L+R.
*/ */
unsigned
ic_left = 0,
ic_right = 0,
ic_center = 0,
ic_unconnected_left = 0,
ic_unconnected_right = 0,
ic_unconnected_center = 0,
ic_unconnected_lfe = 0;
pa_assert(remix);
for (ic = 0; ic < n_ic; ic++) {
if (on_left(r->i_cm.map[ic]))
ic_left++;
if (on_right(r->i_cm.map[ic]))
ic_right++;
if (on_center(r->i_cm.map[ic]))
ic_center++;
}
for (oc = 0; oc < n_oc; oc++) {
bool oc_connected = false;
pa_channel_position_t b = r->o_cm.map[oc];
for (ic = 0; ic < n_ic; ic++) {
pa_channel_position_t a = r->i_cm.map[ic];
if (a == b || a == PA_CHANNEL_POSITION_MONO) { if (a == b || a == PA_CHANNEL_POSITION_MONO) {
m->map_table_f[oc][ic] = 1.0; m->map_table_f[oc][ic] = 1.0f;
oc_connected = true; oc_connected = true;
ic_connected[ic] = true; ic_connected[ic] = true;
} }
else if (b == PA_CHANNEL_POSITION_MONO) { else if (b == PA_CHANNEL_POSITION_MONO) {
if (n_ic)
m->map_table_f[oc][ic] = 1.0f / (float) n_ic; m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
oc_connected = true; oc_connected = true;
@ -779,117 +792,82 @@ static void calc_map_table(pa_resampler *r) {
} }
} }
if (!oc_connected && remix) { if (!oc_connected) {
/* OK, we shall remix */
/* Try to find matching input ports for this output port */ /* Try to find matching input ports for this output port */
if (on_left(b)) { if (on_left(b)) {
unsigned n = 0;
/* We are not connected and on the left side, let's /* We are not connected and on the left side, let's
* average all left side input channels. */ * average all left side input channels. */
for (ic = 0; ic < n_ic; ic++) if (ic_left > 0)
if (on_left(r->i_cm.map[ic]))
n++;
if (n > 0)
for (ic = 0; ic < n_ic; ic++) for (ic = 0; ic < n_ic; ic++)
if (on_left(r->i_cm.map[ic])) { if (on_left(r->i_cm.map[ic])) {
m->map_table_f[oc][ic] = 1.0f / (float) n; m->map_table_f[oc][ic] = 1.0f / (float) ic_left;
ic_connected[ic] = true; ic_connected[ic] = true;
} }
/* We ignore the case where there is no left input /* We ignore the case where there is no left input channel.
* channel. Something is really wrong in this case * Something is really wrong in this case anyway. */
* anyway. */
} else if (on_right(b)) { } else if (on_right(b)) {
unsigned n = 0;
/* We are not connected and on the right side, let's /* We are not connected and on the right side, let's
* average all right side input channels. */ * average all right side input channels. */
for (ic = 0; ic < n_ic; ic++) if (ic_right > 0)
if (on_right(r->i_cm.map[ic]))
n++;
if (n > 0)
for (ic = 0; ic < n_ic; ic++) for (ic = 0; ic < n_ic; ic++)
if (on_right(r->i_cm.map[ic])) { if (on_right(r->i_cm.map[ic])) {
m->map_table_f[oc][ic] = 1.0f / (float) n; m->map_table_f[oc][ic] = 1.0f / (float) ic_right;
ic_connected[ic] = true; ic_connected[ic] = true;
} }
/* We ignore the case where there is no right input /* We ignore the case where there is no right input
* channel. Something is really wrong in this case * channel. Something is really wrong in this case anyway.
* anyway. */ * */
} else if (on_center(b)) { } else if (on_center(b)) {
unsigned n = 0;
/* We are not connected and at the center. Let's if (ic_center > 0) {
* average all center input channels. */
for (ic = 0; ic < n_ic; ic++) /* We are not connected and at the center. Let's average
if (on_center(r->i_cm.map[ic])) * all center input channels. */
n++;
if (n > 0) {
for (ic = 0; ic < n_ic; ic++) for (ic = 0; ic < n_ic; ic++)
if (on_center(r->i_cm.map[ic])) { if (on_center(r->i_cm.map[ic])) {
m->map_table_f[oc][ic] = 1.0f / (float) n; m->map_table_f[oc][ic] = 1.0f / (float) ic_center;
ic_connected[ic] = true; ic_connected[ic] = true;
} }
} else {
/* Hmm, no center channel around, let's synthesize } else if (ic_left + ic_right > 0) {
* it by mixing L and R.*/
n = 0; /* Hmm, no center channel around, let's synthesize it
* by mixing L and R.*/
for (ic = 0; ic < n_ic; ic++)
if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic]))
n++;
if (n > 0)
for (ic = 0; ic < n_ic; ic++) for (ic = 0; ic < n_ic; ic++)
if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) {
m->map_table_f[oc][ic] = 1.0f / (float) n; m->map_table_f[oc][ic] = 1.0f / (float) (ic_left + ic_right);
ic_connected[ic] = true; ic_connected[ic] = true;
} }
/* We ignore the case where there is not even a
* left or right input channel. Something is
* really wrong in this case anyway. */
} }
} else if (on_lfe(b)) { /* We ignore the case where there is not even a left or
* right input channel. Something is really wrong in this
* case anyway. */
} else if (on_lfe(b) && !(r->flags & PA_RESAMPLER_NO_LFE)) {
/* We are not connected and an LFE. Let's average all /* We are not connected and an LFE. Let's average all
* channels for LFE. */ * channels for LFE. */
for (ic = 0; ic < n_ic; ic++) { for (ic = 0; ic < n_ic; ic++)
if (!(r->flags & PA_RESAMPLER_NO_LFE))
m->map_table_f[oc][ic] = 1.0f / (float) n_ic; m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
else
m->map_table_f[oc][ic] = 0;
/* Please note that a channel connected to LFE /* Please note that a channel connected to LFE doesn't
* doesn't really count as connected. */ * really count as connected. */
} }
} }
} }
}
if (remix) {
unsigned
ic_unconnected_left = 0,
ic_unconnected_right = 0,
ic_unconnected_center = 0,
ic_unconnected_lfe = 0;
for (ic = 0; ic < n_ic; ic++) { for (ic = 0; ic < n_ic; ic++) {
pa_channel_position_t a = r->i_cm.map[ic]; pa_channel_position_t a = r->i_cm.map[ic];
@ -909,10 +887,9 @@ static void calc_map_table(pa_resampler *r) {
if (ic_unconnected_left > 0) { if (ic_unconnected_left > 0) {
/* OK, so there are unconnected input channels on the /* OK, so there are unconnected input channels on the left. Let's
* left. Let's multiply all already connected channels on * multiply all already connected channels on the left side by .9
* the left side by .9 and add in our averaged unconnected * and add in our averaged unconnected channels multiplied by .1 */
* channels multiplied by .1 */
for (oc = 0; oc < n_oc; oc++) { for (oc = 0; oc < n_oc; oc++) {
@ -934,10 +911,9 @@ static void calc_map_table(pa_resampler *r) {
if (ic_unconnected_right > 0) { if (ic_unconnected_right > 0) {
/* OK, so there are unconnected input channels on the /* OK, so there are unconnected input channels on the right. Let's
* right. Let's multiply all already connected channels on * multiply all already connected channels on the right side by .9
* the right side by .9 and add in our averaged unconnected * and add in our averaged unconnected channels multiplied by .1 */
* channels multiplied by .1 */
for (oc = 0; oc < n_oc; oc++) { for (oc = 0; oc < n_oc; oc++) {
@ -960,10 +936,9 @@ static void calc_map_table(pa_resampler *r) {
if (ic_unconnected_center > 0) { if (ic_unconnected_center > 0) {
bool mixed_in = false; bool mixed_in = false;
/* OK, so there are unconnected input channels on the /* OK, so there are unconnected input channels on the center. Let's
* center. Let's multiply all already connected channels on * multiply all already connected channels on the center side by .9
* the center side by .9 and add in our averaged unconnected * and add in our averaged unconnected channels multiplied by .1 */
* channels multiplied by .1 */
for (oc = 0; oc < n_oc; oc++) { for (oc = 0; oc < n_oc; oc++) {
@ -992,9 +967,8 @@ static void calc_map_table(pa_resampler *r) {
memset(found_frs, 0, sizeof(found_frs)); memset(found_frs, 0, sizeof(found_frs));
/* Hmm, as it appears there was no center channel we /* Hmm, as it appears there was no center channel we
could mix our center channel in. In this case, mix could mix our center channel in. In this case, mix it into
it into left and right. Using .375 and 0.75 as left and right. Using .375 and 0.75 as factors. */
factors. */
for (ic = 0; ic < n_ic; ic++) { for (ic = 0; ic < n_ic; ic++) {
@ -1052,8 +1026,8 @@ static void calc_map_table(pa_resampler *r) {
if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) { if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) {
/* OK, so there is an unconnected LFE channel. Let's mix /* OK, so there is an unconnected LFE channel. Let's mix it into
* it into all channels, with factor 0.375 */ * all channels, with factor 0.375 */
for (ic = 0; ic < n_ic; ic++) { for (ic = 0; ic < n_ic; ic++) {
@ -1065,6 +1039,7 @@ static void calc_map_table(pa_resampler *r) {
} }
} }
} }
/* make an 16:16 int version of the matrix */ /* make an 16:16 int version of the matrix */
for (oc = 0; oc < n_oc; oc++) for (oc = 0; oc < n_oc; oc++)
for (ic = 0; ic < n_ic; ic++) for (ic = 0; ic < n_ic; ic++)