From 27505f30325579d19905a54435631af493ad50de Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Fri, 10 Jul 2026 20:03:36 +0200 Subject: [PATCH 1/3] test(cmocka, drc): add DRC process unit test Add a process-level cmocka test for the DRC module. The new drc_process test follows the eq_iir_process harness (legacy process_audio_stream API): it builds a small libaudio, creates the DRC component through the full lifecycle (comp_new -> set_configuration -> prepare -> streaming) and pushes a chirp signal in S16/S24/S32. --- test/cmocka/src/audio/drc/CMakeLists.txt | 51 ++ test/cmocka/src/audio/drc/cmocka_drc_coef.h | 42 ++ test/cmocka/src/audio/drc/drc_process.c | 535 ++++++++++++++++++++ 3 files changed, 628 insertions(+) create mode 100644 test/cmocka/src/audio/drc/cmocka_drc_coef.h create mode 100644 test/cmocka/src/audio/drc/drc_process.c diff --git a/test/cmocka/src/audio/drc/CMakeLists.txt b/test/cmocka/src/audio/drc/CMakeLists.txt index f0c351e5c90a..ac21121da88f 100644 --- a/test/cmocka/src/audio/drc/CMakeLists.txt +++ b/test/cmocka/src/audio/drc/CMakeLists.txt @@ -10,3 +10,54 @@ cmocka_test(drc_math_test ) target_include_directories(drc_math_test PRIVATE ${PROJECT_SOURCE_DIR}/src/audio) + +cmocka_test(drc_process + drc_process.c +) + +target_include_directories(drc_process PRIVATE ${PROJECT_SOURCE_DIR}/src/audio) + +# make small version of libaudio so we don't have to care +# about unused missing references + +add_compile_options(-DUNIT_TEST) + +add_library(audio_for_drc STATIC + ${PROJECT_SOURCE_DIR}/src/audio/drc/drc.c + ${PROJECT_SOURCE_DIR}/src/audio/drc/drc_generic.c + ${PROJECT_SOURCE_DIR}/src/audio/drc/drc_math_generic.c + ${PROJECT_SOURCE_DIR}/src/audio/drc/drc_math_hifi3.c + ${PROJECT_SOURCE_DIR}/src/audio/drc/drc_log.c + ${PROJECT_SOURCE_DIR}/src/math/numbers.c + ${PROJECT_SOURCE_DIR}/src/math/exp_fcn.c + ${PROJECT_SOURCE_DIR}/src/math/exp_fcn_hifi.c + ${PROJECT_SOURCE_DIR}/src/math/lut_trig.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c + ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c + ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c + ${PROJECT_SOURCE_DIR}/src/audio/sink_api_helper.c + ${PROJECT_SOURCE_DIR}/src/audio/sink_source_utils.c + ${PROJECT_SOURCE_DIR}/src/audio/audio_stream.c + ${PROJECT_SOURCE_DIR}/src/audio/component.c + ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c + ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c + ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-graph.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-params.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-schedule.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-stream.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-xrun.c +) +sof_append_relative_path_definitions(audio_for_drc) + +target_link_libraries(audio_for_drc PRIVATE sof_options) + +target_link_libraries(drc_process PRIVATE audio_for_drc) diff --git a/test/cmocka/src/audio/drc/cmocka_drc_coef.h b/test/cmocka/src/audio/drc/cmocka_drc_coef.h new file mode 100644 index 000000000000..446100a65d47 --- /dev/null +++ b/test/cmocka/src/audio/drc/cmocka_drc_coef.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. + * + * DRC configuration blobs for the process unit test. Generated from + * tools/ctl/ipc4/drc/{passthrough,speaker_default}.txt (see + * src/audio/drc/tune/sof_example_drc.m). Each array is a sof_abi_hdr + * header followed by a struct sof_drc_config payload. + */ + +#ifndef CMOCKA_DRC_COEF_H +#define CMOCKA_DRC_COEF_H + +#include + +/* Pass-through configuration (params.enabled = 0) */ +static const uint32_t drc_coef_pass_2ch[35] = { + 0x00464f53, 0x00000000, 0x0000006c, 0x03013000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000006c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xe8000000, 0x1e000000, + 0x0c000000, 0x00624dd3, 0x0409c2b1, 0x05555555, + 0x001efa50, 0x00946055, 0xff6a987e, 0x01fec983, + 0x22474764, 0x01745617, 0x0071c71c, 0xff777777, + 0x001f77d8, 0x00000005, 0x00438000, 0x00047dd7, + 0x0025cea0, 0x00097dd7, 0x0000b5b1 +}; + +/* Enabled configuration, small speaker default (params.enabled = 1) */ +static const uint32_t drc_coef_enabled_2ch[35] = { + 0x00464f53, 0x00000000, 0x0000006c, 0x03013000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000006c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0xe2000000, 0x14000000, + 0x0a000000, 0x00624dd3, 0x02061b8a, 0x06666666, + 0x00ba972f, 0x001e0c18, 0xffe04220, 0x0050f44e, + 0x08349f9a, 0x04d82cd3, 0x0071c71c, 0xff777777, + 0x001f77d8, 0x00000005, 0x00438000, 0x00047dd7, + 0x0025cea0, 0x00097dd7, 0x0000b5b1 +}; + +#endif /* CMOCKA_DRC_COEF_H */ diff --git a/test/cmocka/src/audio/drc/drc_process.c b/test/cmocka/src/audio/drc/drc_process.c new file mode 100644 index 000000000000..cb8174eee4c2 --- /dev/null +++ b/test/cmocka/src/audio/drc/drc_process.c @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drc/drc.h" +#include "../../util.h" +#include "../../../include/cmocka_chirp_2ch.h" +#include "cmocka_drc_coef.h" + +/* Thresholds for frames count jitter for rand() function */ +#define THR_RAND_PLUS_ONE ((RAND_MAX >> 1) + (RAND_MAX >> 2)) +#define THR_RAND_MINUS_ONE ((RAND_MAX >> 1) - (RAND_MAX >> 2)) + +/* Maximum absolute value of a signed 24 bit sample */ +#define S24_MAX_ABS 0x800000 + +struct buffer_state { + int idx; +}; + +static struct buffer_state buffer_fill_data; +static struct buffer_state buffer_verify_data; + +struct test_parameters { + uint32_t channels; + uint32_t frames; + uint32_t buffer_size_mult; + uint32_t source_format; + uint32_t sink_format; + const uint32_t *config; /* sof_abi_hdr wrapped DRC config blob */ + bool passthrough; /* true when config has params.enabled == 0 */ +}; + +struct test_data { + struct comp_dev *dev; + struct comp_buffer *sink; + struct comp_buffer *source; + struct test_parameters *params; + struct processing_module *mod; + bool continue_loop; + int diff_count; /* enabled mode: samples that differ from input */ +}; + +static int setup_group(void **state) +{ + sys_comp_init(sof_get()); + sys_comp_module_drc_interface_init(); + return 0; +} + +static struct sof_ipc_comp_process *create_drc_comp_ipc(struct test_data *td) +{ + struct sof_ipc_comp_process *ipc; + size_t ipc_size = sizeof(struct sof_ipc_comp_process); + const struct sof_uuid uuid = SOF_REG_UUID(drc); + + ipc = calloc(1, ipc_size + SOF_UUID_SIZE); + memcpy_s(ipc + 1, SOF_UUID_SIZE, &uuid, SOF_UUID_SIZE); + ipc->comp.hdr.size = ipc_size + SOF_UUID_SIZE; + ipc->comp.type = SOF_COMP_MODULE_ADAPTER; + ipc->config.hdr.size = sizeof(struct sof_ipc_comp_config); + ipc->size = 0; + ipc->comp.ext_data_length = SOF_UUID_SIZE; + return ipc; +} + +static int drc_send_config(struct processing_module *mod, const uint32_t *config) +{ + const struct module_interface *const ops = mod->dev->drv->adapter_ops; + const struct sof_abi_hdr *blob = (const struct sof_abi_hdr *)config; + size_t cdata_size = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr) + + blob->size; + struct sof_ipc_ctrl_data *cdata; + int ret; + + cdata = calloc(1, cdata_size); + if (!cdata) + return -ENOMEM; + + cdata->cmd = SOF_CTRL_CMD_BINARY; + cdata->num_elems = blob->size; + cdata->data[0].magic = blob->magic; + cdata->data[0].type = blob->type; + cdata->data[0].size = blob->size; + cdata->data[0].abi = blob->abi; + memcpy_s(cdata->data[0].data, blob->size, blob->data, blob->size); + + ret = ops->set_configuration(mod, 0, MODULE_CFG_FRAGMENT_SINGLE, + blob->size, (const uint8_t *)cdata, + blob->size, NULL, 0); + + free(cdata); + return ret; +} + +static void prepare_sink(struct test_data *td, struct processing_module *mod) +{ + struct test_parameters *parameters = td->params; + struct module_data *md = &mod->priv; + size_t size; + size_t free; + + size = parameters->frames * get_frame_bytes(parameters->sink_format, parameters->channels) * + parameters->buffer_size_mult; + + md->mpd.out_buff_size = parameters->frames * get_frame_bytes(parameters->sink_format, + parameters->channels); + + td->sink = create_test_sink(td->dev, 0, parameters->sink_format, + parameters->channels, size); + free = audio_stream_get_free_bytes(&td->sink->stream); + assert_int_equal(free, size); +} + +static void prepare_source(struct test_data *td, struct processing_module *mod) +{ + struct test_parameters *parameters = td->params; + struct module_data *md = &mod->priv; + size_t size; + size_t free; + + md->mpd.in_buff_size = parameters->frames * get_frame_bytes(parameters->source_format, + parameters->channels); + + size = parameters->frames * get_frame_bytes(parameters->source_format, + parameters->channels) * parameters->buffer_size_mult; + + td->source = create_test_source(td->dev, 0, parameters->source_format, + parameters->channels, size); + free = audio_stream_get_free_bytes(&td->source->stream); + assert_int_equal(free, size); +} + +static int setup(void **state) +{ + struct test_parameters *params = *state; + struct processing_module *mod; + struct test_data *td; + struct sof_ipc_comp_process *ipc; + struct comp_dev *dev; + int ret; + + td = test_malloc(sizeof(*td)); + if (!td) + return -EINVAL; + + td->params = test_malloc(sizeof(*params)); + if (!td->params) { + test_free(td); + return -EINVAL; + } + + memcpy_s(td->params, sizeof(*td->params), params, sizeof(*params)); + ipc = create_drc_comp_ipc(td); + buffer_fill_data.idx = 0; + buffer_verify_data.idx = 0; + td->diff_count = 0; + + dev = comp_new((struct sof_ipc_comp *)ipc); + free(ipc); + if (!dev) { + test_free(td->params); + test_free(td); + return -EINVAL; + } + + td->dev = dev; + dev->frames = params->frames; + mod = comp_mod(dev); + + ret = drc_send_config(mod, params->config); + if (ret) { + comp_free(td->dev); + test_free(td->params); + test_free(td); + return ret; + } + + prepare_sink(td, mod); + prepare_source(td, mod); + + /* allocate intermediate buffers */ + mod->input_buffers = test_malloc(sizeof(struct input_stream_buffer)); + mod->input_buffers[0].data = &td->source->stream; + mod->output_buffers = test_malloc(sizeof(struct output_stream_buffer)); + mod->output_buffers[0].data = &td->sink->stream; + mod->stream_params = test_malloc(sizeof(struct sof_ipc_stream_params)); + mod->stream_params->channels = params->channels; + mod->period_bytes = get_frame_bytes(params->source_format, params->channels) * 48000 / 1000; + + ret = module_prepare(mod, NULL, 0, NULL, 0); + if (ret) { + free_test_source(td->source); + free_test_sink(td->sink); + comp_free(td->dev); + test_free(td->params); + test_free(td); + return ret; + } + + td->continue_loop = true; + + *state = td; + return 0; +} + +static int teardown(void **state) +{ + struct test_data *td = *state; + struct processing_module *mod = comp_mod(td->dev); + + test_free(mod->input_buffers); + test_free(mod->output_buffers); + test_free(mod->stream_params); + mod->stream_params = NULL; + test_free(td->params); + free_test_source(td->source); + free_test_sink(td->sink); + comp_free(td->dev); + test_free(td); + return 0; +} + +#if CONFIG_FORMAT_S16LE +static void fill_source_s16(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int16_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s16(ss, i); + *x = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 15)); + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s16(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t ref; + int32_t out; + int16_t *x; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 1; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s16(ss, i); + out = *x; + ref = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx++], 31, 15)); + if (td->params->passthrough) + assert_int_equal(out, ref); + else if (out != ref) + td->diff_count++; + } +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +static void fill_source_s24(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s32(ss, i); + *x = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 23)); + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s24(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t ref; + int32_t out; + int32_t *x; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 2; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s32(ss, i); + out = (*x << 8) >> 8; /* Make sure there's no 24 bit overflow */ + ref = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx++], 31, 23)); + /* DRC must never produce a value outside of the 24 bit range */ + assert_true(out < S24_MAX_ABS && out >= -S24_MAX_ABS); + if (td->params->passthrough) + assert_int_equal(out, ref); + else if (out != ref) + td->diff_count++; + } +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +static void fill_source_s32(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s32(ss, i); + *x = chirp_2ch[buffer_fill_data.idx++]; + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s32(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t ref; + int32_t out; + int32_t *x; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 2; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s32(ss, i); + out = *x; + ref = chirp_2ch[buffer_verify_data.idx++]; + if (td->params->passthrough) + assert_int_equal(out, ref); + else if (out != ref) + td->diff_count++; + } +} +#endif /* CONFIG_FORMAT_S32LE */ + +static int frames_jitter(int frames) +{ + int r = rand(); + + if (r > THR_RAND_PLUS_ONE) + return frames + 1; + else if (r < THR_RAND_MINUS_ONE) + return frames - 1; + else + return frames; +} + +static void test_audio_drc(void **state) +{ + struct test_data *td = *state; + struct processing_module *mod = comp_mod(td->dev); + + struct comp_buffer *source = td->source; + struct comp_buffer *sink = td->sink; + int ret; + int frames; + + while (td->continue_loop) { + frames = frames_jitter(td->params->frames); + switch (audio_stream_get_frm_fmt(&source->stream)) { + case SOF_IPC_FRAME_S16_LE: + fill_source_s16(td, frames); + break; + case SOF_IPC_FRAME_S24_4LE: + fill_source_s24(td, frames); + break; + case SOF_IPC_FRAME_S32_LE: + fill_source_s32(td, frames); + break; + default: + assert(0); + break; + } + + mod->input_buffers[0].consumed = 0; + mod->output_buffers[0].size = 0; + ret = module_process_legacy(mod, mod->input_buffers, 1, + mod->output_buffers, 1); + assert_int_equal(ret, 0); + + comp_update_buffer_consume(source, mod->input_buffers[0].consumed); + comp_update_buffer_produce(sink, mod->output_buffers[0].size); + + switch (audio_stream_get_frm_fmt(&sink->stream)) { + case SOF_IPC_FRAME_S16_LE: + verify_sink_s16(td); + break; + case SOF_IPC_FRAME_S24_4LE: + verify_sink_s24(td); + break; + case SOF_IPC_FRAME_S32_LE: + verify_sink_s32(td); + break; + default: + assert(0); + break; + } + + comp_update_buffer_consume(sink, mod->output_buffers[0].size); + } + + /* An enabled DRC must actually change the signal, otherwise the + * processing function was never exercised (e.g. silently fell back + * to pass-through). + */ + if (!td->params->passthrough) + assert_true(td->diff_count > 0); +} + +static struct test_parameters parameters[] = { +#if CONFIG_FORMAT_S16LE + { 2, 48, 2, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, drc_coef_pass_2ch, true }, + { 2, 48, 2, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, drc_coef_enabled_2ch, false }, +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE + { 2, 48, 2, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, drc_coef_pass_2ch, true }, + { 2, 48, 2, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, drc_coef_enabled_2ch, false }, +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE + { 2, 48, 2, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, drc_coef_pass_2ch, true }, + { 2, 48, 2, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, drc_coef_enabled_2ch, false }, +#endif /* CONFIG_FORMAT_S32LE */ +}; + +int main(void) +{ + int i; + + struct CMUnitTest tests[ARRAY_SIZE(parameters)]; + + for (i = 0; i < ARRAY_SIZE(parameters); i++) { + tests[i].name = "test_audio_drc"; + tests[i].test_func = test_audio_drc; + tests[i].setup_func = setup; + tests[i].teardown_func = teardown; + tests[i].initial_state = ¶meters[i]; + } + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, setup_group, NULL); +} From 5b67ca01a9156ad9a64f52410e2e916c46067c5d Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Fri, 10 Jul 2026 21:07:49 +0200 Subject: [PATCH 2/3] test(cmocka, drc): adopt test to use SOF API --- test/cmocka/src/audio/drc/drc_process.c | 327 ++++++++---------------- 1 file changed, 108 insertions(+), 219 deletions(-) diff --git a/test/cmocka/src/audio/drc/drc_process.c b/test/cmocka/src/audio/drc/drc_process.c index cb8174eee4c2..e8a5ff323406 100644 --- a/test/cmocka/src/audio/drc/drc_process.c +++ b/test/cmocka/src/audio/drc/drc_process.c @@ -19,10 +19,6 @@ #include "../../../include/cmocka_chirp_2ch.h" #include "cmocka_drc_coef.h" -/* Thresholds for frames count jitter for rand() function */ -#define THR_RAND_PLUS_ONE ((RAND_MAX >> 1) + (RAND_MAX >> 2)) -#define THR_RAND_MINUS_ONE ((RAND_MAX >> 1) - (RAND_MAX >> 2)) - /* Maximum absolute value of a signed 24 bit sample */ #define S24_MAX_ABS 0x800000 @@ -48,9 +44,8 @@ struct test_data { struct comp_buffer *sink; struct comp_buffer *source; struct test_parameters *params; - struct processing_module *mod; bool continue_loop; - int diff_count; /* enabled mode: samples that differ from input */ + int diff_count; /* enabled mode: output samples that differ from input */ }; static int setup_group(void **state) @@ -105,42 +100,16 @@ static int drc_send_config(struct processing_module *mod, const uint32_t *config return ret; } -static void prepare_sink(struct test_data *td, struct processing_module *mod) +static void prepare_buffers(struct test_data *td) { - struct test_parameters *parameters = td->params; - struct module_data *md = &mod->priv; - size_t size; - size_t free; - - size = parameters->frames * get_frame_bytes(parameters->sink_format, parameters->channels) * - parameters->buffer_size_mult; - - md->mpd.out_buff_size = parameters->frames * get_frame_bytes(parameters->sink_format, - parameters->channels); - - td->sink = create_test_sink(td->dev, 0, parameters->sink_format, - parameters->channels, size); - free = audio_stream_get_free_bytes(&td->sink->stream); - assert_int_equal(free, size); -} - -static void prepare_source(struct test_data *td, struct processing_module *mod) -{ - struct test_parameters *parameters = td->params; - struct module_data *md = &mod->priv; - size_t size; - size_t free; - - md->mpd.in_buff_size = parameters->frames * get_frame_bytes(parameters->source_format, - parameters->channels); - - size = parameters->frames * get_frame_bytes(parameters->source_format, - parameters->channels) * parameters->buffer_size_mult; - - td->source = create_test_source(td->dev, 0, parameters->source_format, - parameters->channels, size); - free = audio_stream_get_free_bytes(&td->source->stream); - assert_int_equal(free, size); + struct test_parameters *p = td->params; + size_t src_size = p->frames * get_frame_bytes(p->source_format, p->channels) * + p->buffer_size_mult; + size_t sink_size = p->frames * get_frame_bytes(p->sink_format, p->channels) * + p->buffer_size_mult; + + td->source = create_test_source(td->dev, 0, p->source_format, p->channels, src_size); + td->sink = create_test_sink(td->dev, 0, p->sink_format, p->channels, sink_size); } static int setup(void **state) @@ -163,11 +132,12 @@ static int setup(void **state) } memcpy_s(td->params, sizeof(*td->params), params, sizeof(*params)); - ipc = create_drc_comp_ipc(td); buffer_fill_data.idx = 0; buffer_verify_data.idx = 0; td->diff_count = 0; + td->continue_loop = true; + ipc = create_drc_comp_ipc(td); dev = comp_new((struct sof_ipc_comp *)ipc); free(ipc); if (!dev) { @@ -188,17 +158,7 @@ static int setup(void **state) return ret; } - prepare_sink(td, mod); - prepare_source(td, mod); - - /* allocate intermediate buffers */ - mod->input_buffers = test_malloc(sizeof(struct input_stream_buffer)); - mod->input_buffers[0].data = &td->source->stream; - mod->output_buffers = test_malloc(sizeof(struct output_stream_buffer)); - mod->output_buffers[0].data = &td->sink->stream; - mod->stream_params = test_malloc(sizeof(struct sof_ipc_stream_params)); - mod->stream_params->channels = params->channels; - mod->period_bytes = get_frame_bytes(params->source_format, params->channels) * 48000 / 1000; + prepare_buffers(td); ret = module_prepare(mod, NULL, 0, NULL, 0); if (ret) { @@ -210,8 +170,6 @@ static int setup(void **state) return ret; } - td->continue_loop = true; - *state = td; return 0; } @@ -219,12 +177,7 @@ static int setup(void **state) static int teardown(void **state) { struct test_data *td = *state; - struct processing_module *mod = comp_mod(td->dev); - test_free(mod->input_buffers); - test_free(mod->output_buffers); - test_free(mod->stream_params); - mod->stream_params = NULL; test_free(td->params); free_test_source(td->source); free_test_sink(td->sink); @@ -233,60 +186,49 @@ static int teardown(void **state) return 0; } +static void make_views(struct test_data *td, struct cir_buf_source *source_buf, + struct cir_buf_sink *sink_buf) +{ + struct audio_stream *ss = &td->source->stream; + struct audio_stream *ds = &td->sink->stream; + + source_buf->buf_start = audio_stream_get_addr(ss); + source_buf->buf_end = audio_stream_get_end_addr(ss); + source_buf->ptr = audio_stream_get_addr(ss); + + sink_buf->buf_start = audio_stream_get_addr(ds); + sink_buf->buf_end = audio_stream_get_end_addr(ds); + sink_buf->ptr = audio_stream_get_addr(ds); +} + #if CONFIG_FORMAT_S16LE -static void fill_source_s16(struct test_data *td, int frames_max) +static int fill_source_s16(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; - int16_t *x; - int bytes_total; - int samples; - int frames; + int16_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; int i; - int samples_processed = 0; - sb = comp_dev_get_first_data_producer(dev); - ss = &sb->stream; - frames = MIN(audio_stream_get_free_frames(ss), frames_max); - samples = frames * audio_stream_get_channels(ss); for (i = 0; i < samples; i++) { - x = audio_stream_write_frag_s16(ss, i); - *x = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 15)); - samples_processed++; + x[i] = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 15)); if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { td->continue_loop = false; + i++; break; } } - - if (samples_processed > 0) { - bytes_total = samples_processed * audio_stream_sample_bytes(ss); - comp_update_buffer_produce(sb, bytes_total); - } - - mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); + return i / td->params->channels; } -static void verify_sink_s16(struct test_data *td) +static void verify_sink_s16(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; + int16_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; int32_t ref; int32_t out; - int16_t *x; - int samples; int i; - sb = comp_dev_get_first_data_consumer(dev); - ss = &sb->stream; - samples = mod->output_buffers[0].size >> 1; for (i = 0; i < samples; i++) { - x = audio_stream_read_frag_s16(ss, i); - out = *x; + out = y[i]; ref = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx++], 31, 15)); if (td->params->passthrough) assert_int_equal(out, ref); @@ -297,59 +239,33 @@ static void verify_sink_s16(struct test_data *td) #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -static void fill_source_s24(struct test_data *td, int frames_max) +static int fill_source_s24(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; - int32_t *x; - int bytes_total; - int samples; - int frames; + int32_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; int i; - int samples_processed = 0; - sb = comp_dev_get_first_data_producer(dev); - ss = &sb->stream; - frames = MIN(audio_stream_get_free_frames(ss), frames_max); - samples = frames * audio_stream_get_channels(ss); for (i = 0; i < samples; i++) { - x = audio_stream_write_frag_s32(ss, i); - *x = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 23)); - samples_processed++; + x[i] = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 23)); if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { td->continue_loop = false; + i++; break; } } - - if (samples_processed > 0) { - bytes_total = samples_processed * audio_stream_sample_bytes(ss); - comp_update_buffer_produce(sb, bytes_total); - } - - mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); + return i / td->params->channels; } -static void verify_sink_s24(struct test_data *td) +static void verify_sink_s24(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; + int32_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; int32_t ref; int32_t out; - int32_t *x; - int samples; int i; - sb = comp_dev_get_first_data_consumer(dev); - ss = &sb->stream; - samples = mod->output_buffers[0].size >> 2; for (i = 0; i < samples; i++) { - x = audio_stream_read_frag_s32(ss, i); - out = (*x << 8) >> 8; /* Make sure there's no 24 bit overflow */ + out = (y[i] << 8) >> 8; /* Make sure there's no 24 bit overflow */ ref = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx++], 31, 23)); /* DRC must never produce a value outside of the 24 bit range */ assert_true(out < S24_MAX_ABS && out >= -S24_MAX_ABS); @@ -362,59 +278,33 @@ static void verify_sink_s24(struct test_data *td) #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -static void fill_source_s32(struct test_data *td, int frames_max) +static int fill_source_s32(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; - int32_t *x; - int bytes_total; - int samples; - int frames; + int32_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; int i; - int samples_processed = 0; - sb = comp_dev_get_first_data_producer(dev); - ss = &sb->stream; - frames = MIN(audio_stream_get_free_frames(ss), frames_max); - samples = frames * audio_stream_get_channels(ss); for (i = 0; i < samples; i++) { - x = audio_stream_write_frag_s32(ss, i); - *x = chirp_2ch[buffer_fill_data.idx++]; - samples_processed++; + x[i] = chirp_2ch[buffer_fill_data.idx++]; if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { td->continue_loop = false; + i++; break; } } - - if (samples_processed > 0) { - bytes_total = samples_processed * audio_stream_sample_bytes(ss); - comp_update_buffer_produce(sb, bytes_total); - } - - mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); + return i / td->params->channels; } -static void verify_sink_s32(struct test_data *td) +static void verify_sink_s32(struct test_data *td, int frames) { - struct processing_module *mod = comp_mod(td->dev); - struct comp_dev *dev = td->dev; - struct comp_buffer *sb; - struct audio_stream *ss; + int32_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; int32_t ref; int32_t out; - int32_t *x; - int samples; int i; - sb = comp_dev_get_first_data_consumer(dev); - ss = &sb->stream; - samples = mod->output_buffers[0].size >> 2; for (i = 0; i < samples; i++) { - x = audio_stream_read_frag_s32(ss, i); - out = *x; + out = y[i]; ref = chirp_2ch[buffer_verify_data.idx++]; if (td->params->passthrough) assert_int_equal(out, ref); @@ -424,70 +314,69 @@ static void verify_sink_s32(struct test_data *td) } #endif /* CONFIG_FORMAT_S32LE */ -static int frames_jitter(int frames) +static int fill_source(struct test_data *td, int frames) { - int r = rand(); - - if (r > THR_RAND_PLUS_ONE) - return frames + 1; - else if (r < THR_RAND_MINUS_ONE) - return frames - 1; - else - return frames; + switch (td->params->source_format) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + return fill_source_s16(td, frames); +#endif +#if CONFIG_FORMAT_S24LE + case SOF_IPC_FRAME_S24_4LE: + return fill_source_s24(td, frames); +#endif +#if CONFIG_FORMAT_S32LE + case SOF_IPC_FRAME_S32_LE: + return fill_source_s32(td, frames); +#endif + default: + assert(0); + return 0; + } +} + +static void verify_sink(struct test_data *td, int frames) +{ + switch (td->params->sink_format) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + verify_sink_s16(td, frames); + break; +#endif +#if CONFIG_FORMAT_S24LE + case SOF_IPC_FRAME_S24_4LE: + verify_sink_s24(td, frames); + break; +#endif +#if CONFIG_FORMAT_S32LE + case SOF_IPC_FRAME_S32_LE: + verify_sink_s32(td, frames); + break; +#endif + default: + assert(0); + break; + } } static void test_audio_drc(void **state) { struct test_data *td = *state; struct processing_module *mod = comp_mod(td->dev); - - struct comp_buffer *source = td->source; - struct comp_buffer *sink = td->sink; - int ret; + struct drc_comp_data *cd = module_get_private_data(mod); + struct cir_buf_source source_buf; + struct cir_buf_sink sink_buf; int frames; while (td->continue_loop) { - frames = frames_jitter(td->params->frames); - switch (audio_stream_get_frm_fmt(&source->stream)) { - case SOF_IPC_FRAME_S16_LE: - fill_source_s16(td, frames); - break; - case SOF_IPC_FRAME_S24_4LE: - fill_source_s24(td, frames); - break; - case SOF_IPC_FRAME_S32_LE: - fill_source_s32(td, frames); - break; - default: - assert(0); + frames = fill_source(td, td->params->frames); + if (frames <= 0) break; - } - - mod->input_buffers[0].consumed = 0; - mod->output_buffers[0].size = 0; - ret = module_process_legacy(mod, mod->input_buffers, 1, - mod->output_buffers, 1); - assert_int_equal(ret, 0); - comp_update_buffer_consume(source, mod->input_buffers[0].consumed); - comp_update_buffer_produce(sink, mod->output_buffers[0].size); - - switch (audio_stream_get_frm_fmt(&sink->stream)) { - case SOF_IPC_FRAME_S16_LE: - verify_sink_s16(td); - break; - case SOF_IPC_FRAME_S24_4LE: - verify_sink_s24(td); - break; - case SOF_IPC_FRAME_S32_LE: - verify_sink_s32(td); - break; - default: - assert(0); - break; - } + make_views(td, &source_buf, &sink_buf); + cd->drc_func(mod, &source_buf, &sink_buf, frames); - comp_update_buffer_consume(sink, mod->output_buffers[0].size); + verify_sink(td, frames); } /* An enabled DRC must actually change the signal, otherwise the From ce1d88e09991da410118994ea0e71e93cc277d12 Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Fri, 10 Jul 2026 21:12:47 +0200 Subject: [PATCH 3/3] audio: drc: switch to source/sink processing API Convert the DRC module from the legacy audio_stream processing API to the modern sof_source/sof_sink API. --- src/audio/drc/drc.c | 55 ++++++++++++---- src/audio/drc/drc.h | 11 ++-- src/audio/drc/drc_generic.c | 128 ++++++++++++++++++++---------------- src/audio/drc/drc_hifi4.c | 117 ++++++++++++++++++-------------- 4 files changed, 186 insertions(+), 125 deletions(-) diff --git a/src/audio/drc/drc.c b/src/audio/drc/drc.c index a727b68d55fd..b9bd27efd67f 100644 --- a/src/audio/drc/drc.c +++ b/src/audio/drc/drc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -269,16 +270,21 @@ __cold static int drc_get_config(struct processing_module *mod, } static int drc_process(struct processing_module *mod, - struct input_stream_buffer *input_buffers, - int num_input_buffers, - struct output_stream_buffer *output_buffers, - int num_output_buffers) + struct sof_source **sources, + int num_of_sources, + struct sof_sink **sinks, + int num_of_sinks) { struct drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct audio_stream *source = input_buffers[0].data; - struct audio_stream *sink = output_buffers[0].data; - int frames = input_buffers[0].size; + struct sof_source *source = sources[0]; + struct sof_sink *sink = sinks[0]; + struct cir_buf_source source_buf; + struct cir_buf_sink sink_buf; + size_t source_frame_bytes = source_get_frame_bytes(source); + size_t sink_frame_bytes = sink_get_frame_bytes(sink); + size_t source_bytes, sink_bytes, bytes; + uint32_t frames; int ret; comp_dbg(dev, "entry"); @@ -286,8 +292,8 @@ static int drc_process(struct processing_module *mod, /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = drc_setup(mod, audio_stream_get_channels(source), - audio_stream_get_rate(source)); + ret = drc_setup(mod, source_get_channels(source), + source_get_rate(source)); if (ret < 0) { comp_err(dev, "drc_copy(), failed DRC setup"); return ret; @@ -309,10 +315,32 @@ static int drc_process(struct processing_module *mod, /* Control pass-though in processing function with switch control */ cd->enabled = cd->config && cd->config->params.enabled && cd->enable_switch; - cd->drc_func(mod, source, sink, frames); + frames = source_sink_avail_frames_aligned(source, sink); + if (!frames) + return 0; + + source_bytes = frames * source_frame_bytes; + sink_bytes = frames * sink_frame_bytes; + + /* acquire source and sink circular buffers for the whole period */ + ret = source_get_data(source, source_bytes, &source_buf.ptr, + &source_buf.buf_start, &bytes); + if (ret < 0) + return ret; + source_buf.buf_end = (const char *)source_buf.buf_start + bytes; + + ret = sink_get_buffer(sink, sink_bytes, &sink_buf.ptr, &sink_buf.buf_start, &bytes); + if (ret < 0) { + source_release_data(source, 0); + return ret; + } + sink_buf.buf_end = (char *)sink_buf.buf_start + bytes; + + cd->drc_func(mod, &source_buf, &sink_buf, frames); - /* calc new free and available */ - module_update_buffer_position(&input_buffers[0], &output_buffers[0], frames); + /* commit the consumed and produced data */ + source_release_data(source, source_bytes); + sink_commit_buffer(sink, sink_bytes); return 0; } @@ -367,6 +395,7 @@ static int drc_prepare(struct processing_module *mod, cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); channels = audio_stream_get_channels(&sinkb->stream); rate = audio_stream_get_rate(&sinkb->stream); + cd->channels = channels; /* Initialize DRC */ comp_info(dev, "source_format=%d", cd->source_format); @@ -414,7 +443,7 @@ static int drc_reset(struct processing_module *mod) static const struct module_interface drc_interface = { .init = drc_init, .prepare = drc_prepare, - .process_audio_stream = drc_process, + .process = drc_process, .set_configuration = drc_set_config, .get_configuration = drc_get_config, .reset = drc_reset, diff --git a/src/audio/drc/drc.h b/src/audio/drc/drc.h index 5598d64c87de..140877b21895 100644 --- a/src/audio/drc/drc.h +++ b/src/audio/drc/drc.h @@ -15,6 +15,8 @@ #include "drc_user.h" struct audio_stream; +struct cir_buf_source; +struct cir_buf_sink; struct comp_dev; /* Define CONFIG_DRC_MAX_PRE_DELAY_FRAMES for the build purposes without Kconfig, @@ -66,8 +68,8 @@ struct drc_state { }; typedef void (*drc_func)(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames); /* DRC component private data */ @@ -79,6 +81,7 @@ struct drc_comp_data { bool enabled; /**< control processing via blob and switch */ bool enable_switch; /**< enable switch state */ enum sof_ipc_frame source_format; /**< source frame format */ + int channels; /**< number of channels */ drc_func drc_func; /**< processing function */ }; @@ -91,8 +94,8 @@ extern const struct drc_proc_fnmap drc_proc_fnmap[]; extern const size_t drc_proc_fncount; void drc_default_pass(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, uint32_t frames); + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames); /** * \brief Returns DRC processing function. */ diff --git a/src/audio/drc/drc_generic.c b/src/audio/drc/drc_generic.c index 8ace19623045..182d2300a211 100644 --- a/src/audio/drc/drc_generic.c +++ b/src/audio/drc/drc_generic.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "drc.h" @@ -471,10 +472,26 @@ static void drc_process_one_division(struct drc_state *state, } void drc_default_pass(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, uint32_t frames) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); + struct drc_comp_data *cd = module_get_private_data(mod); + const int sample_bytes = get_sample_bytes(cd->source_format); + size_t bytes = (size_t)frames * cd->channels * sample_bytes; + const uint8_t *src = source->ptr; + uint8_t *dst = sink->ptr; + int n; + + while (bytes) { + n = MIN((const uint8_t *)source->buf_end - src, + (uint8_t *)sink->buf_end - dst); + n = MIN(n, bytes); + memcpy_s(dst, n, src, n); + src = cir_buf_wrap((void *)(src + n), (void *)source->buf_start, + (void *)source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + bytes -= n; + } } static inline void drc_pre_delay_index_inc(int *idx, int increment) @@ -484,26 +501,25 @@ static inline void drc_pre_delay_index_inc(int *idx, int increment) #if CONFIG_FORMAT_S16LE static void drc_delay_input_sample_s16(struct drc_state *state, - const struct audio_stream *source, - struct audio_stream *sink, - int16_t **x, int16_t **y, int samples) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, + const int16_t **x, int16_t **y, int samples, int nch) { - int16_t *x1; + const int16_t *x1; int16_t *y1; int16_t *pd; int pd_write_index, pd_read_index; int nbuf, npcm, nfrm; int ch; int i; - int16_t *x0 = *x; + const int16_t *x0 = *x; int16_t *y0 = *y; int remaining_samples = samples; - int nch = audio_stream_get_channels(source); while (remaining_samples) { - nbuf = audio_stream_samples_without_wrap_s16(source, x0); + nbuf = cir_buf_samples_without_wrap_s16(x0, source->buf_end); npcm = MIN(remaining_samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s16(sink, y0); + nbuf = cir_buf_samples_without_wrap_s16(y0, sink->buf_end); npcm = MIN(npcm, nbuf); nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { @@ -522,8 +538,8 @@ static void drc_delay_input_sample_s16(struct drc_state *state, } } remaining_samples -= npcm; - x0 = audio_stream_wrap(source, x0 + npcm); - y0 = audio_stream_wrap(sink, y0 + npcm); + x0 = cir_buf_wrap(x0 + npcm, source->buf_start, source->buf_end); + y0 = cir_buf_wrap(y0 + npcm, sink->buf_start, sink->buf_end); drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } @@ -533,15 +549,15 @@ static void drc_delay_input_sample_s16(struct drc_state *state, } static void drc_s16_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int16_t *x = audio_stream_get_rptr(source); - int16_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); - int samples = frames * nch; struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + const int16_t *x = (int16_t *)source->ptr; + int16_t *y = (int16_t *)sink->ptr; + int samples = frames * nch; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment_samples; @@ -552,7 +568,7 @@ static void drc_s16_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - drc_delay_input_sample_s16(state, source, sink, &x, &y, samples); + drc_delay_input_sample_s16(state, source, sink, &x, &y, samples, nch); return; } @@ -567,7 +583,7 @@ static void drc_s16_default(struct processing_module *mod, (state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK); fragment_samples = fragment * nch; fragment_samples = MIN(samples, fragment_samples); - drc_delay_input_sample_s16(state, source, sink, &x, &y, fragment_samples); + drc_delay_input_sample_s16(state, source, sink, &x, &y, fragment_samples, nch); samples -= fragment_samples; /* Process the input division (32 frames). */ @@ -579,26 +595,25 @@ static void drc_s16_default(struct processing_module *mod, #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE static void drc_delay_input_sample_s32(struct drc_state *state, - const struct audio_stream *source, - struct audio_stream *sink, - int32_t **x, int32_t **y, int samples) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, + const int32_t **x, int32_t **y, int samples, int nch) { - int32_t *x1; + const int32_t *x1; int32_t *y1; int32_t *pd; int pd_write_index, pd_read_index; int nbuf, npcm, nfrm; int ch; int i; - int32_t *x0 = *x; + const int32_t *x0 = *x; int32_t *y0 = *y; int remaining_samples = samples; - int nch = audio_stream_get_channels(source); while (remaining_samples) { - nbuf = audio_stream_samples_without_wrap_s32(source, x0); + nbuf = cir_buf_samples_without_wrap_s32(x0, source->buf_end); npcm = MIN(remaining_samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s32(sink, y0); + nbuf = cir_buf_samples_without_wrap_s32(y0, sink->buf_end); npcm = MIN(npcm, nbuf); nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { @@ -617,8 +632,8 @@ static void drc_delay_input_sample_s32(struct drc_state *state, } } remaining_samples -= npcm; - x0 = audio_stream_wrap(source, x0 + npcm); - y0 = audio_stream_wrap(sink, y0 + npcm); + x0 = cir_buf_wrap(x0 + npcm, source->buf_start, source->buf_end); + y0 = cir_buf_wrap(y0 + npcm, sink->buf_start, sink->buf_end); drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } @@ -630,26 +645,25 @@ static void drc_delay_input_sample_s32(struct drc_state *state, #if CONFIG_FORMAT_S24LE static void drc_delay_input_sample_s24(struct drc_state *state, - const struct audio_stream *source, - struct audio_stream *sink, - int32_t **x, int32_t **y, int samples) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, + const int32_t **x, int32_t **y, int samples, int nch) { - int32_t *x1; + const int32_t *x1; int32_t *y1; int32_t *pd; int pd_write_index, pd_read_index; int nbuf, npcm, nfrm; int ch; int i; - int32_t *x0 = *x; + const int32_t *x0 = *x; int32_t *y0 = *y; int remaining_samples = samples; - int nch = audio_stream_get_channels(source); while (remaining_samples) { - nbuf = audio_stream_samples_without_wrap_s24(source, x0); + nbuf = cir_buf_samples_without_wrap_s32(x0, source->buf_end); npcm = MIN(remaining_samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s24(sink, y0); + nbuf = cir_buf_samples_without_wrap_s32(y0, sink->buf_end); npcm = MIN(npcm, nbuf); nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { @@ -668,8 +682,8 @@ static void drc_delay_input_sample_s24(struct drc_state *state, } } remaining_samples -= npcm; - x0 = audio_stream_wrap(source, x0 + npcm); - y0 = audio_stream_wrap(sink, y0 + npcm); + x0 = cir_buf_wrap(x0 + npcm, source->buf_start, source->buf_end); + y0 = cir_buf_wrap(y0 + npcm, sink->buf_start, sink->buf_end); drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } @@ -679,15 +693,15 @@ static void drc_delay_input_sample_s24(struct drc_state *state, } static void drc_s24_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); - int samples = frames * nch; struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + const int32_t *x = (int32_t *)source->ptr; + int32_t *y = (int32_t *)sink->ptr; + int samples = frames * nch; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment_samples; @@ -698,7 +712,7 @@ static void drc_s24_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. Note: use 32 bit delay function. */ - drc_delay_input_sample_s32(state, source, sink, &x, &y, samples); + drc_delay_input_sample_s32(state, source, sink, &x, &y, samples, nch); return; } @@ -715,7 +729,7 @@ static void drc_s24_default(struct processing_module *mod, fragment_samples = MIN(samples, fragment_samples); /* Use 24 bit delay function */ - drc_delay_input_sample_s24(state, source, sink, &x, &y, fragment_samples); + drc_delay_input_sample_s24(state, source, sink, &x, &y, fragment_samples, nch); samples -= fragment_samples; /* Process the input division (32 frames). */ @@ -727,15 +741,15 @@ static void drc_s24_default(struct processing_module *mod, #if CONFIG_FORMAT_S32LE static void drc_s32_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); - int samples = frames * nch; struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + const int32_t *x = (int32_t *)source->ptr; + int32_t *y = (int32_t *)sink->ptr; + int samples = frames * nch; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment_samples; @@ -746,7 +760,7 @@ static void drc_s32_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - drc_delay_input_sample_s32(state, source, sink, &x, &y, samples); + drc_delay_input_sample_s32(state, source, sink, &x, &y, samples, nch); return; } @@ -761,7 +775,7 @@ static void drc_s32_default(struct processing_module *mod, (state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK); fragment_samples = fragment * nch; fragment_samples = MIN(samples, fragment_samples); - drc_delay_input_sample_s32(state, source, sink, &x, &y, fragment_samples); + drc_delay_input_sample_s32(state, source, sink, &x, &y, fragment_samples, nch); samples -= fragment_samples; /* Process the input division (32 frames). */ diff --git a/src/audio/drc/drc_hifi4.c b/src/audio/drc/drc_hifi4.c index a4c32c0deb15..63b189d3114a 100644 --- a/src/audio/drc/drc_hifi4.c +++ b/src/audio/drc/drc_hifi4.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "drc.h" @@ -525,10 +526,26 @@ static void drc_process_one_division(struct drc_state *state, } void drc_default_pass(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, uint32_t frames) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); + struct drc_comp_data *cd = module_get_private_data(mod); + const int sample_bytes = get_sample_bytes(cd->source_format); + size_t bytes = (size_t)frames * cd->channels * sample_bytes; + const uint8_t *src = source->ptr; + uint8_t *dst = sink->ptr; + int n; + + while (bytes) { + n = MIN((const uint8_t *)source->buf_end - src, + (uint8_t *)sink->buf_end - dst); + n = MIN(n, bytes); + memcpy_s(dst, n, src, n); + src = cir_buf_wrap((void *)(src + n), (void *)source->buf_start, + (void *)source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + bytes -= n; + } } static inline void drc_pre_delay_index_inc(int *idx, int increment) @@ -538,9 +555,9 @@ static inline void drc_pre_delay_index_inc(int *idx, int increment) #if CONFIG_FORMAT_S16LE static void drc_delay_input_sample_s16(struct drc_state *state, - const struct audio_stream *source, - struct audio_stream *sink, - int16_t **x, int16_t **y, int samples) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, + int16_t **x, int16_t **y, int samples, int nch) { ae_int16 *x1; ae_int16 *y1; @@ -553,15 +570,14 @@ static void drc_delay_input_sample_s16(struct drc_state *state, ae_int16 *x0 = (ae_int16 *)*x; ae_int16 *y0 = (ae_int16 *)*y; int remaining_samples = samples; - int nch = audio_stream_get_channels(source); const int sample_inc = nch * sizeof(int16_t); const int delay_inc = sizeof(int16_t); ae_int16x4 sample; while (remaining_samples) { - nbuf = audio_stream_samples_without_wrap_s16(source, x0); + nbuf = cir_buf_samples_without_wrap_s16(x0, source->buf_end); npcm = MIN(remaining_samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s16(sink, y0); + nbuf = cir_buf_samples_without_wrap_s16(y0, sink->buf_end); npcm = MIN(npcm, nbuf); nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { @@ -580,8 +596,8 @@ static void drc_delay_input_sample_s16(struct drc_state *state, } } remaining_samples -= npcm; - x0 = audio_stream_wrap(source, x0 + npcm); - y0 = audio_stream_wrap(sink, y0 + npcm); + x0 = cir_buf_wrap(x0 + npcm, source->buf_start, source->buf_end); + y0 = cir_buf_wrap(y0 + npcm, sink->buf_start, sink->buf_end); drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } @@ -591,15 +607,15 @@ static void drc_delay_input_sample_s16(struct drc_state *state, } static void drc_s16_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int16_t *x = audio_stream_get_rptr(source); - int16_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); - int samples = frames * nch; struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + int16_t *x = (int16_t *)source->ptr; + int16_t *y = (int16_t *)sink->ptr; + int samples = frames * nch; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment; @@ -618,7 +634,7 @@ static void drc_s16_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - drc_delay_input_sample_s16(state, source, sink, &x, &y, samples); + drc_delay_input_sample_s16(state, source, sink, &x, &y, samples, nch); return; } @@ -628,8 +644,8 @@ static void drc_s16_default(struct processing_module *mod, state->processed = 1; } - set_circular_buf0(source->addr, source->end_addr); - set_circular_buf1(sink->addr, sink->end_addr); + set_circular_buf0((void *)source->buf_start, (void *)source->buf_end); + set_circular_buf1(sink->buf_start, sink->buf_end); while (frames) { fragment = DRC_DIVISION_FRAMES - @@ -659,8 +675,8 @@ static void drc_s16_default(struct processing_module *mod, } drc_pre_delay_index_inc(&state->pre_delay_write_index, fragment); drc_pre_delay_index_inc(&state->pre_delay_read_index, fragment); - x = audio_stream_wrap(source, x + fragment * nch); - y = audio_stream_wrap(sink, y + fragment * nch); + x = cir_buf_wrap(x + fragment * nch, source->buf_start, source->buf_end); + y = cir_buf_wrap(y + fragment * nch, sink->buf_start, sink->buf_end); frames -= fragment; /* Process the input division (32 frames). */ @@ -672,9 +688,9 @@ static void drc_s16_default(struct processing_module *mod, #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE static void drc_delay_input_sample_s32(struct drc_state *state, - const struct audio_stream *source, - struct audio_stream *sink, - int32_t **x, int32_t **y, int samples) + const struct cir_buf_source *source, + struct cir_buf_sink *sink, + int32_t **x, int32_t **y, int samples, int nch) { ae_int32 *x1; ae_int32 *y1; @@ -689,14 +705,13 @@ static void drc_delay_input_sample_s32(struct drc_state *state, ae_int32x2 sample; int remaining_samples = samples; - int nch = audio_stream_get_channels(source); const int sample_inc = nch * sizeof(int32_t); const int delay_inc = sizeof(int32_t); while (remaining_samples) { - nbuf = audio_stream_samples_without_wrap_s32(source, x0); + nbuf = cir_buf_samples_without_wrap_s32(x0, source->buf_end); npcm = MIN(remaining_samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s32(sink, y0); + nbuf = cir_buf_samples_without_wrap_s32(y0, sink->buf_end); npcm = MIN(npcm, nbuf); nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { @@ -718,8 +733,8 @@ static void drc_delay_input_sample_s32(struct drc_state *state, } } remaining_samples -= npcm; - x0 = audio_stream_wrap(source, x0 + npcm); - y0 = audio_stream_wrap(sink, y0 + npcm); + x0 = cir_buf_wrap(x0 + npcm, source->buf_start, source->buf_end); + y0 = cir_buf_wrap(y0 + npcm, sink->buf_start, sink->buf_end); drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } @@ -732,15 +747,15 @@ static void drc_delay_input_sample_s32(struct drc_state *state, #if CONFIG_FORMAT_S24LE static void drc_s24_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); - int samples = frames * nch; struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + int32_t *x = (int32_t *)source->ptr; + int32_t *y = (int32_t *)sink->ptr; + int samples = frames * nch; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment; @@ -759,7 +774,7 @@ static void drc_s24_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. Note: use 32 bit delay function. */ - drc_delay_input_sample_s32(state, source, sink, &x, &y, samples); + drc_delay_input_sample_s32(state, source, sink, &x, &y, samples, nch); return; } @@ -769,8 +784,8 @@ static void drc_s24_default(struct processing_module *mod, state->processed = 1; } - set_circular_buf0(source->addr, source->end_addr); - set_circular_buf1(sink->addr, sink->end_addr); + set_circular_buf0((void *)source->buf_start, (void *)source->buf_end); + set_circular_buf1(sink->buf_start, sink->buf_end); while (frames) { fragment = DRC_DIVISION_FRAMES - @@ -807,8 +822,8 @@ static void drc_s24_default(struct processing_module *mod, } drc_pre_delay_index_inc(&state->pre_delay_write_index, fragment); drc_pre_delay_index_inc(&state->pre_delay_read_index, fragment); - x = audio_stream_wrap(source, x + fragment * nch); - y = audio_stream_wrap(sink, y + fragment * nch); + x = cir_buf_wrap(x + fragment * nch, source->buf_start, source->buf_end); + y = cir_buf_wrap(y + fragment * nch, sink->buf_start, sink->buf_end); frames -= fragment; /* Process the input division (32 frames). */ @@ -820,14 +835,14 @@ static void drc_s24_default(struct processing_module *mod, #if CONFIG_FORMAT_S32LE static void drc_s32_default(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, + const struct cir_buf_source *source, + struct cir_buf_sink *sink, uint32_t frames) { - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int nch = audio_stream_get_channels(source); struct drc_comp_data *cd = module_get_private_data(mod); + int nch = cd->channels; + int32_t *x = (int32_t *)source->ptr; + int32_t *y = (int32_t *)sink->ptr; struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ int fragment; @@ -846,7 +861,7 @@ static void drc_s32_default(struct processing_module *mod, * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - drc_delay_input_sample_s32(state, source, sink, &x, &y, frames * nch); + drc_delay_input_sample_s32(state, source, sink, &x, &y, frames * nch, nch); return; } @@ -856,8 +871,8 @@ static void drc_s32_default(struct processing_module *mod, state->processed = 1; } - set_circular_buf0(source->addr, source->end_addr); - set_circular_buf1(sink->addr, sink->end_addr); + set_circular_buf0((void *)source->buf_start, (void *)source->buf_end); + set_circular_buf1(sink->buf_start, sink->buf_end); while (frames) { fragment = DRC_DIVISION_FRAMES - @@ -889,8 +904,8 @@ static void drc_s32_default(struct processing_module *mod, } drc_pre_delay_index_inc(&state->pre_delay_write_index, fragment); drc_pre_delay_index_inc(&state->pre_delay_read_index, fragment); - x = audio_stream_wrap(source, x + fragment * nch); - y = audio_stream_wrap(sink, y + fragment * nch); + x = cir_buf_wrap(x + fragment * nch, source->buf_start, source->buf_end); + y = cir_buf_wrap(y + fragment * nch, sink->buf_start, sink->buf_end); frames -= fragment; /* Process the input division (32 frames). */