mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
resampler: Flag for remixing to all sink channels.
Add a flag PA_RESAMPLER_NO_FILL_SINK, which controls whether remixing should attempt to use all sink channels, versus only the ones needed to reproduce the source audio. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=62588 BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=94563 Suggested-by: Alexander E. Patrakov <patrakov@gmail.com>
This commit is contained in:
parent
e2968b5738
commit
21c3570b12
2 changed files with 75 additions and 10 deletions
|
|
@ -796,6 +796,64 @@ static int front_rear_side(pa_channel_position_t p) {
|
||||||
return ON_OTHER;
|
return ON_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fill a map of which output channels should get mono from input, not including
|
||||||
|
* LFE output channels. (The LFE output channels are mapped separately.)
|
||||||
|
*/
|
||||||
|
static void setup_oc_mono_map(const pa_resampler *r, float *oc_mono_map) {
|
||||||
|
unsigned oc;
|
||||||
|
unsigned n_oc;
|
||||||
|
bool found_oc_for_mono = false;
|
||||||
|
|
||||||
|
pa_assert(r);
|
||||||
|
pa_assert(oc_mono_map);
|
||||||
|
|
||||||
|
n_oc = r->o_ss.channels;
|
||||||
|
|
||||||
|
if (!(r->flags & PA_RESAMPLER_NO_FILL_SINK)) {
|
||||||
|
/* Mono goes to all non-LFE output channels and we're done. */
|
||||||
|
for (oc = 0; oc < n_oc; oc++)
|
||||||
|
oc_mono_map[oc] = on_lfe(r->o_cm.map[oc]) ? 0.0f : 1.0f;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* Initialize to all zero so we can select individual channels below. */
|
||||||
|
for (oc = 0; oc < n_oc; oc++)
|
||||||
|
oc_mono_map[oc] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (oc = 0; oc < n_oc; oc++) {
|
||||||
|
if (r->o_cm.map[oc] == PA_CHANNEL_POSITION_MONO) {
|
||||||
|
oc_mono_map[oc] = 1.0f;
|
||||||
|
found_oc_for_mono = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_oc_for_mono)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (oc = 0; oc < n_oc; oc++) {
|
||||||
|
if (r->o_cm.map[oc] == PA_CHANNEL_POSITION_FRONT_CENTER) {
|
||||||
|
oc_mono_map[oc] = 1.0f;
|
||||||
|
found_oc_for_mono = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_oc_for_mono)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (oc = 0; oc < n_oc; oc++) {
|
||||||
|
if (r->o_cm.map[oc] == PA_CHANNEL_POSITION_FRONT_LEFT || r->o_cm.map[oc] == PA_CHANNEL_POSITION_FRONT_RIGHT) {
|
||||||
|
oc_mono_map[oc] = 1.0f;
|
||||||
|
found_oc_for_mono = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_oc_for_mono)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Give up on finding a suitable map for mono, and just send it to all
|
||||||
|
* non-LFE output channels.
|
||||||
|
*/
|
||||||
|
for (oc = 0; oc < n_oc; oc++)
|
||||||
|
oc_mono_map[oc] = on_lfe(r->o_cm.map[oc]) ? 0.0f : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed) {
|
static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed) {
|
||||||
unsigned oc, ic;
|
unsigned oc, ic;
|
||||||
unsigned n_oc, n_ic;
|
unsigned n_oc, n_ic;
|
||||||
|
|
@ -858,14 +916,14 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
* 1) Connect all channels with matching names.
|
* 1) Connect all channels with matching names.
|
||||||
*
|
*
|
||||||
* 2) Mono Handling:
|
* 2) Mono Handling:
|
||||||
* S:Mono: Copy into all D:channels
|
* S:Mono: See setup_oc_mono_map().
|
||||||
* D:Mono: Avg all S:channels
|
* D:Mono: Avg all S:channels
|
||||||
*
|
*
|
||||||
* 3) Mix D:Left, D:Right:
|
* 3) Mix D:Left, D:Right (if PA_RESAMPLER_NO_FILL_SINK is clear):
|
||||||
* D:Left: If not connected, avg all S:Left
|
* D:Left: If not connected, avg all S:Left
|
||||||
* D:Right: If not connected, avg all S:Right
|
* D:Right: If not connected, avg all S:Right
|
||||||
*
|
*
|
||||||
* 4) Mix D:Center
|
* 4) Mix D:Center (if PA_RESAMPLER_NO_FILL_SINK is clear):
|
||||||
* If not connected, avg all S:Center
|
* If not connected, avg all S:Center
|
||||||
* If still not connected, avg all S:Left, S:Right
|
* If still not connected, avg all S:Left, S:Right
|
||||||
*
|
*
|
||||||
|
|
@ -908,6 +966,7 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
ic_unconnected_center = 0,
|
ic_unconnected_center = 0,
|
||||||
ic_unconnected_lfe = 0;
|
ic_unconnected_lfe = 0;
|
||||||
bool ic_unconnected_center_mixed_in = 0;
|
bool ic_unconnected_center_mixed_in = 0;
|
||||||
|
float oc_mono_map[PA_CHANNELS_MAX];
|
||||||
|
|
||||||
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]))
|
||||||
|
|
@ -918,6 +977,8 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
ic_center++;
|
ic_center++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_oc_mono_map(r, oc_mono_map);
|
||||||
|
|
||||||
for (oc = 0; oc < n_oc; oc++) {
|
for (oc = 0; oc < n_oc; oc++) {
|
||||||
bool oc_connected = false;
|
bool oc_connected = false;
|
||||||
pa_channel_position_t b = r->o_cm.map[oc];
|
pa_channel_position_t b = r->o_cm.map[oc];
|
||||||
|
|
@ -925,14 +986,17 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
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 (a == b || a == PA_CHANNEL_POSITION_MONO) {
|
if (a == b) {
|
||||||
m->map_table_f[oc][ic] = 1.0f;
|
m->map_table_f[oc][ic] = 1.0f;
|
||||||
|
|
||||||
oc_connected = true;
|
oc_connected = true;
|
||||||
ic_connected[ic] = true;
|
ic_connected[ic] = true;
|
||||||
|
}
|
||||||
|
else if (a == PA_CHANNEL_POSITION_MONO && oc_mono_map[oc] > 0.0f) {
|
||||||
|
m->map_table_f[oc][ic] = oc_mono_map[oc];
|
||||||
|
|
||||||
if (a == PA_CHANNEL_POSITION_MONO && on_lfe(b) && !(r->flags & PA_RESAMPLER_NO_LFE))
|
oc_connected = true;
|
||||||
*lfe_remixed = true;
|
ic_connected[ic] = true;
|
||||||
}
|
}
|
||||||
else if (b == PA_CHANNEL_POSITION_MONO) {
|
else if (b == PA_CHANNEL_POSITION_MONO) {
|
||||||
m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
|
m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
|
||||||
|
|
@ -945,7 +1009,7 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
if (!oc_connected) {
|
if (!oc_connected) {
|
||||||
/* 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) && !(r->flags & PA_RESAMPLER_NO_FILL_SINK)) {
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
|
@ -960,7 +1024,7 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
/* We ignore the case where there is no left input channel.
|
/* We ignore the case where there is no left input channel.
|
||||||
* Something is really wrong in this case anyway. */
|
* Something is really wrong in this case anyway. */
|
||||||
|
|
||||||
} else if (on_right(b)) {
|
} else if (on_right(b) && !(r->flags & PA_RESAMPLER_NO_FILL_SINK)) {
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
|
@ -976,7 +1040,7 @@ static void setup_remap(const pa_resampler *r, pa_remap_t *m, bool *lfe_remixed)
|
||||||
* channel. Something is really wrong in this case anyway.
|
* channel. Something is really wrong in this case anyway.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
} else if (on_center(b)) {
|
} else if (on_center(b) && !(r->flags & PA_RESAMPLER_NO_FILL_SINK)) {
|
||||||
|
|
||||||
if (ic_center > 0) {
|
if (ic_center > 0) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ typedef enum pa_resample_flags {
|
||||||
PA_RESAMPLER_VARIABLE_RATE = 0x0001U,
|
PA_RESAMPLER_VARIABLE_RATE = 0x0001U,
|
||||||
PA_RESAMPLER_NO_REMAP = 0x0002U, /* implies NO_REMIX */
|
PA_RESAMPLER_NO_REMAP = 0x0002U, /* implies NO_REMIX */
|
||||||
PA_RESAMPLER_NO_REMIX = 0x0004U,
|
PA_RESAMPLER_NO_REMIX = 0x0004U,
|
||||||
PA_RESAMPLER_NO_LFE = 0x0008U
|
PA_RESAMPLER_NO_LFE = 0x0008U,
|
||||||
|
PA_RESAMPLER_NO_FILL_SINK = 0x0010U,
|
||||||
} pa_resample_flags_t;
|
} pa_resample_flags_t;
|
||||||
|
|
||||||
struct pa_resampler {
|
struct pa_resampler {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue