Skip to content
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

Audio: Volume: Add bypass functions #7828

Merged
merged 2 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/audio/module_adapter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC)
add_local_sources(sof
module/volume/volume_generic.c
module/volume/volume_hifi3.c
module/volume/volume_hifi4.c
module/volume/volume_generic_with_peakvol.c
module/volume/volume_hifi3_with_peakvol.c
module/volume/volume_hifi4_with_peakvol.c
module/volume/volume.c)
endif()

Expand Down
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;
}
}
andrula-song marked this conversation as resolved.
Show resolved Hide resolved

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
135 changes: 128 additions & 7 deletions src/audio/module_adapter/module/volume/volume_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ LOG_MODULE_DECLARE(volume_generic, CONFIG_SOF_LOG_LEVEL);

#include <sof/audio/volume.h>

#ifdef CONFIG_GENERIC
#ifdef VOLUME_GENERIC

#if (!CONFIG_COMP_PEAK_VOL)

Expand Down 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));
andrula-song marked this conversation as resolved.
Show resolved Hide resolved
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrula-song @singalsu
Hmm, audio_stream_samples_without_wrap_s24() is identical to audio_stream_samples_without_wrap_s32(), so effectively vol_passthrough_s32_to_s32() and vol_passthrough_s24_to_s24 are duplicated code. Can we just use one fucntion instead?

And it seems generic copy seems like something we use in other audio functions, so do we have this function already somewhere else we could just call?

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