From 2eeea7b143f398445adb81fcd09c93bfb1ff2709 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Thu, 24 Feb 2022 18:57:29 +0200 Subject: [PATCH 1/2] Audio: DRC: Optimize source and sink buffers access This patch replaces the audio_stream_read/write_frag_s16/s32 functions based source buffer read and sink buffer write with audio_stream_bytes_without_wrap() based blocks access. The drc_s16/s24/s32_default processing functions are simplified by move of common delay input sample operation to separate function. The same function is used in DRC disabled and enabled part of processing functions. The pass-through mode is optimized with generic audio_stream_copy() that is a common function for all s16/s24/s32 formats. The MCPS savings are in TGL-H for stereo 48 kHz stream - Normal operation 68 to 50 MCPS, saving 18 MCPS - Pass-through without delay 22 to 6 MCPS, saving 16 MCPS - Pass-through with delay 21 to 7 MCPS, saving is 14 MCPS Signed-off-by: Seppo Ingalsuo --- src/audio/drc/drc.c | 8 +- src/audio/drc/drc_generic.c | 471 +++++++++++++------------------- src/include/sof/audio/drc/drc.h | 19 +- 3 files changed, 202 insertions(+), 296 deletions(-) diff --git a/src/audio/drc/drc.c b/src/audio/drc/drc.c index 888a2718f32e..95bc73ffc194 100644 --- a/src/audio/drc/drc.c +++ b/src/audio/drc/drc.c @@ -401,12 +401,8 @@ static int drc_prepare(struct comp_dev *dev) goto err; } } else { - cd->drc_func = drc_find_proc_func_pass(cd->source_format); - if (!cd->drc_func) { - comp_err(dev, "drc_prepare(), No proc func passthrough"); - ret = -EINVAL; - goto err; - } + /* Generic function for all formats */ + cd->drc_func = drc_default_pass; } comp_info(dev, "drc_prepare(), DRC is configured."); diff --git a/src/audio/drc/drc_generic.c b/src/audio/drc/drc_generic.c index 94dfabca5b18..2d3c878e9624 100644 --- a/src/audio/drc/drc_generic.c +++ b/src/audio/drc/drc_generic.c @@ -465,255 +465,253 @@ static void drc_process_one_division(struct drc_state *state, drc_compress_output(state, p, nbyte, nch); } -#if CONFIG_FORMAT_S16LE -static void drc_s16_default_pass(const struct comp_dev *dev, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +void drc_default_pass(const struct comp_dev *dev, const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { - int16_t *x; - int16_t *y; - int i; - int n = source->channels * frames; + audio_stream_copy(source, 0, sink, 0, frames * source->channels); +} - for (i = 0; i < n; i++) { - x = audio_stream_read_frag_s16(source, i); - y = audio_stream_write_frag_s16(sink, i); - *y = *x; - } +static inline void drc_pre_delay_index_inc(int *idx, int increment) +{ + *idx = (*idx + increment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; } -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE -static void drc_s32_default_pass(const struct comp_dev *dev, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +#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) { - int32_t *x; - int32_t *y; + int16_t *x1; + int16_t *y1; + int16_t *pd; + int pd_write_index, pd_read_index; + int nbuf, npcm, nfrm; + int ch; int i; - int n = source->channels * frames; + int16_t *x0 = *x; + int16_t *y0 = *y; + int remaining_samples = samples; + int nch = source->channels; - for (i = 0; i < n; i++) { - x = audio_stream_read_frag_s32(source, i); - y = audio_stream_write_frag_s32(sink, i); - *y = *x; + while (remaining_samples) { + nbuf = audio_stream_samples_without_wrap_s16(source, x0); + npcm = MIN(remaining_samples, nbuf); + nbuf = audio_stream_samples_without_wrap_s16(sink, y0); + npcm = MIN(npcm, nbuf); + nfrm = npcm / nch; + for (ch = 0; ch < nch; ++ch) { + pd = (int16_t *)state->pre_delay_buffers[ch]; + x1 = x0 + ch; + y1 = y0 + ch; + pd_write_index = state->pre_delay_write_index; + pd_read_index = state->pre_delay_read_index; + for (i = 0; i < nfrm; i++) { + *(pd + pd_write_index) = *x1; + *y1 = *(pd + pd_read_index); + drc_pre_delay_index_inc(&pd_write_index, 1); + drc_pre_delay_index_inc(&pd_read_index, 1); + x1 += nch; + y1 += nch; + } + } + remaining_samples -= npcm; + x0 = audio_stream_wrap(source, x0 + npcm); + y0 = audio_stream_wrap(sink, y0 + npcm); + drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); + drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } + + *x = x0; + *y = y0; } -#endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S16LE static void drc_s16_default(const struct comp_dev *dev, const struct audio_stream *source, struct audio_stream *sink, uint32_t frames) { - int16_t *x; - int16_t *y; - int16_t *pd_write; - int16_t *pd_read; - int offset; - int i = 0; - int ch; - int idx; - int f; - int fragment; - int pd_write_index; - int pd_read_index; + int16_t *x = source->r_ptr; + int16_t *y = sink->w_ptr; int nch = source->channels; - + int samples = frames * nch; struct drc_comp_data *cd = comp_get_drvdata(dev); struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ + int fragment_samples; + int fragment; if (!p->enabled) { /* Delay the input sample only and don't do other processing. This is used when the * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - for (ch = 0; ch < nch; ++ch) { - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; - pd_write = (int16_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int16_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = ch; - for (i = 0; i < frames; ++i) { - x = audio_stream_read_frag_s16(source, idx); - y = audio_stream_write_frag_s16(sink, idx); - *pd_write = *x; - *y = *pd_read; - if (++pd_write_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_write_index = 0; - pd_write = (int16_t *)state->pre_delay_buffers[ch]; - } else { - pd_write++; - } - if (++pd_read_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_read_index = 0; - pd_read = (int16_t *)state->pre_delay_buffers[ch]; - } else { - pd_read++; - } - idx += nch; - } - } - - state->pre_delay_write_index += frames; - state->pre_delay_write_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index += frames; - state->pre_delay_read_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; + drc_delay_input_sample_s16(state, source, sink, &x, &y, samples); return; } if (!state->processed) { drc_update_envelope(state, p); - drc_compress_output(state, p, 2, nch); + drc_compress_output(state, p, sizeof(int16_t), nch); state->processed = 1; } - offset = state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK; - while (i < frames) { - /* Copy fragment data from source to pre-delay buffers, and copy the output fragment - * to sink. - */ - fragment = MIN(DRC_DIVISION_FRAMES - offset, frames - i); - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; + while (samples) { + fragment = DRC_DIVISION_FRAMES - + (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); + samples -= fragment_samples; + + /* Process the input division (32 frames). */ + if ((state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK) == 0) + drc_process_one_division(state, p, sizeof(int16_t), nch); + } +} +#endif /* CONFIG_FORMAT_S16LE */ + +#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) +{ + 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; + int32_t *y0 = *y; + int remaining_samples = samples; + int nch = source->channels; + + while (remaining_samples) { + nbuf = audio_stream_samples_without_wrap_s32(source, x0); + npcm = MIN(remaining_samples, nbuf); + nbuf = audio_stream_samples_without_wrap_s32(sink, y0); + npcm = MIN(npcm, nbuf); + nfrm = npcm / nch; for (ch = 0; ch < nch; ++ch) { - pd_write = (int16_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int16_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = i * nch + ch; - for (f = 0; f < fragment; ++f) { - x = audio_stream_read_frag_s16(source, idx); - y = audio_stream_write_frag_s16(sink, idx); - *pd_write = *x; - *y = *pd_read; - pd_write++; - pd_read++; - idx += nch; + pd = (int32_t *)state->pre_delay_buffers[ch]; + x1 = x0 + ch; + y1 = y0 + ch; + pd_write_index = state->pre_delay_write_index; + pd_read_index = state->pre_delay_read_index; + for (i = 0; i < nfrm; i++) { + *(pd + pd_write_index) = *x1; + *y1 = *(pd + pd_read_index); + drc_pre_delay_index_inc(&pd_write_index, 1); + drc_pre_delay_index_inc(&pd_read_index, 1); + x1 += nch; + y1 += nch; } } - state->pre_delay_write_index = - (pd_write_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index = - (pd_read_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; + remaining_samples -= npcm; + x0 = audio_stream_wrap(source, x0 + npcm); + y0 = audio_stream_wrap(sink, y0 + npcm); + drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); + drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); + } - i += fragment; - offset = (offset + fragment) & DRC_DIVISION_FRAMES_MASK; + *x = x0; + *y = y0; +} +#endif - /* Process the input division (32 frames). */ - if (offset == 0) - drc_process_one_division(state, p, 2, nch); +#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) +{ + 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; + int32_t *y0 = *y; + int remaining_samples = samples; + int nch = source->channels; + + while (remaining_samples) { + nbuf = audio_stream_samples_without_wrap_s24(source, x0); + npcm = MIN(remaining_samples, nbuf); + nbuf = audio_stream_samples_without_wrap_s24(sink, y0); + npcm = MIN(npcm, nbuf); + nfrm = npcm / nch; + for (ch = 0; ch < nch; ++ch) { + pd = (int32_t *)state->pre_delay_buffers[ch]; + x1 = x0 + ch; + y1 = y0 + ch; + pd_write_index = state->pre_delay_write_index; + pd_read_index = state->pre_delay_read_index; + for (i = 0; i < nfrm; i++) { + *(pd + pd_write_index) = *x1 << 8; + *y1 = sat_int24(Q_SHIFT_RND(*(pd + pd_read_index), 31, 23)); + drc_pre_delay_index_inc(&pd_write_index, 1); + drc_pre_delay_index_inc(&pd_read_index, 1); + x1 += nch; + y1 += nch; + } + } + remaining_samples -= npcm; + x0 = audio_stream_wrap(source, x0 + npcm); + y0 = audio_stream_wrap(sink, y0 + npcm); + drc_pre_delay_index_inc(&state->pre_delay_write_index, nfrm); + drc_pre_delay_index_inc(&state->pre_delay_read_index, nfrm); } + + *x = x0; + *y = y0; } -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE static void drc_s24_default(const struct comp_dev *dev, const struct audio_stream *source, struct audio_stream *sink, uint32_t frames) { - int32_t *x; - int32_t *y; - int32_t *pd_write; - int32_t *pd_read; - int offset; - int i = 0; - int ch; - int idx; - int f; - int fragment; - int pd_write_index; - int pd_read_index; + int32_t *x = source->r_ptr; + int32_t *y = sink->w_ptr; int nch = source->channels; - + int samples = frames * nch; struct drc_comp_data *cd = comp_get_drvdata(dev); struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ + int fragment_samples; + int fragment; if (!p->enabled) { /* Delay the input sample only and don't do other processing. This is used when the * DRC is disabled. We want to do this to match the processing delay of other bands - * in multi-band DRC kernel case. + * in multi-band DRC kernel case. Note: use 32 bit delay function. */ - for (ch = 0; ch < nch; ++ch) { - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; - pd_write = (int32_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int32_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = ch; - for (i = 0; i < frames; ++i) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_write_frag_s32(sink, idx); - *pd_write = *x; - *y = *pd_read; - if (++pd_write_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_write_index = 0; - pd_write = (int32_t *)state->pre_delay_buffers[ch]; - } else { - pd_write++; - } - if (++pd_read_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_read_index = 0; - pd_read = (int32_t *)state->pre_delay_buffers[ch]; - } else { - pd_read++; - } - idx += nch; - } - } - - state->pre_delay_write_index += frames; - state->pre_delay_write_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index += frames; - state->pre_delay_read_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; + drc_delay_input_sample_s32(state, source, sink, &x, &y, samples); return; } if (!state->processed) { drc_update_envelope(state, p); - drc_compress_output(state, p, 4, nch); + drc_compress_output(state, p, sizeof(int32_t), nch); state->processed = 1; } - offset = state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK; - while (i < frames) { - /* Copy fragment data from source to pre-delay buffers, and copy the output fragment - * to sink. - */ - fragment = MIN(DRC_DIVISION_FRAMES - offset, frames - i); - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; - for (ch = 0; ch < nch; ++ch) { - pd_write = (int32_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int32_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = i * nch + ch; - for (f = 0; f < fragment; ++f) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_write_frag_s32(sink, idx); - - /* Write/Read pre_delay_buffer as s32 format */ - *pd_write = *x << 8; - *y = sat_int24(Q_SHIFT_RND(*pd_read, 31, 23)); - - pd_write++; - pd_read++; - idx += nch; - } - } - state->pre_delay_write_index = - (pd_write_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index = - (pd_read_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; + while (samples) { + fragment = DRC_DIVISION_FRAMES - + (state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK); + fragment_samples = fragment * nch; + fragment_samples = MIN(samples, fragment_samples); - i += fragment; - offset = (offset + fragment) & DRC_DIVISION_FRAMES_MASK; + /* Use 24 bit delay function */ + drc_delay_input_sample_s24(state, source, sink, &x, &y, fragment_samples); + samples -= fragment_samples; /* Process the input division (32 frames). */ - if (offset == 0) - drc_process_one_division(state, p, 4, nch); + if ((state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK) == 0) + drc_process_one_division(state, p, sizeof(int32_t), nch); } } #endif /* CONFIG_FORMAT_S24LE */ @@ -724,102 +722,42 @@ static void drc_s32_default(const struct comp_dev *dev, struct audio_stream *sink, uint32_t frames) { - int32_t *x; - int32_t *y; - int32_t *pd_write; - int32_t *pd_read; - int offset; - int i = 0; - int ch; - int idx; - int f; - int fragment; - int pd_write_index; - int pd_read_index; + int32_t *x = source->r_ptr; + int32_t *y = sink->w_ptr; int nch = source->channels; - + int samples = frames * nch; struct drc_comp_data *cd = comp_get_drvdata(dev); struct drc_state *state = &cd->state; const struct sof_drc_params *p = &cd->config->params; /* Read-only */ + int fragment_samples; + int fragment; if (!p->enabled) { /* Delay the input sample only and don't do other processing. This is used when the * DRC is disabled. We want to do this to match the processing delay of other bands * in multi-band DRC kernel case. */ - for (ch = 0; ch < nch; ++ch) { - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; - pd_write = (int32_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int32_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = ch; - for (i = 0; i < frames; ++i) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_write_frag_s32(sink, idx); - *pd_write = *x; - *y = *pd_read; - if (++pd_write_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_write_index = 0; - pd_write = (int32_t *)state->pre_delay_buffers[ch]; - } else { - pd_write++; - } - if (++pd_read_index == CONFIG_DRC_MAX_PRE_DELAY_FRAMES) { - pd_read_index = 0; - pd_read = (int32_t *)state->pre_delay_buffers[ch]; - } else { - pd_read++; - } - idx += nch; - } - } - - state->pre_delay_write_index += frames; - state->pre_delay_write_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index += frames; - state->pre_delay_read_index &= DRC_MAX_PRE_DELAY_FRAMES_MASK; + drc_delay_input_sample_s32(state, source, sink, &x, &y, samples); return; } if (!state->processed) { drc_update_envelope(state, p); - drc_compress_output(state, p, 4, nch); + drc_compress_output(state, p, sizeof(int32_t), nch); state->processed = 1; } - offset = state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK; - while (i < frames) { - /* Copy fragment data from source to pre-delay buffers, and copy the output fragment - * to sink. - */ - fragment = MIN(DRC_DIVISION_FRAMES - offset, frames - i); - pd_write_index = state->pre_delay_write_index; - pd_read_index = state->pre_delay_read_index; - for (ch = 0; ch < nch; ++ch) { - pd_write = (int32_t *)state->pre_delay_buffers[ch] + pd_write_index; - pd_read = (int32_t *)state->pre_delay_buffers[ch] + pd_read_index; - idx = i * nch + ch; - for (f = 0; f < fragment; ++f) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_write_frag_s32(sink, idx); - *pd_write = *x; - *y = *pd_read; - pd_write++; - pd_read++; - idx += nch; - } - } - state->pre_delay_write_index = - (pd_write_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; - state->pre_delay_read_index = - (pd_read_index + fragment) & DRC_MAX_PRE_DELAY_FRAMES_MASK; - - i += fragment; - offset = (offset + fragment) & DRC_DIVISION_FRAMES_MASK; + while (samples) { + fragment = DRC_DIVISION_FRAMES - + (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); + samples -= fragment_samples; /* Process the input division (32 frames). */ - if (offset == 0) - drc_process_one_division(state, p, 4, nch); + if ((state->pre_delay_write_index & DRC_DIVISION_FRAMES_MASK) == 0) + drc_process_one_division(state, p, sizeof(int32_t), nch); } } #endif /* CONFIG_FORMAT_S32LE */ @@ -839,19 +777,4 @@ const struct drc_proc_fnmap drc_proc_fnmap[] = { #endif /* CONFIG_FORMAT_S32LE */ }; -const struct drc_proc_fnmap drc_proc_fnmap_pass[] = { -/* { SOURCE_FORMAT , PROCESSING FUNCTION } */ -#if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, drc_s16_default_pass }, -#endif /* CONFIG_FORMAT_S16LE */ - -#if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, drc_s32_default_pass }, -#endif /* CONFIG_FORMAT_S24LE */ - -#if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, drc_s32_default_pass }, -#endif /* CONFIG_FORMAT_S32LE */ -}; - const size_t drc_proc_fncount = ARRAY_SIZE(drc_proc_fnmap); diff --git a/src/include/sof/audio/drc/drc.h b/src/include/sof/audio/drc/drc.h index 645d9546ea5d..1ed278ba7b0a 100644 --- a/src/include/sof/audio/drc/drc.h +++ b/src/include/sof/audio/drc/drc.h @@ -78,9 +78,11 @@ struct drc_proc_fnmap { }; extern const struct drc_proc_fnmap drc_proc_fnmap[]; -extern const struct drc_proc_fnmap drc_proc_fnmap_pass[]; extern const size_t drc_proc_fncount; +void drc_default_pass(const struct comp_dev *dev, const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames); + /** * \brief Returns DRC processing function. */ @@ -96,19 +98,4 @@ static inline drc_func drc_find_proc_func(enum sof_ipc_frame src_fmt) return NULL; } -/** - * \brief Returns DRC passthrough functions. - */ -static inline drc_func drc_find_proc_func_pass(enum sof_ipc_frame src_fmt) -{ - int i; - - /* Find suitable processing function from map */ - for (i = 0; i < drc_proc_fncount; i++) - if (src_fmt == drc_proc_fnmap_pass[i].frame_fmt) - return drc_proc_fnmap_pass[i].drc_proc_func; - - return NULL; -} - #endif // __SOF_AUDIO_DRC_DRC_H__ From 29cba704502c1b47f93ba981801a44d108f04541 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 8 Mar 2022 17:13:05 +0200 Subject: [PATCH 2/2] Topology: Topology1: Add topology with playback DRC to HDA generic This patch enables testing of DRC in HDA generic devices by adding it to headset/speaker pipeline after mixer. Signed-off-by: Seppo Ingalsuo --- .../topology1/development/CMakeLists.txt | 2 + .../sof/pipe-mixer-drc-dai-playback.m4 | 83 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tools/topology/topology1/sof/pipe-mixer-drc-dai-playback.m4 diff --git a/tools/topology/topology1/development/CMakeLists.txt b/tools/topology/topology1/development/CMakeLists.txt index d7f39d5a4e6a..7c6ee829d073 100644 --- a/tools/topology/topology1/development/CMakeLists.txt +++ b/tools/topology/topology1/development/CMakeLists.txt @@ -50,6 +50,8 @@ set(TPLGS_UP "sof-hda-generic\;sof-hda-generic-4ch-loud\;-DCHANNELS=4\;-DHSPROC=eq-iir-eq-fir-volume\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DHSPROC_FILTER1=eq_iir_coef_pass.m4\;-DHSPROC_FILTER2=eq_fir_coef_loudness.m4\;-DDYNAMIC=1" "sof-hda-generic\;sof-hda-generic-multiband-drc\;-DCHANNELS=0\;-DHSPROC=multiband-drc\;-DDYNAMIC=1" "sof-hda-generic\;sof-hda-generic-2ch-multiband-drc\;-DCHANNELS=2\;-DHSPROC=multiband-drc\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DDYNAMIC=1" + "sof-hda-generic\;sof-hda-generic-drc\;-DCHANNELS=0\;-DHSPROC=drc\;-DDYNAMIC=1" + "sof-hda-generic\;sof-hda-generic-2ch-drc\;-DCHANNELS=2\;-DHSPROC=drc\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DDYNAMIC=1" "sof-tgl-rt711-rt1308\;sof-tgl-sdw-max98373-rt5682-dmic4ch-ampref\;-DCHANNELS=4\;-DEXT_AMP\;-DEXT_AMP_REF\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DPLATFORM=tgl" ) diff --git a/tools/topology/topology1/sof/pipe-mixer-drc-dai-playback.m4 b/tools/topology/topology1/sof/pipe-mixer-drc-dai-playback.m4 new file mode 100644 index 000000000000..08edefef0c4c --- /dev/null +++ b/tools/topology/topology1/sof/pipe-mixer-drc-dai-playback.m4 @@ -0,0 +1,83 @@ +# Mixer DAI Playback connector +# +# DAI playback starting with a LL mixer +# +# Pipeline Endpoints for connection are :- +# +# LL Playback Mixer (Mixer) +# LL Playback Volume B1 (DAI buffer) +# +# DAI_BUF --> ll mixer(M) --> B0 --> DRC(LL) --> B1 --> sink DAI +# +# the ll mixer is connected to one DAI_BUF by default. Additional ones can be added later + +# Include topology builder +include(`utils.m4') +include(`mixer.m4') +include(`buffer.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`bytecontrol.m4') +include(`drc.m4') + +# +# Controls +# + +# +# DRC Configuration +# + +define(DRC_priv, concat(`drc_bytes_', PIPELINE_ID)) +define(MY_DRC_CTRL, concat(`drc_control_', PIPELINE_ID)) +include(`drc_coef_default.m4') +C_CONTROLBYTES(MY_DRC_CTRL, PIPELINE_ID, + CONTROLBYTES_OPS(bytes, 258 binds the control to bytes get/put handlers, 258, 258), + CONTROLBYTES_EXTOPS(258 binds the control to bytes get/put handlers, 258, 258), + , , , + CONTROLBYTES_MAX(, 1024), + , + DRC_priv) + + +# Mixer 0 has 2 sink and source periods. +W_MIXER(0, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE) + +# "DRC" has 2 sink periods and 2 source periods +W_DRC(0, PIPELINE_FORMAT, DAI_PERIODS, 2, SCHEDULE_CORE, + LIST(` ', "MY_DRC_CTRL")) + +# +# DAI definitions +# +W_DAI_OUT(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 0, DAI_PERIODS, SCHEDULE_CORE) + +# +# DAI pipeline - always use 0 for DAIs - FIXME WHY 0? +# +W_PIPELINE(N_DAI_OUT, SCHEDULE_PERIOD, SCHEDULE_PRIORITY, SCHEDULE_CORE, SCHEDULE_TIME_DOMAIN, pipe_dai_schedule_plat) + +# Low Latency Buffers +W_BUFFER(0, COMP_BUFFER_SIZE(2, + COMP_SAMPLE_SIZE(DAI_FORMAT), DAI_CHANNELS, COMP_PERIOD_FRAMES(DAI_RATE, SCHEDULE_PERIOD)), + PLATFORM_COMP_MEM_CAP) +W_BUFFER(1, COMP_BUFFER_SIZE(2, + COMP_SAMPLE_SIZE(DAI_FORMAT), DAI_CHANNELS,COMP_PERIOD_FRAMES(DAI_RATE, SCHEDULE_PERIOD)), + PLATFORM_COMP_MEM_CAP) + +# +# Graph connections to pipelines +# we don't connect `dapm(N_MIXER(0), DAI_BUF)' due to forward dependencies +# +P_GRAPH(DAI_NAME, PIPELINE_ID, + LIST(` ', + `dapm(N_BUFFER(0), N_MIXER(0))', + `dapm(N_DRC(0), N_BUFFER(0))', + `dapm(N_BUFFER(1), N_DRC(0))' + `dapm(N_DAI_OUT, N_BUFFER(1))')) + +indir(`define', concat(`PIPELINE_PLAYBACK_SCHED_COMP_', PIPELINE_ID), N_DAI_OUT) +indir(`define', concat(`PIPELINE_MIXER_', PIPELINE_ID), N_MIXER(0)) + +undefine(`MY_DRC_CTRL') +undefine(`DRC_priv')