From 38508fcebbe05cac7c35c0f0b349c8a7623a8491 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Thu, 19 Oct 2023 11:59:24 +0800 Subject: [PATCH] audio: eq_iir: create generic/ipc3/ipc4 source files for eq_iir Create generic ipc3 ipc4 source files and move related code into these source files. Signed-off-by: Baofeng Tian --- src/audio/CMakeLists.txt | 2 + src/audio/eq_iir/CMakeLists.txt | 7 +- src/audio/eq_iir/eq_iir.c | 692 +----------------- src/audio/eq_iir/eq_iir.h | 16 + src/audio/eq_iir/eq_iir_generic.c | 346 +++++++++ src/audio/eq_iir/eq_iir_ipc3.c | 336 +++++++++ src/audio/eq_iir/eq_iir_ipc4.c | 151 ++++ test/cmocka/src/audio/eq_iir/CMakeLists.txt | 2 + test/cmocka/src/audio/eq_iir/eq_iir_process.c | 2 +- zephyr/CMakeLists.txt | 16 +- 10 files changed, 874 insertions(+), 696 deletions(-) create mode 100644 src/audio/eq_iir/eq_iir_generic.c create mode 100644 src/audio/eq_iir/eq_iir_ipc3.c create mode 100644 src/audio/eq_iir/eq_iir_ipc4.c diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 7e58fd55d929..425756f7e4d5 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -175,9 +175,11 @@ set(sof_audio_modules mixer volume src asrc eq-fir eq-iir dcblock crossover tdfb if(CONFIG_IPC_MAJOR_3) set(volume_sources volume/volume.c volume/volume_generic.c volume/volume_ipc3.c) set(src_sources src/src.c src/src_ipc3.c src/src_generic.c) + set(eq-iir_sources eq_iir/eq_iir_ipc3.c eq_iir/eq_iir_generic.c) elseif(CONFIG_IPC_MAJOR_4) set(volume_sources volume/volume.c volume/volume_generic.c volume/volume_ipc4.c) set(src_sources src/src.c src/src_ipc4.c src/src_generic.c) + set(eq-iir_sources eq_iir/eq_iir_ipc4.c eq_iir/eq_iir_generic.c) endif() set(mixer_sources ${mixer_src}) set(asrc_sources asrc/asrc.c asrc/asrc_farrow.c asrc/asrc_farrow_generic.c) diff --git a/src/audio/eq_iir/CMakeLists.txt b/src/audio/eq_iir/CMakeLists.txt index 498946370528..0c9853540ad5 100644 --- a/src/audio/eq_iir/CMakeLists.txt +++ b/src/audio/eq_iir/CMakeLists.txt @@ -1,3 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof eq_iir.c) +add_local_sources(sof eq_iir.c eq_iir_generic.c) +if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof eq_iir_ipc3.c) +elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof eq_iir_ipc4.c) +endif() diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 0bd8dc82bfe9..2a91a08165a2 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -43,575 +43,6 @@ DECLARE_SOF_RT_UUID("eq-iir", eq_iir_uuid, 0x5150c0e6, 0x27f9, 0x4ec8, DECLARE_TR_CTX(eq_iir_tr, SOF_UUID(eq_iir_uuid), LOG_LEVEL_INFO); -#if CONFIG_FORMAT_S16LE - -/* - * EQ IIR algorithm code - */ - -void eq_iir_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - struct iir_state_df1 *filter; - int16_t *x0; - int16_t *y0; - int16_t *x; - int16_t *y; - int nmax; - int n1; - int n2; - int i; - int j; - int n; - const int nch = audio_stream_get_channels(source); - const int samples = frames * nch; - int processed = 0; - - x = audio_stream_get_rptr(source); - y = audio_stream_get_wptr(sink); - while (processed < samples) { - nmax = samples - processed; - n1 = audio_stream_bytes_without_wrap(source, x) >> 1; - n2 = audio_stream_bytes_without_wrap(sink, y) >> 1; - n = MIN(n1, n2); - n = MIN(n, nmax); - for (i = 0; i < nch; i++) { - x0 = x + i; - y0 = y + i; - filter = &cd->iir[i]; - for (j = 0; j < n; j += nch) { - *y0 = iir_df1_s16(filter, *x0); - x0 += nch; - y0 += nch; - } - } - processed += n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); - } -} -#endif /* CONFIG_FORMAT_S16LE */ - -#if CONFIG_FORMAT_S24LE - -void eq_iir_s24_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - struct iir_state_df1 *filter; - int32_t *x0; - int32_t *y0; - int32_t *x; - int32_t *y; - int nmax; - int n1; - int n2; - int i; - int j; - int n; - const int nch = audio_stream_get_channels(source); - const int samples = frames * nch; - int processed = 0; - - x = audio_stream_get_rptr(source); - y = audio_stream_get_wptr(sink); - while (processed < samples) { - nmax = samples - processed; - n1 = audio_stream_bytes_without_wrap(source, x) >> 2; - n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; - n = MIN(n1, n2); - n = MIN(n, nmax); - for (i = 0; i < nch; i++) { - x0 = x + i; - y0 = y + i; - filter = &cd->iir[i]; - for (j = 0; j < n; j += nch) { - *y0 = iir_df1_s24(filter, *x0); - x0 += nch; - y0 += nch; - } - } - processed += n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); - } -} -#endif /* CONFIG_FORMAT_S24LE */ - -#if CONFIG_FORMAT_S32LE - -void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - struct iir_state_df1 *filter; - int32_t *x0; - int32_t *y0; - int32_t *x; - int32_t *y; - int nmax; - int n1; - int n2; - int i; - int j; - int n; - const int nch = audio_stream_get_channels(source); - const int samples = frames * nch; - int processed = 0; - - x = audio_stream_get_rptr(source); - y = audio_stream_get_wptr(sink); - while (processed < samples) { - nmax = samples - processed; - n1 = audio_stream_bytes_without_wrap(source, x) >> 2; - n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; - n = MIN(n1, n2); - n = MIN(n, nmax); - for (i = 0; i < nch; i++) { - x0 = x + i; - y0 = y + i; - filter = &cd->iir[i]; - for (j = 0; j < n; j += nch) { - *y0 = iir_df1(filter, *x0); - x0 += nch; - y0 += nch; - } - } - processed += n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); - } -} -#endif /* CONFIG_FORMAT_S32LE */ - -#if CONFIG_IPC_MAJOR_3 -#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE -static void eq_iir_s32_16_default(struct processing_module *mod, - struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - struct iir_state_df1 *filter; - int32_t *x0; - int16_t *y0; - int32_t *x; - int16_t *y; - int nmax; - int n1; - int n2; - int i; - int j; - int n; - const int nch = audio_stream_get_channels(source); - const int samples = frames * nch; - int processed = 0; - - x = audio_stream_get_rptr(source); - y = audio_stream_get_wptr(sink); - while (processed < samples) { - nmax = samples - processed; - n1 = audio_stream_bytes_without_wrap(source, x) >> 2; /* divide 4 */ - n2 = audio_stream_bytes_without_wrap(sink, y) >> 1; /* divide 2 */ - n = MIN(n1, n2); - n = MIN(n, nmax); - for (i = 0; i < nch; i++) { - x0 = x + i; - y0 = y + i; - filter = &cd->iir[i]; - for (j = 0; j < n; j += nch) { - *y0 = iir_df1_s32_s16(filter, *x0); - x0 += nch; - y0 += nch; - } - } - processed += n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); - } -} -#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE */ - -#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE -static void eq_iir_s32_24_default(struct processing_module *mod, - struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - struct iir_state_df1 *filter; - int32_t *x0; - int32_t *y0; - int32_t *x; - int32_t *y; - int nmax; - int n1; - int n2; - int i; - int j; - int n; - const int nch = audio_stream_get_channels(source); - const int samples = frames * nch; - int processed = 0; - - x = audio_stream_get_rptr(source); - y = audio_stream_get_wptr(sink); - while (processed < samples) { - nmax = samples - processed; - n1 = audio_stream_bytes_without_wrap(source, x) >> 2; - n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; - n = MIN(n1, n2); - n = MIN(n, nmax); - for (i = 0; i < nch; i++) { - x0 = x + i; - y0 = y + i; - filter = &cd->iir[i]; - for (j = 0; j < n; j += nch) { - *y0 = iir_df1_s32_s24(filter, *x0); - x0 += nch; - y0 += nch; - } - } - processed += n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); - } -} -#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE */ -#endif /* CONFIG_IPC_MAJOR_3 */ - -static void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - - audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); -} - -#if CONFIG_IPC_MAJOR_3 -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE -static void eq_iir_s32_s16_pass(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - int32_t *x = audio_stream_get_rptr(source); - int16_t *y = audio_stream_get_wptr(sink); - int nmax; - int n; - int i; - int remaining_samples = frames * audio_stream_get_channels(source); - - while (remaining_samples) { - nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(source, x)); - n = MIN(remaining_samples, nmax); - nmax = EQ_IIR_BYTES_TO_S16_SAMPLES(audio_stream_bytes_without_wrap(sink, y)); - n = MIN(n, nmax); - for (i = 0; i < n; i++) { - *y = sat_int16(Q_SHIFT_RND(*x, 31, 15)); - x++; - y++; - } - remaining_samples -= n; - x = audio_stream_wrap(source, x); - y = audio_stream_wrap(sink, y); - } -} -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ - -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE -static void eq_iir_s32_s24_pass(struct processing_module *mod, struct input_stream_buffer *bsource, - struct output_stream_buffer *bsink, uint32_t frames) -{ - struct audio_stream *source = bsource->data; - struct audio_stream *sink = bsink->data; - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int nmax; - int n; - int i; - int remaining_samples = frames * audio_stream_get_channels(source); - - while (remaining_samples) { - nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(source, x)); - n = MIN(remaining_samples, nmax); - nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(sink, y)); - n = MIN(n, nmax); - for (i = 0; i < n; i++) { - *y = sat_int24(Q_SHIFT_RND(*x, 31, 23)); - x++; - y++; - } - remaining_samples -= n; - x = audio_stream_wrap(source, x); - y = audio_stream_wrap(sink, y); - } -} -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ -#endif /* CONFIG_IPC_MAJOR_3 */ - -#if CONFIG_IPC_MAJOR_3 -const struct eq_iir_func_map fm_configured[] = { -#if CONFIG_FORMAT_S16LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s16_default}, -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, NULL}, - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, NULL}, - -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, NULL}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s32_16_default}, -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s24_default}, -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, NULL}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s32_24_default}, -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, eq_iir_s32_default}, -#endif /* CONFIG_FORMAT_S32LE */ -}; - -const struct eq_iir_func_map fm_passthrough[] = { -#if CONFIG_FORMAT_S16LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, eq_iir_pass}, -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, NULL}, - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, NULL}, - -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE*/ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, NULL}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s32_s16_pass}, -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE*/ -#if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, eq_iir_pass}, -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, NULL}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s32_s24_pass}, -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, eq_iir_pass}, -#endif /* CONFIG_FORMAT_S32LE */ -}; - -static eq_iir_func eq_iir_find_func(enum sof_ipc_frame source_format, - enum sof_ipc_frame sink_format, - const struct eq_iir_func_map *map, - int n) -{ - int i; - - /* Find suitable processing function from map. */ - for (i = 0; i < n; i++) { - if ((uint8_t)source_format != map[i].source) - continue; - if ((uint8_t)sink_format != map[i].sink) - continue; - - return map[i].func; - } - - return NULL; -} - -#elif CONFIG_IPC_MAJOR_4 - -static eq_iir_func eq_iir_find_func(struct processing_module *mod) -{ - unsigned int valid_bit_depth = mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth; - - comp_dbg(mod->dev, "eq_iir_find_func(): valid_bit_depth %d", valid_bit_depth); - switch (valid_bit_depth) { -#if CONFIG_FORMAT_S16LE - case IPC4_DEPTH_16BIT: - return eq_iir_s16_default; -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE - case IPC4_DEPTH_24BIT: - return eq_iir_s24_default; -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - case IPC4_DEPTH_32BIT: - return eq_iir_s32_default; -#endif /* CONFIG_FORMAT_S32LE */ - default: - comp_err(mod->dev, "set_fir_func(), invalid valid_bith_depth"); - } - return NULL; -} -#endif /* CONFIG_IPC_MAJOR_4 */ - -static void eq_iir_free_delaylines(struct comp_data *cd) -{ - struct iir_state_df1 *iir = cd->iir; - int i = 0; - - /* Free the common buffer for all EQs and point then - * each IIR channel delay line to NULL. - */ - rfree(cd->iir_delay); - cd->iir_delay = NULL; - cd->iir_delay_size = 0; - for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - iir[i].delay = NULL; -} - -static int eq_iir_init_coef(struct processing_module *mod, int nch) -{ - struct comp_data *cd = module_get_private_data(mod); - struct sof_eq_iir_config *config = cd->config; - struct iir_state_df1 *iir = cd->iir; - struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES]; - struct sof_eq_iir_header *eq; - int32_t *assign_response; - int32_t *coef_data; - int size_sum = 0; - int resp = 0; - int i; - int j; - int s; - - comp_info(mod->dev, "eq_iir_init_coef(): %u responses, %u channels, stream %d channels", - config->number_of_responses, config->channels_in_config, nch); - - /* Sanity checks */ - if (nch > PLATFORM_MAX_CHANNELS || - config->channels_in_config > PLATFORM_MAX_CHANNELS || - !config->channels_in_config) { - comp_err(mod->dev, "eq_iir_init_coef(), invalid channels count"); - return -EINVAL; - } - if (config->number_of_responses > SOF_EQ_IIR_MAX_RESPONSES) { - comp_err(mod->dev, "eq_iir_init_coef(), # of resp exceeds max"); - return -EINVAL; - } - - /* Collect index of response start positions in all_coefficients[] */ - j = 0; - assign_response = ASSUME_ALIGNED(&config->data[0], 4); - coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], - 4); - for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) { - if (i < config->number_of_responses) { - eq = (struct sof_eq_iir_header *)&coef_data[j]; - lookup[i] = eq; - j += SOF_EQ_IIR_NHEADER - + SOF_EQ_IIR_NBIQUAD * eq->num_sections; - } else { - lookup[i] = NULL; - } - } - - /* Initialize 1st phase */ - for (i = 0; i < nch; i++) { - /* Check for not reading past blob response to channel assign - * map. The previous channel response is assigned for any - * additional channels in the stream. It allows to use single - * channel configuration to setup multi channel equalization - * with the same response. - */ - if (i < config->channels_in_config) - resp = assign_response[i]; - - if (resp < 0) { - /* Initialize EQ channel to bypass and continue with - * next channel response. - */ - comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to bypass", i); - iir_reset_df1(&iir[i]); - continue; - } - - if (resp >= config->number_of_responses) { - comp_err(mod->dev, "eq_iir_init_coef(), requested response %d exceeds defined", - resp); - return -EINVAL; - } - - /* Initialize EQ coefficients */ - eq = lookup[resp]; - s = iir_delay_size_df1(eq); - if (s > 0) { - size_sum += s; - } else { - comp_err(mod->dev, "eq_iir_init_coef(), sections count %d exceeds max", - eq->num_sections); - return -EINVAL; - } - - iir_init_coef_df1(&iir[i], eq); - comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to response %d", i, resp); - } - - return size_sum; -} - -static void eq_iir_init_delay(struct iir_state_df1 *iir, - int32_t *delay_start, int nch) -{ - int32_t *delay = delay_start; - int i; - - /* Initialize second phase to set EQ delay lines pointers. A - * bypass mode filter is indicated by biquads count of zero. - */ - for (i = 0; i < nch; i++) { - if (iir[i].biquads > 0) - iir_init_delay_df1(&iir[i], &delay); - } -} - -static int eq_iir_setup(struct processing_module *mod, int nch) -{ - struct comp_data *cd = module_get_private_data(mod); - int delay_size; - - /* Free existing IIR channels data if it was allocated */ - eq_iir_free_delaylines(cd); - - /* Set coefficients for each channel EQ from coefficient blob */ - delay_size = eq_iir_init_coef(mod, nch); - if (delay_size < 0) - return delay_size; /* Contains error code */ - - /* If all channels were set to bypass there's no need to - * allocate delay. Just return with success. - */ - if (!delay_size) - return 0; - - /* Allocate all IIR channels data in a big chunk and clear it */ - cd->iir_delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, - delay_size); - if (!cd->iir_delay) { - comp_err(mod->dev, "eq_iir_setup(), delay allocation fail"); - return -ENOMEM; - } - - cd->iir_delay_size = delay_size; - - /* Assign delay line to each channel EQ */ - eq_iir_init_delay(cd->iir, cd->iir_delay, nch); - return 0; -} - /* * End of EQ setup code. Next the standard component methods. */ @@ -678,42 +109,6 @@ static int eq_iir_free(struct processing_module *mod) return 0; } -#if CONFIG_IPC_MAJOR_3 -static int eq_iir_verify_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) -{ - struct comp_buffer *sourceb, *sinkb; - uint32_t buffer_flag; - int ret; - - comp_dbg(dev, "eq_iir_verify_params()"); - - /* EQ component will only ever have 1 source and 1 sink buffer */ - sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, - sink_list); - sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, - source_list); - - /* we check whether we can support frame_fmt conversion (whether we have - * such conversion function) due to source and sink buffer frame_fmt's. - * If not, we will overwrite sink (playback) and source (capture) with - * pcm frame_fmt and will not make any conversion (sink and source - * frame_fmt will be equal). - */ - buffer_flag = eq_iir_find_func(audio_stream_get_frm_fmt(&sourceb->stream), - audio_stream_get_frm_fmt(&sinkb->stream), fm_configured, - ARRAY_SIZE(fm_configured)) ? - BUFF_PARAMS_FRAME_FMT : 0; - - ret = comp_verify_params(dev, buffer_flag, params); - if (ret < 0) { - comp_err(dev, "eq_iir_verify_params(): comp_verify_params() failed."); - return ret; - } - - return 0; -} -#endif /* CONFIG_IPC_MAJOR_3 */ /* used to pass standard and bespoke commands (with data) to component */ static int eq_iir_set_config(struct processing_module *mod, uint32_t config_id, @@ -741,37 +136,6 @@ static int eq_iir_get_config(struct processing_module *mod, return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } -static int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, - enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, - int channels) -{ - int ret; - - ret = eq_iir_setup(mod, channels); - if (ret < 0) { - comp_err(mod->dev, "eq_iir_new_blob(), failed IIR setup"); - return ret; - } else if (cd->iir_delay_size) { - comp_dbg(mod->dev, "eq_iir_new_blob(), active"); -#if CONFIG_IPC_MAJOR_3 - cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_configured, - ARRAY_SIZE(fm_configured)); -#elif CONFIG_IPC_MAJOR_4 - cd->eq_iir_func = eq_iir_find_func(mod); -#endif - } else { - comp_dbg(mod->dev, "eq_iir_new_blob(), pass-through"); -#if CONFIG_IPC_MAJOR_3 - cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_passthrough, - ARRAY_SIZE(fm_passthrough)); -#elif CONFIG_IPC_MAJOR_4 - cd->eq_iir_func = eq_iir_pass; -#endif - } - - return 0; -} - static int eq_iir_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) @@ -814,51 +178,6 @@ static void eq_iir_set_alignment(struct audio_stream *source, audio_stream_init_alignment_constants(byte_align, frame_align_req, sink); } -#if CONFIG_IPC_MAJOR_4 -static int eq_iir_params(struct processing_module *mod) -{ - struct sof_ipc_stream_params *params = mod->stream_params; - struct sof_ipc_stream_params comp_params; - struct comp_dev *dev = mod->dev; - struct comp_buffer *sinkb; - enum sof_ipc_frame valid_fmt, frame_fmt; - int i, ret; - - comp_dbg(dev, "eq_iir_params()"); - comp_params = *params; - comp_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; - comp_params.rate = mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency; - comp_params.buffer_fmt = mod->priv.cfg.base_cfg.audio_fmt.interleaving_style; - - audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, - mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth, - &frame_fmt, &valid_fmt, - mod->priv.cfg.base_cfg.audio_fmt.s_type); - - comp_params.frame_fmt = valid_fmt; - - for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) - comp_params.chmap[i] = (mod->priv.cfg.base_cfg.audio_fmt.ch_map >> i * 4) & 0xf; - - component_set_nearest_period_frames(dev, comp_params.rate); - sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - ret = buffer_set_params(sinkb, &comp_params, true); - return ret; -} -#endif - -static void eq_iir_set_passthrough_func(struct comp_data *cd, - enum sof_ipc_frame source_format, - enum sof_ipc_frame sink_format) -{ -#if CONFIG_IPC_MAJOR_3 - cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_passthrough, - ARRAY_SIZE(fm_passthrough)); -#else - cd->eq_iir_func = eq_iir_pass; -#endif -} - static int eq_iir_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -873,19 +192,10 @@ static int eq_iir_prepare(struct processing_module *mod, comp_dbg(dev, "eq_iir_prepare()"); -#if CONFIG_IPC_MAJOR_3 - ret = eq_iir_verify_params(dev, mod->stream_params); + ret = eq_iir_prepare_sub(mod); if (ret < 0) return ret; -#elif CONFIG_IPC_MAJOR_4 - ret = eq_iir_params(mod); - if (ret < 0) { - comp_set_state(dev, COMP_TRIGGER_RESET); - return ret; - } -#endif - /* EQ component will only ever have 1 source and 1 sink buffer */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); diff --git a/src/audio/eq_iir/eq_iir.h b/src/audio/eq_iir/eq_iir.h index 583a87c4a30a..7b6b6c247574 100644 --- a/src/audio/eq_iir/eq_iir.h +++ b/src/audio/eq_iir/eq_iir.h @@ -56,4 +56,20 @@ void eq_iir_s24_default(struct processing_module *mod, struct input_stream_buffe void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, uint32_t frames); +int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, + enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, + int channels); + +void eq_iir_set_passthrough_func(struct comp_data *cd, + enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format); + +int eq_iir_prepare_sub(struct processing_module *mod); + +void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames); + +int eq_iir_setup(struct processing_module *mod, int nch); + +void eq_iir_free_delaylines(struct comp_data *cd); #endif /* __SOF_AUDIO_EQ_IIR_EQ_IIR_H__ */ diff --git a/src/audio/eq_iir/eq_iir_generic.c b/src/audio/eq_iir/eq_iir_generic.c new file mode 100644 index 000000000000..2f891e240b10 --- /dev/null +++ b/src/audio/eq_iir/eq_iir_generic.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017-2022 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo +// Liam Girdwood +// Keyon Jie + +#include "eq_iir.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(eq_iir, CONFIG_SOF_LOG_LEVEL); + +#if CONFIG_FORMAT_S16LE +void eq_iir_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + struct iir_state_df1 *filter; + int16_t *x0; + int16_t *y0; + int16_t *x; + int16_t *y; + int nmax; + int n1; + int n2; + int i; + int j; + int n; + const int nch = audio_stream_get_channels(source); + const int samples = frames * nch; + int processed = 0; + + x = audio_stream_get_rptr(source); + y = audio_stream_get_wptr(sink); + while (processed < samples) { + nmax = samples - processed; + n1 = audio_stream_bytes_without_wrap(source, x) >> 1; + n2 = audio_stream_bytes_without_wrap(sink, y) >> 1; + n = MIN(n1, n2); + n = MIN(n, nmax); + for (i = 0; i < nch; i++) { + x0 = x + i; + y0 = y + i; + filter = &cd->iir[i]; + for (j = 0; j < n; j += nch) { + *y0 = iir_df1_s16(filter, *x0); + x0 += nch; + y0 += nch; + } + } + processed += n; + x = audio_stream_wrap(source, x + n); + y = audio_stream_wrap(sink, y + n); + } +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE + +void eq_iir_s24_default(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + struct iir_state_df1 *filter; + int32_t *x0; + int32_t *y0; + int32_t *x; + int32_t *y; + int nmax; + int n1; + int n2; + int i; + int j; + int n; + const int nch = audio_stream_get_channels(source); + const int samples = frames * nch; + int processed = 0; + + x = audio_stream_get_rptr(source); + y = audio_stream_get_wptr(sink); + while (processed < samples) { + nmax = samples - processed; + n1 = audio_stream_bytes_without_wrap(source, x) >> 2; + n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; + n = MIN(n1, n2); + n = MIN(n, nmax); + for (i = 0; i < nch; i++) { + x0 = x + i; + y0 = y + i; + filter = &cd->iir[i]; + for (j = 0; j < n; j += nch) { + *y0 = iir_df1_s24(filter, *x0); + x0 += nch; + y0 += nch; + } + } + processed += n; + x = audio_stream_wrap(source, x + n); + y = audio_stream_wrap(sink, y + n); + } +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE + +void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + struct iir_state_df1 *filter; + int32_t *x0; + int32_t *y0; + int32_t *x; + int32_t *y; + int nmax; + int n1; + int n2; + int i; + int j; + int n; + const int nch = audio_stream_get_channels(source); + const int samples = frames * nch; + int processed = 0; + + x = audio_stream_get_rptr(source); + y = audio_stream_get_wptr(sink); + while (processed < samples) { + nmax = samples - processed; + n1 = audio_stream_bytes_without_wrap(source, x) >> 2; + n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; + n = MIN(n1, n2); + n = MIN(n, nmax); + for (i = 0; i < nch; i++) { + x0 = x + i; + y0 = y + i; + filter = &cd->iir[i]; + for (j = 0; j < n; j += nch) { + *y0 = iir_df1(filter, *x0); + x0 += nch; + y0 += nch; + } + } + processed += n; + x = audio_stream_wrap(source, x + n); + y = audio_stream_wrap(sink, y + n); + } +} +#endif /* CONFIG_FORMAT_S32LE */ + +static int eq_iir_init_coef(struct processing_module *mod, int nch) +{ + struct comp_data *cd = module_get_private_data(mod); + struct sof_eq_iir_config *config = cd->config; + struct iir_state_df1 *iir = cd->iir; + struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES]; + struct sof_eq_iir_header *eq; + int32_t *assign_response; + int32_t *coef_data; + int size_sum = 0; + int resp = 0; + int i; + int j; + int s; + + comp_info(mod->dev, "eq_iir_init_coef(): %u responses, %u channels, stream %d channels", + config->number_of_responses, config->channels_in_config, nch); + + /* Sanity checks */ + if (nch > PLATFORM_MAX_CHANNELS || + config->channels_in_config > PLATFORM_MAX_CHANNELS || + !config->channels_in_config) { + comp_err(mod->dev, "eq_iir_init_coef(), invalid channels count"); + return -EINVAL; + } + if (config->number_of_responses > SOF_EQ_IIR_MAX_RESPONSES) { + comp_err(mod->dev, "eq_iir_init_coef(), # of resp exceeds max"); + return -EINVAL; + } + + /* Collect index of response start positions in all_coefficients[] */ + j = 0; + assign_response = ASSUME_ALIGNED(&config->data[0], 4); + coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], + 4); + for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) { + if (i < config->number_of_responses) { + eq = (struct sof_eq_iir_header *)&coef_data[j]; + lookup[i] = eq; + j += SOF_EQ_IIR_NHEADER + + SOF_EQ_IIR_NBIQUAD * eq->num_sections; + } else { + lookup[i] = NULL; + } + } + + /* Initialize 1st phase */ + for (i = 0; i < nch; i++) { + /* Check for not reading past blob response to channel assign + * map. The previous channel response is assigned for any + * additional channels in the stream. It allows to use single + * channel configuration to setup multi channel equalization + * with the same response. + */ + if (i < config->channels_in_config) + resp = assign_response[i]; + + if (resp < 0) { + /* Initialize EQ channel to bypass and continue with + * next channel response. + */ + comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to bypass", i); + iir_reset_df1(&iir[i]); + continue; + } + + if (resp >= config->number_of_responses) { + comp_err(mod->dev, "eq_iir_init_coef(), requested response %d exceeds defined", + resp); + return -EINVAL; + } + + /* Initialize EQ coefficients */ + eq = lookup[resp]; + s = iir_delay_size_df1(eq); + if (s > 0) { + size_sum += s; + } else { + comp_err(mod->dev, "eq_iir_init_coef(), sections count %d exceeds max", + eq->num_sections); + return -EINVAL; + } + + iir_init_coef_df1(&iir[i], eq); + comp_info(mod->dev, "eq_iir_init_coef(), ch %d is set to response %d", i, resp); + } + + return size_sum; +} + +static void eq_iir_init_delay(struct iir_state_df1 *iir, + int32_t *delay_start, int nch) +{ + int32_t *delay = delay_start; + int i; + + /* Initialize second phase to set EQ delay lines pointers. A + * bypass mode filter is indicated by biquads count of zero. + */ + for (i = 0; i < nch; i++) { + if (iir[i].biquads > 0) + iir_init_delay_df1(&iir[i], &delay); + } +} + +void eq_iir_free_delaylines(struct comp_data *cd) +{ + struct iir_state_df1 *iir = cd->iir; + int i = 0; + + /* Free the common buffer for all EQs and point then + * each IIR channel delay line to NULL. + */ + rfree(cd->iir_delay); + cd->iir_delay = NULL; + cd->iir_delay_size = 0; + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + iir[i].delay = NULL; +} + +void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + + audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); +} + +int eq_iir_setup(struct processing_module *mod, int nch) +{ + struct comp_data *cd = module_get_private_data(mod); + int delay_size; + + /* Free existing IIR channels data if it was allocated */ + eq_iir_free_delaylines(cd); + + /* Set coefficients for each channel EQ from coefficient blob */ + delay_size = eq_iir_init_coef(mod, nch); + if (delay_size < 0) + return delay_size; /* Contains error code */ + + /* If all channels were set to bypass there's no need to + * allocate delay. Just return with success. + */ + if (!delay_size) + return 0; + + /* Allocate all IIR channels data in a big chunk and clear it */ + cd->iir_delay = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + delay_size); + if (!cd->iir_delay) { + comp_err(mod->dev, "eq_iir_setup(), delay allocation fail"); + return -ENOMEM; + } + + cd->iir_delay_size = delay_size; + + /* Assign delay line to each channel EQ */ + eq_iir_init_delay(cd->iir, cd->iir_delay, nch); + return 0; +} + diff --git a/src/audio/eq_iir/eq_iir_ipc3.c b/src/audio/eq_iir/eq_iir_ipc3.c new file mode 100644 index 000000000000..6958dd6b536b --- /dev/null +++ b/src/audio/eq_iir/eq_iir_ipc3.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017-2022 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo +// Liam Girdwood +// Keyon Jie + +#include "eq_iir.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(eq_iir, CONFIG_SOF_LOG_LEVEL); + +#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE +static void eq_iir_s32_16_default(struct processing_module *mod, + struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + struct iir_state_df1 *filter; + int32_t *x0; + int16_t *y0; + int32_t *x; + int16_t *y; + int nmax; + int n1; + int n2; + int i; + int j; + int n; + const int nch = audio_stream_get_channels(source); + const int samples = frames * nch; + int processed = 0; + + x = audio_stream_get_rptr(source); + y = audio_stream_get_wptr(sink); + while (processed < samples) { + nmax = samples - processed; + n1 = audio_stream_bytes_without_wrap(source, x) >> 2; /* divide 4 */ + n2 = audio_stream_bytes_without_wrap(sink, y) >> 1; /* divide 2 */ + n = MIN(n1, n2); + n = MIN(n, nmax); + for (i = 0; i < nch; i++) { + x0 = x + i; + y0 = y + i; + filter = &cd->iir[i]; + for (j = 0; j < n; j += nch) { + *y0 = iir_df1_s32_s16(filter, *x0); + x0 += nch; + y0 += nch; + } + } + processed += n; + x = audio_stream_wrap(source, x + n); + y = audio_stream_wrap(sink, y + n); + } +} +#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE +static void eq_iir_s32_24_default(struct processing_module *mod, + struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + struct iir_state_df1 *filter; + int32_t *x0; + int32_t *y0; + int32_t *x; + int32_t *y; + int nmax; + int n1; + int n2; + int i; + int j; + int n; + const int nch = audio_stream_get_channels(source); + const int samples = frames * nch; + int processed = 0; + + x = audio_stream_get_rptr(source); + y = audio_stream_get_wptr(sink); + while (processed < samples) { + nmax = samples - processed; + n1 = audio_stream_bytes_without_wrap(source, x) >> 2; + n2 = audio_stream_bytes_without_wrap(sink, y) >> 2; + n = MIN(n1, n2); + n = MIN(n, nmax); + for (i = 0; i < nch; i++) { + x0 = x + i; + y0 = y + i; + filter = &cd->iir[i]; + for (j = 0; j < n; j += nch) { + *y0 = iir_df1_s32_s24(filter, *x0); + x0 += nch; + y0 += nch; + } + } + processed += n; + x = audio_stream_wrap(source, x + n); + y = audio_stream_wrap(sink, y + n); + } +} +#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE +static void eq_iir_s32_s16_pass(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + int32_t *x = audio_stream_get_rptr(source); + int16_t *y = audio_stream_get_wptr(sink); + int nmax; + int n; + int i; + int remaining_samples = frames * audio_stream_get_channels(source); + + while (remaining_samples) { + nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(source, x)); + n = MIN(remaining_samples, nmax); + nmax = EQ_IIR_BYTES_TO_S16_SAMPLES(audio_stream_bytes_without_wrap(sink, y)); + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *y = sat_int16(Q_SHIFT_RND(*x, 31, 15)); + x++; + y++; + } + remaining_samples -= n; + x = audio_stream_wrap(source, x); + y = audio_stream_wrap(sink, y); + } +} +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE +static void eq_iir_s32_s24_pass(struct processing_module *mod, struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames) +{ + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; + int32_t *x = audio_stream_get_rptr(source); + int32_t *y = audio_stream_get_wptr(sink); + int nmax; + int n; + int i; + int remaining_samples = frames * audio_stream_get_channels(source); + + while (remaining_samples) { + nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(source, x)); + n = MIN(remaining_samples, nmax); + nmax = EQ_IIR_BYTES_TO_S32_SAMPLES(audio_stream_bytes_without_wrap(sink, y)); + n = MIN(n, nmax); + for (i = 0; i < n; i++) { + *y = sat_int24(Q_SHIFT_RND(*x, 31, 23)); + x++; + y++; + } + remaining_samples -= n; + x = audio_stream_wrap(source, x); + y = audio_stream_wrap(sink, y); + } +} +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ + +const struct eq_iir_func_map fm_configured[] = { +#if CONFIG_FORMAT_S16LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s16_default}, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, NULL}, + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, NULL}, + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, NULL}, + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s32_16_default}, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S24LE + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s24_default}, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, NULL}, + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s32_24_default}, +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, eq_iir_s32_default}, +#endif /* CONFIG_FORMAT_S32LE */ +}; + +const struct eq_iir_func_map fm_passthrough[] = { +#if CONFIG_FORMAT_S16LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, eq_iir_pass}, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, NULL}, + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, NULL}, + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE*/ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, NULL}, + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, eq_iir_s32_s16_pass}, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE*/ +#if CONFIG_FORMAT_S24LE + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, eq_iir_pass}, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, NULL}, + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, eq_iir_s32_s24_pass}, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, eq_iir_pass}, +#endif /* CONFIG_FORMAT_S32LE */ +}; + +static eq_iir_func eq_iir_find_func(enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format, + const struct eq_iir_func_map *map, + int n) +{ + int i; + + /* Find suitable processing function from map. */ + for (i = 0; i < n; i++) { + if ((uint8_t)source_format != map[i].source) + continue; + if ((uint8_t)sink_format != map[i].sink) + continue; + + return map[i].func; + } + + return NULL; +} + +static int eq_iir_verify_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + struct comp_buffer *sourceb, *sinkb; + uint32_t buffer_flag; + int ret; + + comp_dbg(dev, "eq_iir_verify_params()"); + + /* EQ component will only ever have 1 source and 1 sink buffer */ + sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + /* we check whether we can support frame_fmt conversion (whether we have + * such conversion function) due to source and sink buffer frame_fmt's. + * If not, we will overwrite sink (playback) and source (capture) with + * pcm frame_fmt and will not make any conversion (sink and source + * frame_fmt will be equal). + */ + buffer_flag = eq_iir_find_func(audio_stream_get_frm_fmt(&sourceb->stream), + audio_stream_get_frm_fmt(&sinkb->stream), fm_configured, + ARRAY_SIZE(fm_configured)) ? + BUFF_PARAMS_FRAME_FMT : 0; + + ret = comp_verify_params(dev, buffer_flag, params); + if (ret < 0) { + comp_err(dev, "eq_iir_verify_params(): comp_verify_params() failed."); + return ret; + } + + return 0; +} + +int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, + enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, + int channels) +{ + int ret; + + ret = eq_iir_setup(mod, channels); + if (ret < 0) { + comp_err(mod->dev, "eq_iir_new_blob(), failed IIR setup"); + return ret; + } else if (cd->iir_delay_size) { + comp_dbg(mod->dev, "eq_iir_new_blob(), active"); + cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_configured, + ARRAY_SIZE(fm_configured)); + } else { + comp_dbg(mod->dev, "eq_iir_new_blob(), pass-through"); + cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_passthrough, + ARRAY_SIZE(fm_passthrough)); + } + + return 0; +} + +void eq_iir_set_passthrough_func(struct comp_data *cd, + enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format) +{ + cd->eq_iir_func = eq_iir_find_func(source_format, sink_format, fm_passthrough, + ARRAY_SIZE(fm_passthrough)); +} + +int eq_iir_prepare_sub(struct processing_module *mod) +{ + return eq_iir_verify_params(mod->dev, mod->stream_params); +} diff --git a/src/audio/eq_iir/eq_iir_ipc4.c b/src/audio/eq_iir/eq_iir_ipc4.c new file mode 100644 index 000000000000..474b820b14de --- /dev/null +++ b/src/audio/eq_iir/eq_iir_ipc4.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017-2022 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo +// Liam Girdwood +// Keyon Jie + +#include "eq_iir.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(eq_iir, CONFIG_SOF_LOG_LEVEL); + +/* + * In early days of SOF the preference for pipelines was 16 bits to save RAM in platforms + * like Baytrail. However in microphone paths if there was need to digitally boost the gain + * the quality was bad in topologies where capture DAI was 16 bit and we applied with volume + * or IIR about 20 dB gain. In practice a 16 bit word got left shifted by some bit positions + * that effectively made signal like 12 bits. We could achieve a lot better quality by + * capturing codec and DAI with 24 or 32bits and applying the gain in IIR for the larger word + * length. Then all 16 bits in the pipelines after DAI and IIR had signal. The IIR was chosen for + * format conversion because it also canceled the sometimes large DC component + * (and some lowest non-audible frequencies) in signal. + * It gave the headroom for signal for amplification. + + * If IPC4 systems ever need the memory save small 16 bit capture paths + * the format conversion could be brought back. + */ + +static eq_iir_func eq_iir_find_func(struct processing_module *mod) +{ + unsigned int valid_bit_depth = mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth; + + comp_dbg(mod->dev, "eq_iir_find_func(): valid_bit_depth %d", valid_bit_depth); + switch (valid_bit_depth) { +#if CONFIG_FORMAT_S16LE + case IPC4_DEPTH_16BIT: + return eq_iir_s16_default; +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + case IPC4_DEPTH_24BIT: + return eq_iir_s24_default; +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + case IPC4_DEPTH_32BIT: + return eq_iir_s32_default; +#endif /* CONFIG_FORMAT_S32LE */ + default: + comp_err(mod->dev, "set_fir_func(), invalid valid_bith_depth"); + } + return NULL; +} + +int eq_iir_new_blob(struct processing_module *mod, struct comp_data *cd, + enum sof_ipc_frame source_format, enum sof_ipc_frame sink_format, + int channels) +{ + int ret; + + ret = eq_iir_setup(mod, channels); + if (ret < 0) { + comp_err(mod->dev, "eq_iir_new_blob(), failed IIR setup"); + return ret; + } else if (cd->iir_delay_size) { + comp_dbg(mod->dev, "eq_iir_new_blob(), active"); + cd->eq_iir_func = eq_iir_find_func(mod); + } else { + comp_dbg(mod->dev, "eq_iir_new_blob(), pass-through"); + cd->eq_iir_func = eq_iir_pass; + } + + return 0; +} + +static int eq_iir_params(struct processing_module *mod) +{ + struct sof_ipc_stream_params *params = mod->stream_params; + struct sof_ipc_stream_params comp_params; + struct comp_dev *dev = mod->dev; + struct comp_buffer *sinkb; + enum sof_ipc_frame valid_fmt, frame_fmt; + int i, ret; + + comp_dbg(dev, "eq_iir_params()"); + comp_params = *params; + comp_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; + comp_params.rate = mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency; + comp_params.buffer_fmt = mod->priv.cfg.base_cfg.audio_fmt.interleaving_style; + + audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, + mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth, + &frame_fmt, &valid_fmt, + mod->priv.cfg.base_cfg.audio_fmt.s_type); + + comp_params.frame_fmt = valid_fmt; + + for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) + comp_params.chmap[i] = (mod->priv.cfg.base_cfg.audio_fmt.ch_map >> i * 4) & 0xf; + + component_set_nearest_period_frames(dev, comp_params.rate); + sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + ret = buffer_set_params(sinkb, &comp_params, true); + return ret; +} + +void eq_iir_set_passthrough_func(struct comp_data *cd, + enum sof_ipc_frame source_format, + enum sof_ipc_frame sink_format) +{ + cd->eq_iir_func = eq_iir_pass; +} + +int eq_iir_prepare_sub(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + int ret = 0; + + ret = eq_iir_params(mod); + if (ret < 0) + comp_set_state(dev, COMP_TRIGGER_RESET); + + return ret; +} + diff --git a/test/cmocka/src/audio/eq_iir/CMakeLists.txt b/test/cmocka/src/audio/eq_iir/CMakeLists.txt index a520a22fa441..8f00dbedc750 100644 --- a/test/cmocka/src/audio/eq_iir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_iir/CMakeLists.txt @@ -13,6 +13,8 @@ add_compile_options(-DUNIT_TEST) add_library(audio_for_eq_iir STATIC ${PROJECT_SOURCE_DIR}/src/audio/eq_iir/eq_iir.c + ${PROJECT_SOURCE_DIR}/src/audio/eq_iir/eq_iir_generic.c + ${PROJECT_SOURCE_DIR}/src/audio/eq_iir/eq_iir_ipc3.c ${PROJECT_SOURCE_DIR}/src/math/iir_df1.c ${PROJECT_SOURCE_DIR}/src/math/iir_df1_generic.c ${PROJECT_SOURCE_DIR}/src/math/iir_df1_hifi3.c diff --git a/test/cmocka/src/audio/eq_iir/eq_iir_process.c b/test/cmocka/src/audio/eq_iir/eq_iir_process.c index b960a6997b14..529d4328f580 100644 --- a/test/cmocka/src/audio/eq_iir/eq_iir_process.c +++ b/test/cmocka/src/audio/eq_iir/eq_iir_process.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "../../util.h" diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 8deca5155919..68e110426ea5 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -426,9 +426,19 @@ zephyr_library_sources_ifdef(CONFIG_COMP_FIR ${SOF_MATH_PATH}/fir_hifi3.c ) -zephyr_library_sources_ifdef(CONFIG_COMP_IIR - ${SOF_AUDIO_PATH}/eq_iir/eq_iir.c -) +if(CONFIG_IPC_MAJOR_3) + zephyr_library_sources_ifdef(CONFIG_COMP_IIR + ${SOF_AUDIO_PATH}/eq_iir/eq_iir.c + ${SOF_AUDIO_PATH}/eq_iir/eq_iir_ipc3.c + ${SOF_AUDIO_PATH}/eq_iir/eq_iir_generic.c + ) +elseif(CONFIG_IPC_MAJOR_4) + zephyr_library_sources_ifdef(CONFIG_COMP_IIR + ${SOF_AUDIO_PATH}/eq_iir/eq_iir.c + ${SOF_AUDIO_PATH}/eq_iir/eq_iir_ipc4.c + ${SOF_AUDIO_PATH}/eq_iir/eq_iir_generic.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_MATH_IIR_DF1 ${SOF_MATH_PATH}/iir_df1_generic.c