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). */ 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..e8a5ff323406 --- /dev/null +++ b/test/cmocka/src/audio/drc/drc_process.c @@ -0,0 +1,424 @@ +// 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" + +/* 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; + bool continue_loop; + int diff_count; /* enabled mode: output 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_buffers(struct test_data *td) +{ + 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) +{ + 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)); + 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) { + 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_buffers(td); + + 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; + } + + *state = td; + return 0; +} + +static int teardown(void **state) +{ + struct test_data *td = *state; + + test_free(td->params); + free_test_source(td->source); + free_test_sink(td->sink); + comp_free(td->dev); + test_free(td); + 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 int fill_source_s16(struct test_data *td, int frames) +{ + int16_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; + int i; + + for (i = 0; i < samples; i++) { + 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; + } + } + return i / td->params->channels; +} + +static void verify_sink_s16(struct test_data *td, int frames) +{ + int16_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; + int32_t ref; + int32_t out; + int i; + + for (i = 0; i < samples; i++) { + 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); + else if (out != ref) + td->diff_count++; + } +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +static int fill_source_s24(struct test_data *td, int frames) +{ + int32_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; + int i; + + for (i = 0; i < samples; i++) { + 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; + } + } + return i / td->params->channels; +} + +static void verify_sink_s24(struct test_data *td, int frames) +{ + int32_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; + int32_t ref; + int32_t out; + int i; + + for (i = 0; i < samples; i++) { + 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); + 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 int fill_source_s32(struct test_data *td, int frames) +{ + int32_t *x = audio_stream_get_addr(&td->source->stream); + int samples = frames * td->params->channels; + int i; + + for (i = 0; i < samples; i++) { + x[i] = chirp_2ch[buffer_fill_data.idx++]; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + i++; + break; + } + } + return i / td->params->channels; +} + +static void verify_sink_s32(struct test_data *td, int frames) +{ + int32_t *y = audio_stream_get_addr(&td->sink->stream); + int samples = frames * td->params->channels; + int32_t ref; + int32_t out; + int i; + + for (i = 0; i < samples; i++) { + out = y[i]; + 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 fill_source(struct test_data *td, int 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 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 = fill_source(td, td->params->frames); + if (frames <= 0) + break; + + make_views(td, &source_buf, &sink_buf); + cd->drc_func(mod, &source_buf, &sink_buf, frames); + + verify_sink(td, frames); + } + + /* 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); +}