mirror of https://github.com/thesofproject/sof.git
Volume: Use min and max volume scale values from IPC
This patch adds feature to retrieve volume scale min and max from IPC if the parameters are set. Volume min and max are now used with ramp time parameter to compute gain ramp step to achieve constant rate ramps with any volume scale. If the min and max are zeros the previous FW operation is preserved. Previously the firmware did not know the volume range so the volume code uses in volume request a check to prevent exceeding ramp length specified in topology by step size re-adjust. It was done to prevent very long ramps to happen with volume scales with large gain. However the smaller transitions remained longer than necessary. This patch fixes that last remaining issue. The ramp length check code is preserved to be compatible with kernel versions those do not provide the min and max volume scale values. When provided the check code has no impact. The patch includes some cosmetic re-arranging of volume comp data struct fields in addition to adding new the fields vol_ramp_range, vol_min, and vol_max. Also error traces were added to notify if the volume min/max or request has been limited to fit to supported volume range. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
This commit is contained in:
parent
a2fa79f211
commit
6f65414176
|
@ -83,7 +83,7 @@ static uint64_t vol_work(void *data)
|
|||
vol += cd->ramp_increment[i];
|
||||
if (cd->volume[i] < cd->tvolume[i]) {
|
||||
/* ramp up, check if ramp completed */
|
||||
if (vol >= cd->tvolume[i] || vol >= VOL_MAX) {
|
||||
if (vol >= cd->tvolume[i] || vol >= cd->vol_max) {
|
||||
vol_update(cd, i);
|
||||
} else {
|
||||
cd->volume[i] = vol;
|
||||
|
@ -96,7 +96,8 @@ static uint64_t vol_work(void *data)
|
|||
vol_update(cd, i);
|
||||
} else {
|
||||
/* ramp completed ? */
|
||||
if (vol <= cd->tvolume[i] || vol <= VOL_MIN) {
|
||||
if (vol <= cd->tvolume[i] ||
|
||||
vol <= cd->vol_min) {
|
||||
vol_update(cd, i);
|
||||
} else {
|
||||
cd->volume[i] = vol;
|
||||
|
@ -157,14 +158,53 @@ static struct comp_dev *volume_new(struct sof_ipc_comp *comp)
|
|||
schedule_task_init(&cd->volwork, SOF_SCHEDULE_LL, SOF_TASK_PRI_MED,
|
||||
vol_work, dev, 0, 0);
|
||||
|
||||
/* set the default volumes */
|
||||
/* Set the default volumes. If IPC sets min_value or max_value to
|
||||
* not-zero, use them. Otherwise set to internal limits and notify
|
||||
* ramp step calculation about assumed range with the range set to
|
||||
* zero.
|
||||
*/
|
||||
if (vol->min_value || vol->max_value) {
|
||||
if (vol->min_value < VOL_MIN) {
|
||||
/* Use VOL_MIN instead, no need to stop new(). */
|
||||
cd->vol_min = VOL_MIN;
|
||||
trace_volume_error("volume_new(): vol->min_value "
|
||||
"was limited to VOL_MIN.");
|
||||
} else {
|
||||
cd->vol_min = vol->min_value;
|
||||
}
|
||||
|
||||
if (vol->max_value > VOL_MAX) {
|
||||
/* Use VOL_MAX instead, no need to stop new(). */
|
||||
cd->vol_max = VOL_MAX;
|
||||
trace_volume_error("volume_new(): vol->max_value "
|
||||
"was limited to VOL_MAX.");
|
||||
} else {
|
||||
cd->vol_max = vol->max_value;
|
||||
}
|
||||
|
||||
cd->vol_ramp_range = vol->max_value - vol->min_value;
|
||||
} else {
|
||||
/* Legacy mode, set the limits to firmware capability where
|
||||
* VOL_MAX is a very large gain to avoid restricting valid
|
||||
* requests. The default ramp rate will be computed based
|
||||
* on 0 - 1.0 gain range assumption when vol_ramp_range
|
||||
* is set to 0.
|
||||
*/
|
||||
cd->vol_min = VOL_MIN;
|
||||
cd->vol_max = VOL_MAX;
|
||||
cd->vol_ramp_range = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
|
||||
cd->volume[i] = MAX(MIN(VOL_MAX, VOL_ZERO_DB), VOL_MIN);
|
||||
cd->volume[i] = MAX(MIN(cd->vol_max, VOL_ZERO_DB),
|
||||
cd->vol_min);
|
||||
cd->tvolume[i] = cd->volume[i];
|
||||
}
|
||||
|
||||
trace_volume("vol->initial_ramp = %d, vol->ramp = %d",
|
||||
vol->initial_ramp, vol->ramp);
|
||||
trace_volume("vol->initial_ramp = %d, vol->ramp = %d, "
|
||||
"vol->min_value = %d, vol->max_value = %d",
|
||||
vol->initial_ramp, vol->ramp,
|
||||
vol->min_value, vol->max_value);
|
||||
|
||||
dev->state = COMP_STATE_READY;
|
||||
return dev;
|
||||
|
@ -220,11 +260,19 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan, uint32_t vol)
|
|||
* multiplication overflow with the 32 bit value. Non-zero MIN option
|
||||
* can be useful to prevent totally muted small volume gain.
|
||||
*/
|
||||
if (v <= VOL_MIN)
|
||||
if (v <= VOL_MIN) {
|
||||
/* No need to fail, just trace the event. */
|
||||
trace_volume_error("volume_set_chan: Limited request %d to "
|
||||
"VOL_MIN.", v);
|
||||
v = VOL_MIN;
|
||||
}
|
||||
|
||||
if (v > VOL_MAX)
|
||||
if (v > VOL_MAX) {
|
||||
/* No need to fail, just trace the event. */
|
||||
trace_volume_error("volume_set_chan: Limited request %d to "
|
||||
"VOL_MAX.", v);
|
||||
v = VOL_MAX;
|
||||
}
|
||||
|
||||
cd->tvolume[chan] = v;
|
||||
|
||||
|
@ -242,6 +290,15 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan, uint32_t vol)
|
|||
else
|
||||
inc = VOL_ZERO_DB;
|
||||
|
||||
/* Scale the increment with actual volume range if it was
|
||||
* passed via IPC.
|
||||
*/
|
||||
if (cd->vol_ramp_range)
|
||||
inc = q_multsr_32x32(inc, cd->vol_ramp_range,
|
||||
Q_SHIFT_BITS_32(VOL_QXY_Y,
|
||||
VOL_QXY_Y,
|
||||
VOL_QXY_Y));
|
||||
|
||||
delta = cd->tvolume[chan] - cd->volume[chan];
|
||||
delta_abs = ABS(delta);
|
||||
|
||||
|
|
|
@ -85,17 +85,20 @@
|
|||
* Gain amplitude value is between 0 (mute) ... 2^16 (0dB) ... 2^24 (~+48dB).
|
||||
*/
|
||||
struct comp_data {
|
||||
enum sof_ipc_frame source_format; /**< source frame format */
|
||||
enum sof_ipc_frame sink_format; /**< sink frame format */
|
||||
struct task volwork; /**< volume scheduled work function */
|
||||
struct sof_ipc_ctrl_value_chan *hvol; /**< host volume readback */
|
||||
int32_t volume[SOF_IPC_MAX_CHANNELS]; /**< current volume */
|
||||
int32_t tvolume[SOF_IPC_MAX_CHANNELS]; /**< target volume */
|
||||
int32_t mvolume[SOF_IPC_MAX_CHANNELS]; /**< mute volume */
|
||||
int32_t ramp_increment[SOF_IPC_MAX_CHANNELS]; /**< for linear ramp */
|
||||
int32_t vol_min; /**< minimum volume */
|
||||
int32_t vol_max; /**< maximum volume */
|
||||
int32_t vol_ramp_range; /**< max ramp transition */
|
||||
enum sof_ipc_frame source_format; /**< source frame format */
|
||||
enum sof_ipc_frame sink_format; /**< sink frame format */
|
||||
/**< volume processing function */
|
||||
void (*scale_vol)(struct comp_dev *dev, struct comp_buffer *sink,
|
||||
struct comp_buffer *source, uint32_t frames);
|
||||
struct task volwork; /**< volume scheduled work function */
|
||||
struct sof_ipc_ctrl_value_chan *hvol; /**< host volume readback */
|
||||
int32_t ramp_increment[SOF_IPC_MAX_CHANNELS]; /**< for linear ramp */
|
||||
};
|
||||
|
||||
/** \brief Volume processing functions map. */
|
||||
|
|
Loading…
Reference in New Issue