Audio: Volume: Fix ongoing gain ramp stop and wrong final gain

In IPC4 the individual channel gains are passed in separate
messages. One channel may have started to ramp to a new gain
while a new channel gain arrives for other channel. If the
gain is same as the previous control value, the ongoing ramp
is stopped and the gain remains at a transition value.

The incorrect code is not fixed but instead the volume_set_volume()
function is simplified. When a volume control is received, it is
assumed that pass-through mode is disabled and ramp is prepared. If
the control is received but gains are not changed, the ramp mode
is finished and pass-through is restored in ramp function.

The volume_set_switch() function is updated similarly to ensure
similar operation.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
This commit is contained in:
Seppo Ingalsuo 2024-03-14 19:21:54 +02:00 committed by Kai Vehmanen
parent 2cfc85eda0
commit 51c686f953
1 changed files with 8 additions and 23 deletions

View File

@ -79,6 +79,8 @@ static uint32_t convert_volume_ipc3_to_ipc4(uint32_t volume)
static void init_ramp(struct vol_data *cd, uint32_t curve_duration, uint32_t target_volume) static void init_ramp(struct vol_data *cd, uint32_t curve_duration, uint32_t target_volume)
{ {
cd->ramp_finished = false;
/* In IPC4 driver sends curve_duration in hundred of ns - it should be /* In IPC4 driver sends curve_duration in hundred of ns - it should be
* converted into ms value required by firmware * converted into ms value required by firmware
*/ */
@ -213,8 +215,6 @@ static int volume_set_volume(struct processing_module *mod, const uint8_t *data,
} }
init_ramp(cd, cdata.curve_duration, cdata.target_volume); init_ramp(cd, cdata.curve_duration, cdata.target_volume);
cd->ramp_finished = true;
channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count; channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count;
if (channels_count > SOF_IPC_MAX_CHANNELS) { if (channels_count > SOF_IPC_MAX_CHANNELS) {
comp_err(dev, "Invalid channels count %u", channels_count); comp_err(dev, "Invalid channels count %u", channels_count);
@ -232,8 +232,6 @@ static int volume_set_volume(struct processing_module *mod, const uint8_t *data,
volume_set_chan(mod, i, cd->tvolume[i], true); volume_set_chan(mod, i, cd->tvolume[i], true);
} }
if (cd->volume[i] != cd->tvolume[i])
cd->ramp_finished = false;
} }
} else { } else {
if (cd->muted[cdata.channel_id]) { if (cd->muted[cdata.channel_id]) {
@ -247,25 +245,12 @@ static int volume_set_volume(struct processing_module *mod, const uint8_t *data,
volume_set_chan(mod, cdata.channel_id, volume_set_chan(mod, cdata.channel_id,
cd->tvolume[cdata.channel_id], true); cd->tvolume[cdata.channel_id], true);
} }
if (cd->volume[cdata.channel_id] != cd->tvolume[cdata.channel_id])
cd->ramp_finished = false;
}
cd->is_passthrough = cd->ramp_finished;
for (i = 0; i < channels_count; i++) {
if (cd->volume[i] != VOL_ZERO_DB) {
cd->is_passthrough = false;
break;
}
} }
cd->is_passthrough = false;
volume_set_ramp_channel_counter(cd, channels_count); volume_set_ramp_channel_counter(cd, channels_count);
cd->scale_vol = vol_get_processing_function(dev, cd); cd->scale_vol = vol_get_processing_function(dev, cd);
volume_prepare_ramp(dev, cd); volume_prepare_ramp(dev, cd);
return 0; return 0;
} }
@ -322,8 +307,6 @@ static int volume_set_switch(struct processing_module *mod, const uint8_t *data,
ctl = (struct sof_ipc4_control_msg_payload *)data; ctl = (struct sof_ipc4_control_msg_payload *)data;
cd->ramp_finished = true;
channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count; channels_count = mod->priv.cfg.base_cfg.audio_fmt.channels_count;
if (channels_count > SOF_IPC_MAX_CHANNELS) { if (channels_count > SOF_IPC_MAX_CHANNELS) {
comp_err(dev, "Invalid channels count %u", channels_count); comp_err(dev, "Invalid channels count %u", channels_count);
@ -344,11 +327,13 @@ static int volume_set_switch(struct processing_module *mod, const uint8_t *data,
volume_set_chan_unmute(mod, i); volume_set_chan_unmute(mod, i);
else else
volume_set_chan_mute(mod, i); volume_set_chan_mute(mod, i);
if (cd->volume[i] != cd->tvolume[i])
cd->ramp_finished = false;
} }
cd->ramp_finished = false;
cd->is_passthrough = false;
volume_set_ramp_channel_counter(cd, channels_count);
cd->scale_vol = vol_get_processing_function(dev, cd);
volume_prepare_ramp(dev, cd);
return 0; return 0;
} }