Repository navigation
Topology: Apply high-pass for HDA capture streams, Volume: Force gain ramp #2109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5830f43
7ed9577
739d167
ab06a84
9c184c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,35 +39,33 @@ | |
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
| /* Shift to use in volume fractional multiplications */ | ||
| #define Q_MUL_SHIFT Q_SHIFT_BITS_32(VOL_QXY_Y, VOL_QXY_Y, VOL_QXY_Y) | ||
|
|
||
| /** | ||
| * \brief Synchronize host mmap() volume with real value. | ||
| * \param[in,out] cd Volume component private data. | ||
| * \param[in] chan Channel number. | ||
| * \param[in] num_channels Update channels 0 to num_channels -1. | ||
| */ | ||
| static void vol_sync_host(struct comp_data *cd, uint32_t chan) | ||
| static void vol_sync_host(struct comp_data *cd, unsigned int num_channels) | ||
| { | ||
| if (!cd->hvol) | ||
| int n; | ||
|
|
||
| if (!cd->hvol) { | ||
| tracev_volume("vol_sync_host() Warning: null hvol, no update"); | ||
| return; | ||
| } | ||
|
|
||
| if (chan < SOF_IPC_MAX_CHANNELS) { | ||
| cd->hvol[chan].value = cd->volume[chan]; | ||
| if (num_channels < SOF_IPC_MAX_CHANNELS) { | ||
| for (n = 0; n < num_channels; n++) | ||
| cd->hvol[n].value = cd->volume[n]; | ||
| } else { | ||
| trace_volume_error("vol_sync_host() error: " | ||
| "chan = %u < SOF_IPC_MAX_CHANNELS", chan); | ||
| trace_volume_error("vol_sync_host() error: channels count %d" | ||
| " exceeds SOF_IPC_MAX_CHANNELS", | ||
| num_channels); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * \brief Update volume with target value. | ||
| * \param[in,out] cd Volume component private data. | ||
| * \param[in] chan Channel number. | ||
| */ | ||
| static void vol_update(struct comp_data *cd, uint32_t chan) | ||
| { | ||
| cd->volume[chan] = cd->tvolume[chan]; | ||
| vol_sync_host(cd, chan); | ||
| } | ||
|
|
||
| /** | ||
| * \brief Ramps volume changes over time. | ||
| * \param[in,out] data Volume base component device. | ||
|
|
@@ -82,10 +80,24 @@ static enum task_state vol_work(void *data) | |
| int again = 0; | ||
| int i; | ||
|
|
||
| /* No need to ramp in idle state, jump volume to request. */ | ||
| if (dev->state == COMP_STATE_READY) { | ||
| for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) | ||
| cd->volume[i] = cd->tvolume[i]; | ||
|
|
||
| vol_sync_host(cd, PLATFORM_MAX_CHANNELS); | ||
| return SOF_TASK_STATE_COMPLETED; | ||
| } | ||
|
|
||
| /* The first is set and cleared to indicate ongoing ramp, the | ||
| * latter is set once to enable self launched ramp only once | ||
| * in stream start. | ||
| */ | ||
| cd->vol_ramp_active = true; | ||
| cd->ramp_started = true; | ||
|
singalsu marked this conversation as resolved.
Outdated
|
||
|
|
||
| /* inc/dec each volume if it's not at target */ | ||
| for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) { | ||
| /* inc/dec each volume if it's not at target for active channels */ | ||
| for (i = 0; i < cd->channels; i++) { | ||
| /* skip if target reached */ | ||
| if (cd->volume[i] == cd->tvolume[i]) | ||
|
singalsu marked this conversation as resolved.
Outdated
|
||
| continue; | ||
|
|
@@ -98,8 +110,8 @@ static enum task_state vol_work(void *data) | |
| if (cd->volume[i] < cd->tvolume[i]) { | ||
| /* ramp up, check if ramp completed */ | ||
| if (vol >= cd->tvolume[i] || vol >= cd->vol_max) { | ||
| vol_update(cd, i); | ||
| cd->ramp_increment[i] = 0; | ||
| cd->volume[i] = cd->tvolume[i]; | ||
| } else { | ||
| cd->volume[i] = vol; | ||
| again = 1; | ||
|
|
@@ -108,25 +120,26 @@ static enum task_state vol_work(void *data) | |
| /* ramp down */ | ||
| if (vol <= 0) { | ||
| /* cannot ramp down below 0 */ | ||
| vol_update(cd, i); | ||
| cd->ramp_increment[i] = 0; | ||
| cd->volume[i] = cd->tvolume[i]; | ||
| } else { | ||
| /* ramp completed ? */ | ||
| if (vol <= cd->tvolume[i] || | ||
| vol <= cd->vol_min) { | ||
| vol_update(cd, i); | ||
| cd->ramp_increment[i] = 0; | ||
| cd->volume[i] = cd->tvolume[i]; | ||
| } else { | ||
| cd->volume[i] = vol; | ||
| again = 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /* sync host with new value */ | ||
| vol_sync_host(cd, i); | ||
| } | ||
|
|
||
| /* sync host with new value */ | ||
| vol_sync_host(cd, cd->channels); | ||
|
|
||
| /* do we need to continue ramping */ | ||
| if (again) | ||
| return SOF_TASK_STATE_RESCHEDULE; | ||
|
|
@@ -228,6 +241,8 @@ static struct comp_dev *volume_new(struct sof_ipc_comp *comp) | |
| } | ||
|
|
||
| cd->vol_ramp_active = false; | ||
| cd->channels = 0; /* To be set in prepare() */ | ||
|
|
||
| trace_volume_with_ids(dev, | ||
| "vol->initial_ramp = %d, vol->ramp = %d, " | ||
| "vol->min_value = %d, vol->max_value = %d", | ||
|
|
@@ -275,8 +290,12 @@ static int volume_params(struct comp_dev *dev, | |
| * \param[in,out] dev Volume base component device. | ||
| * \param[in] chan Channel number. | ||
| * \param[in] vol Target volume. | ||
| * \param[in] constant_rate_ramp When true do a constant rate | ||
| * and variable time length ramp. When false do | ||
| * a fixed length and variable rate ramp. | ||
|
singalsu marked this conversation as resolved.
Outdated
|
||
| */ | ||
| static inline int volume_set_chan(struct comp_dev *dev, int chan, int32_t vol) | ||
| static inline int volume_set_chan(struct comp_dev *dev, int chan, | ||
| int32_t vol, bool constant_rate_ramp) | ||
| { | ||
| struct comp_data *cd = comp_get_drvdata(dev); | ||
| struct sof_ipc_comp_volume *pga = | ||
|
|
@@ -285,7 +304,6 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan, int32_t vol) | |
| int32_t delta; | ||
| int32_t delta_abs; | ||
| int32_t inc; | ||
| int32_t t_us; | ||
|
|
||
| /* Limit received volume gain to MIN..MAX range before applying it. | ||
| * MAX is needed for now for the generic C gain arithmetics to prevent | ||
|
|
@@ -311,39 +329,41 @@ static inline int volume_set_chan(struct comp_dev *dev, int chan, int32_t vol) | |
| /* Check ramp type */ | ||
| switch (pga->ramp) { | ||
| case SOF_VOLUME_LINEAR: | ||
|
|
||
| /* Assume the ramp length (initial_ramp [ms]) describes | ||
| * time of mute to 0 dB ramp. The actual volume scale min/max | ||
| * is not known. If initial_ramp is zero (or negative) use | ||
| * step size that reaches 0 dB gain in one step (VOL_ZERO_DB). | ||
| */ | ||
| if (pga->initial_ramp > 0) | ||
| inc = MAX(VOL_RAMP_STEP_CONST / pga->initial_ramp, 1); | ||
| 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)); | ||
|
|
||
| /* Get volume transition delta and absolute value */ | ||
| delta = cd->tvolume[chan] - cd->volume[chan]; | ||
| delta_abs = ABS(delta); | ||
|
|
||
| /* If the ramp completion would take longer than initial_ramp | ||
| * increase the step size to make this ramp complete at | ||
| * initial_ramp time. Calculate estimated ramp length [us]. | ||
| /* The ramp length (initial_ramp [ms]) describes time of mute | ||
| * to vol_max unmuting. Normally the volume ramp has a | ||
| * constant linear slope defined this way and variable | ||
| * completion time. However in streaming start it is feasible | ||
| * to apply the entire topology defined ramp time to unmute to | ||
| * any used volume. In this case the ramp rate is not constant. | ||
| * Note also the legacy mode without known vol_ramp_range where | ||
| * the volume transition always uses the topology defined time. | ||
| */ | ||
| t_us = delta_abs * VOL_RAMP_UPDATE_US / inc; | ||
| if (t_us > pga->initial_ramp * 1000) { | ||
| inc = (int32_t)((int64_t)inc * delta_abs / VOL_ZERO_DB); | ||
| inc = MAX(inc, 1); | ||
| if (pga->initial_ramp > 0) { | ||
| if (constant_rate_ramp && cd->vol_ramp_range > 0) | ||
| inc = q_multsr_32x32(cd->vol_ramp_range, | ||
| VOL_RAMP_STEP_CONST, | ||
| Q_MUL_SHIFT); | ||
| else | ||
| inc = q_multsr_32x32(delta_abs, | ||
| VOL_RAMP_STEP_CONST, | ||
| Q_MUL_SHIFT); | ||
|
|
||
| /* Divide and round to nearest. Note that there will | ||
| * be some accumulated error in ramp time the longer | ||
| * the ramp and the smaller the transition is. | ||
| */ | ||
| inc = (2 * inc / pga->initial_ramp + 1) >> 1; | ||
| } else { | ||
| inc = delta_abs; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @singalsu The else part seems to be simplified as well. But yeah, I guess this is on purpose as well. It would seem "inc = delta_abs" is correct.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes the behavior is changed a bit with ramp time (length) set to zero. Earlier version used mute to 0 dB increment as step and with high gains the ramp length could become few milliseconds. It's a small mistake in previous version that I realized only now after your comment. |
||
| } | ||
|
|
||
| /* Ensure inc is at least one */ | ||
| inc = MAX(inc, 1); | ||
|
singalsu marked this conversation as resolved.
Outdated
|
||
|
|
||
| /* Invert sign for volume down ramp step */ | ||
| if (delta < 0) | ||
| inc = -inc; | ||
|
|
@@ -375,7 +395,7 @@ static inline void volume_set_chan_mute(struct comp_dev *dev, int chan) | |
|
|
||
| if (!cd->muted[chan]) { | ||
| cd->mvolume[chan] = cd->tvolume[chan]; | ||
| volume_set_chan(dev, chan, 0); | ||
| volume_set_chan(dev, chan, 0, true); | ||
| cd->muted[chan] = true; | ||
| } | ||
| } | ||
|
|
@@ -391,7 +411,7 @@ static inline void volume_set_chan_unmute(struct comp_dev *dev, int chan) | |
|
|
||
| if (cd->muted[chan]) { | ||
| cd->muted[chan] = false; | ||
| volume_set_chan(dev, chan, cd->mvolume[chan]); | ||
| volume_set_chan(dev, chan, cd->mvolume[chan], true); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -438,7 +458,7 @@ static int volume_ctrl_set_cmd(struct comp_dev *dev, | |
| if (cd->muted[ch]) { | ||
| cd->mvolume[ch] = val; | ||
| } else { | ||
| ret = volume_set_chan(dev, ch, val); | ||
| ret = volume_set_chan(dev, ch, val, true); | ||
| if (ret) | ||
| return ret; | ||
| } | ||
|
|
@@ -579,6 +599,10 @@ static int volume_copy(struct comp_dev *dev) | |
|
|
||
| tracev_volume_with_ids(dev, "volume_copy()"); | ||
|
|
||
| if (!cd->ramp_started) | ||
| schedule_task(&cd->volwork, VOL_RAMP_UPDATE_US, | ||
| VOL_RAMP_UPDATE_US); | ||
|
|
||
| /* Get source, sink, number of frames etc. to process. */ | ||
| ret = comp_get_copy_limits(dev, &c); | ||
| if (ret < 0) { | ||
|
|
@@ -652,8 +676,20 @@ static int volume_prepare(struct comp_dev *dev) | |
| goto err; | ||
| } | ||
|
|
||
| for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) | ||
| vol_sync_host(cd, i); | ||
| vol_sync_host(cd, PLATFORM_MAX_CHANNELS); | ||
|
|
||
| /* Set current volume to min to ensure ramp starts from minimum | ||
| * to previous volume request. Copy() checks for ramp started | ||
| * and schedules it if it has not yet started as result of | ||
| * driver commands. Ramp is not constant rate to ensure it lasts | ||
| * for entire topology specified time. | ||
| */ | ||
| cd->ramp_started = false; | ||
| cd->channels = sinkb->channels; | ||
| for (i = 0; i < cd->channels; i++) { | ||
| cd->volume[i] = cd->vol_min; | ||
| volume_set_chan(dev, i, cd->tvolume[i], false); | ||
| } | ||
|
|
||
| return 0; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3225193546,2143508228,537150400,3220666496,537150400,0,32690, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3227172081,2141520527,536653443,3221660410,536653443,0,32690, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3229146956,2139532835,536156946,3222653403,536156946,0,32690, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 4607827,0,88,50380800,0,0,0,0,88,2,1,0,0,0,0,0,0,1,1,0,0,0,0,3231118179,2137545158,535660909,3223645479,535660909,0,32690, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 20 Hz second order high-pass, gain 0 dB, created with example_iir_eq.m 27-Nov-2019 | ||
| CONTROLBYTES_PRIV(EQIIR_HP20HZ0dB16K_priv, | ||
| ` bytes "0x53,0x4f,0x46,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x00,0xc0,0x00,0x03,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x02,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x3c,0xf9,0xb4,0xc0,' | ||
| ` 0x79,0x05,0x4a,0x7f,0x92,0xf9,0xe5,0x1f,' | ||
| ` 0xdc,0x0c,0x34,0xc0,0x92,0xf9,0xe5,0x1f,' | ||
| ` 0x00,0x00,0x00,0x00,0xb2,0x7f,0x00,0x00"' | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 20 Hz second order high-pass, gain 0 dB, created with example_iir_eq.m 27-Nov-2019 | ||
| CONTROLBYTES_PRIV(EQIIR_HP20HZ0dB48K_priv, | ||
| ` bytes "0x53,0x4f,0x46,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x00,0xc0,0x00,0x03,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x02,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x4a,0x8c,0x3c,0xc0,' | ||
| ` 0x04,0x57,0xc3,0x7f,0xc0,0x43,0x04,0x20,' | ||
| ` 0x80,0x78,0xf7,0xbf,0xc0,0x43,0x04,0x20,' | ||
| ` 0x00,0x00,0x00,0x00,0xb2,0x7f,0x00,0x00"' | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 20 Hz second order high-pass, gain 20 dB, created with example_iir_eq.m 27-Nov-2019 | ||
| CONTROLBYTES_PRIV(EQIIR_HP20HZ20dB16K_priv, | ||
| ` bytes "0x53,0x4f,0x46,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x00,0xc0,0x00,0x03,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x02,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x3c,0xf9,0xb4,0xc0,' | ||
| ` 0x79,0x05,0x4a,0x7f,0x92,0xf9,0xe5,0x1f,' | ||
| ` 0xdc,0x0c,0x34,0xc0,0x92,0xf9,0xe5,0x1f,' | ||
| ` 0x00,0x00,0x00,0x00,0xb2,0x7f,0x00,0x00"' | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 20 Hz second order high-pass, gain 20 dB, created with example_iir_eq.m 27-Nov-2019 | ||
| CONTROLBYTES_PRIV(EQIIR_HP20HZ20dB48K_priv, | ||
| ` bytes "0x53,0x4f,0x46,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x00,0xc0,0x00,0x03,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x58,0x00,0x00,0x00,0x02,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,' | ||
| ` 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,' | ||
| ` 0x00,0x00,0x00,0x00,0x4a,0x8c,0x3c,0xc0,' | ||
| ` 0x04,0x57,0xc3,0x7f,0xc0,0x43,0x04,0x20,' | ||
| ` 0x80,0x78,0xf7,0xbf,0xc0,0x43,0x04,0x20,' | ||
| ` 0x00,0x00,0x00,0x00,0xb2,0x7f,0x00,0x00"' | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.