Skip to content

Commit

Permalink
Audio: Volume: Add passthrough functions
Browse files Browse the repository at this point in the history
Add passthrough functions implementation. If the gain of all
channels equal 0dB, then we use passthrough functions to process
the volume component.

Signed-off-by: Andrula Song <[email protected]>
  • Loading branch information
andrula-song committed Jun 21, 2023
1 parent d277d92 commit fc5e117
Show file tree
Hide file tree
Showing 9 changed files with 1,061 additions and 44 deletions.
49 changes: 46 additions & 3 deletions src/audio/module_adapter/module/volume/volume.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,10 @@ static inline int32_t volume_windows_fade_ramp(struct vol_data *cd, int32_t ramp
*/

/* Note: Using inline saves 0.4 MCPS */
static inline void volume_ramp(struct vol_data *cd)
static inline void volume_ramp(struct processing_module *mod)
{
struct vol_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
int32_t new_vol;
int32_t tvolume;
int32_t volume;
Expand Down Expand Up @@ -326,6 +328,29 @@ static inline void volume_ramp(struct vol_data *cd)
}
cd->volume[i] = new_vol;
}

cd->is_passthrough = cd->ramp_finished;
for (i = 0; i < cd->channels; i++) {
if (cd->volume[i] != VOL_ZERO_DB) {
cd->is_passthrough = false;
break;
}
}

#if CONFIG_IPC_MAJOR_4
cd->scale_vol = vol_get_processing_function(dev, cd);
#else
struct comp_buffer *sourceb;
struct comp_buffer __sparse_cache *source_c;

sourceb = list_first_item(&dev->bsource_list,
struct comp_buffer, sink_list);
source_c = buffer_acquire(sourceb);

cd->scale_vol = vol_get_processing_function(dev, source_c, cd);

buffer_release(source_c);
#endif
}

/**
Expand Down Expand Up @@ -368,6 +393,7 @@ static void reset_state(struct vol_data *cd)
cd->vol_ramp_elapsed_frames = 0;
cd->sample_rate_inv = 0;
cd->copy_gain = true;
cd->is_passthrough = false;
}

#if CONFIG_IPC_MAJOR_3
Expand Down Expand Up @@ -397,6 +423,7 @@ static int volume_init(struct processing_module *mod)
}

md->private = cd;
cd->is_passthrough = false;

/* Set the default volumes. If IPC sets min_value or max_value to
* not-zero, use them. Otherwise set to internal limits and notify
Expand Down Expand Up @@ -605,6 +632,7 @@ static int volume_init(struct processing_module *mod)
cd->mailbox_offset += instance_id * sizeof(struct ipc4_peak_volume_regs);

cd->attenuation = 0;
cd->is_passthrough = false;

reset_state(cd);

Expand Down Expand Up @@ -971,6 +999,17 @@ static int volume_set_volume(struct processing_module *mod, const uint8_t *data,
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->scale_vol = vol_get_processing_function(dev, cd);

prepare_ramp(dev, cd);

return 0;
Expand Down Expand Up @@ -1161,7 +1200,7 @@ static int volume_process(struct processing_module *mod,
}

if (!cd->ramp_finished) {
volume_ramp(cd);
volume_ramp(mod);
cd->vol_ramp_elapsed_frames += frames;
}

Expand Down Expand Up @@ -1291,8 +1330,12 @@ static int volume_prepare(struct processing_module *mod,
ret = -ENOMEM;
goto err;
}
#if CONFIG_IPC_MAJOR_4
cd->scale_vol = vol_get_processing_function(dev, cd);
#else
cd->scale_vol = vol_get_processing_function(dev, sink_c, cd);
#endif

cd->scale_vol = vol_get_processing_function(dev, sink_c);
if (!cd->scale_vol) {
comp_err(dev, "volume_prepare(): invalid cd->scale_vol");

Expand Down
133 changes: 127 additions & 6 deletions src/audio/module_adapter/module/volume/volume_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,47 @@ static void vol_s24_to_s24(struct processing_module *mod, struct input_stream_bu
y = audio_stream_wrap(sink, y + n);
}
}

/**
* \brief Volume passthrough from 24/32 bit to 24/32 bit.
* \param[in,out] dev Volume base component device.
* \param[in,out] sink Destination buffer.
* \param[in,out] source Input buffer.
* \param[in] frames Number of frames to process.
* \param[in] attenuation factor for peakmeter adjustment (unused)
*
* Copy and scale volume from 24/32 bit source buffer
* to 24/32 bit destination buffer.
*/
static void vol_passthrough_s24_to_s24(struct processing_module *mod,
struct input_stream_buffer *bsource,
struct output_stream_buffer *bsink, uint32_t frames,
uint32_t attenuation)
{
struct audio_stream __sparse_cache *source = bsource->data;
struct audio_stream __sparse_cache *sink = bsink->data;
int32_t *x;
int32_t *y;
int nmax, n;
const int nch = audio_stream_get_channels(source);
int remaining_samples = frames * nch;

x = audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed);
y = audio_stream_wrap(sink, (char *)audio_stream_get_wptr(sink) + bsink->size);

bsource->consumed += VOL_S32_SAMPLES_TO_BYTES(remaining_samples);
bsink->size += VOL_S32_SAMPLES_TO_BYTES(remaining_samples);
while (remaining_samples) {
nmax = audio_stream_samples_without_wrap_s24(source, x);
n = MIN(remaining_samples, nmax);
nmax = audio_stream_samples_without_wrap_s24(sink, y);
n = MIN(n, nmax);
memcpy_s(y, n * sizeof(int32_t), x, n * sizeof(int32_t));
remaining_samples -= n;
x = audio_stream_wrap(source, x + n);
y = audio_stream_wrap(sink, y + n);
}
}
#endif /* CONFIG_FORMAT_S24LE */

#if CONFIG_FORMAT_S32LE
Expand Down Expand Up @@ -147,6 +188,46 @@ static void vol_s32_to_s32(struct processing_module *mod, struct input_stream_bu
y = audio_stream_wrap(sink, y + n);
}
}

/**
* \brief Volume passthrough from 32 bit to 32 bit.
* \param[in,out] dev Volume base component device.
* \param[in,out] sink Destination buffer.
* \param[in,out] source Input buffer.
* \param[in] frames Number of frames to process.
* \param[in] attenuation factor for peakmeter adjustment (unused)
*
* Copy and scale volume from 32 bit source buffer
* to 32 bit destination buffer.
*/
static void vol_passthrough_s32_to_s32(struct processing_module *mod,
struct input_stream_buffer *bsource,
struct output_stream_buffer *bsink, uint32_t frames,
uint32_t attenuation)
{
struct audio_stream __sparse_cache *source = bsource->data;
struct audio_stream __sparse_cache *sink = bsink->data;
int32_t *x;
int32_t *y;
int nmax, n;
const int nch = audio_stream_get_channels(source);
int remaining_samples = frames * nch;

x = audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed);
y = audio_stream_wrap(sink, (char *)audio_stream_get_wptr(sink) + bsink->size);
bsource->consumed += VOL_S32_SAMPLES_TO_BYTES(remaining_samples);
bsink->size += VOL_S32_SAMPLES_TO_BYTES(remaining_samples);
while (remaining_samples) {
nmax = audio_stream_samples_without_wrap_s32(source, x);
n = MIN(remaining_samples, nmax);
nmax = audio_stream_samples_without_wrap_s32(sink, y);
n = MIN(n, nmax);
memcpy_s(y, n * sizeof(int32_t), x, n * sizeof(int32_t));
remaining_samples -= n;
x = audio_stream_wrap(source, x + n);
y = audio_stream_wrap(sink, y + n);
}
}
#endif /* CONFIG_FORMAT_S32LE */

#if CONFIG_FORMAT_S16LE
Expand Down Expand Up @@ -198,18 +279,58 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu
y = audio_stream_wrap(sink, y + n);
}
}

/**
* \brief Volume passthrough from 16 bit to 16 bit.
* \param[in,out] dev Volume base component device.
* \param[in,out] sink Destination buffer.
* \param[in,out] source Input buffer.
* \param[in] frames Number of frames to process.
* \param[in] attenuation factor for peakmeter adjustment (unused)
*
* Copy and scale volume from 16 bit source buffer
* to 16 bit destination buffer.
*/
static void vol_passthrough_s16_to_s16(struct processing_module *mod,
struct input_stream_buffer *bsource,
struct output_stream_buffer *bsink, uint32_t frames,
uint32_t attenuation)
{
struct audio_stream __sparse_cache *source = bsource->data;
struct audio_stream __sparse_cache *sink = bsink->data;
int16_t *x;
int16_t *y;
int nmax, n;
const int nch = audio_stream_get_channels(source);
int remaining_samples = frames * nch;

x = audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) + bsource->consumed);
y = audio_stream_wrap(sink, (char *)audio_stream_get_wptr(sink) + bsink->size);
bsource->consumed += VOL_S16_SAMPLES_TO_BYTES(remaining_samples);
bsink->size += VOL_S16_SAMPLES_TO_BYTES(remaining_samples);
while (remaining_samples) {
nmax = audio_stream_samples_without_wrap_s16(source, x);
n = MIN(remaining_samples, nmax);
nmax = audio_stream_samples_without_wrap_s16(sink, y);
n = MIN(n, nmax);
memcpy_s(y, n * sizeof(int16_t), x, n * sizeof(int16_t));
remaining_samples -= n;
x = audio_stream_wrap(source, x + n);
y = audio_stream_wrap(sink, y + n);
}
}
#endif /* CONFIG_FORMAT_S16LE */

const struct comp_func_map volume_func_map[] = {
#if CONFIG_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, vol_s16_to_s16 },
#endif /* CONFIG_FORMAT_S16LE */
{ SOF_IPC_FRAME_S16_LE, vol_s16_to_s16, vol_passthrough_s16_to_s16},
#endif
#if CONFIG_FORMAT_S24LE
{ SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24 },
#endif /* CONFIG_FORMAT_S24LE */
{ SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24, vol_passthrough_s24_to_s24},
#endif
#if CONFIG_FORMAT_S32LE
{ SOF_IPC_FRAME_S32_LE, vol_s32_to_s32 },
#endif /* CONFIG_FORMAT_S32LE */
{ SOF_IPC_FRAME_S32_LE, vol_s32_to_s32, vol_passthrough_s32_to_s32},
#endif
};

const size_t volume_func_count = ARRAY_SIZE(volume_func_map);
Expand Down
Loading

0 comments on commit fc5e117

Please sign in to comment.