Skip to content

Commit

Permalink
ipc4: mixin: Add gain support (generic and HIFI3)
Browse files Browse the repository at this point in the history
Restore gain support which was accidentally removed during previous
HIFI optimization/refactoring.

This commit only adds gain supports to "generic" and "HIFI3" mixin
implementation.

Signed-off-by: Serhiy Katsyuba <[email protected]>
  • Loading branch information
serhiy-katsyuba-intel committed Apr 19, 2024
1 parent 62c8eef commit 0fb796f
Show file tree
Hide file tree
Showing 5 changed files with 530 additions and 18 deletions.
15 changes: 11 additions & 4 deletions src/audio/mixin_mixout/mixin_mixout.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct mixin_sink_config {
/* mixin component private data */
struct mixin_data {
mix_func mix;
mix_func gain_mix;
struct mixin_sink_config sink_config[MIXIN_MAX_SINKS];
};

Expand Down Expand Up @@ -205,8 +206,13 @@ static int mix(struct comp_dev *dev, const struct mixin_data *mixin_data,

sink_config = &mixin_data->sink_config[sink_index];

mixin_data->mix(sink, start_sample, mixed_samples,
if (sink_config->gain == IPC4_MIXIN_UNITY_GAIN) {
mixin_data->mix(sink, start_sample, mixed_samples,
source, sample_count, sink_config->gain);
} else {
mixin_data->gain_mix(sink, start_sample, mixed_samples,
source, sample_count, sink_config->gain);
}

return 0;
}
Expand Down Expand Up @@ -555,6 +561,7 @@ static int mixin_reset(struct processing_module *mod)
comp_dbg(dev, "mixin_reset()");

mixin_data->mix = NULL;
mixin_data->gain_mix = NULL;

return 0;
}
Expand Down Expand Up @@ -685,15 +692,15 @@ static int mixin_prepare(struct processing_module *mod,
case SOF_IPC_FRAME_S16_LE:
case SOF_IPC_FRAME_S24_4LE:
case SOF_IPC_FRAME_S32_LE:
md->mix = mixin_get_processing_function(fmt);
mixin_get_processing_functions(fmt, &md->mix, &md->gain_mix);
break;
default:
comp_err(dev, "unsupported data format %d", fmt);
return -EINVAL;
}

if (!md->mix) {
comp_err(dev, "have not found the suitable processing function");
if (!md->mix || !md->gain_mix) {
comp_err(dev, "have not found suitable processing functions");
return -EINVAL;
}

Expand Down
17 changes: 12 additions & 5 deletions src/audio/mixin_mixout/mixin_mixout.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ typedef void (*mix_func)(struct cir_buf_ptr *sink, int32_t start_sample,
*/
struct mix_func_map {
uint16_t frame_fmt; /* frame format */
mix_func func; /* mixin processing function */
mix_func mix; /* faster mixing func without gain support */
mix_func gain_mix; /* slower mixing func with gain support */
};

extern const struct mix_func_map mix_func_map[];
Expand All @@ -119,17 +120,23 @@ extern const size_t mix_count;
* \brief Retrievies mixin processing function.
* \param[in] fmt stream PCM frame format
*/
static inline mix_func mixin_get_processing_function(int fmt)
static inline bool mixin_get_processing_functions(int fmt, mix_func *mix, mix_func *gain_mix)
{
int i;

*mix = NULL;
*gain_mix = NULL;

/* map mixin processing function for source and sink buffers */
for (i = 0; i < mix_count; i++) {
if (fmt == mix_func_map[i].frame_fmt)
return mix_func_map[i].func;
if (fmt == mix_func_map[i].frame_fmt) {
*mix = mix_func_map[i].mix;
*gain_mix = mix_func_map[i].gain_mix;
return true;
}
}

return NULL;
return false;
}

#endif /* __SOF_IPC4_MIXIN_MIXOUT_H__ */
150 changes: 147 additions & 3 deletions src/audio/mixin_mixout/mixin_mixout_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
int16_t *dst = (int16_t *)sink->ptr + start_sample;
int16_t *src = source->ptr;

ARG_UNUSED(gain);

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
Expand Down Expand Up @@ -54,6 +56,54 @@ static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
src += n;
}
}

static void mix_s16_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples,
const struct cir_buf_ptr *source,
int32_t sample_count, uint16_t gain)
{
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;

/* cir_buf_wrap() is required and is done below in a loop */
int16_t *dst = (int16_t *)sink->ptr + start_sample;
int16_t *src = source->ptr;

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
samples_to_copy = sample_count - samples_to_mix;

for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
/* calculate the remaining samples*/
nmax = (int16_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int16_t *)sink->buf_end - dst;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sat_int16((int32_t)*dst +
q_mults_16x16(*src, gain, IPC4_MIXIN_GAIN_SHIFT));
src++;
dst++;
}
}

for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
nmax = (int16_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int16_t *)sink->buf_end - dst;
n = MIN(n, nmax);

for (i = 0; i < n; i++) {
*dst = q_mults_16x16(*src, gain, IPC4_MIXIN_GAIN_SHIFT);
src++;
dst++;
}
}
}
#endif /* CONFIG_FORMAT_S16LE */

#if CONFIG_FORMAT_S24LE
Expand All @@ -67,6 +117,8 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
int32_t *dst = (int32_t *)sink->ptr + start_sample;
int32_t *src = source->ptr;

ARG_UNUSED(gain);

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
Expand Down Expand Up @@ -99,6 +151,52 @@ static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
}
}

static void mix_s24_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples,
const struct cir_buf_ptr *source,
int32_t sample_count, uint16_t gain)
{
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;
/* cir_buf_wrap() is required and is done below in a loop */
int32_t *dst = (int32_t *)sink->ptr + start_sample;
int32_t *src = source->ptr;

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
samples_to_copy = sample_count - samples_to_mix;

for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
/* calculate the remaining samples*/
nmax = (int32_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int32_t *)sink->buf_end - dst;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sat_int24(sign_extend_s24(*dst) +
(int32_t)q_mults_32x32(sign_extend_s24(*src),
gain, IPC4_MIXIN_GAIN_SHIFT));
src++;
dst++;
}
}

for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
nmax = (int32_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int32_t *)sink->buf_end - dst;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = q_mults_32x32(sign_extend_s24(*src), gain, IPC4_MIXIN_GAIN_SHIFT);
src++;
dst++;
}
}
}
#endif /* CONFIG_FORMAT_S24LE */

#if CONFIG_FORMAT_S32LE
Expand All @@ -111,6 +209,8 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
int32_t *dst = (int32_t *)sink->ptr + start_sample;
int32_t *src = source->ptr;

ARG_UNUSED(gain);

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
Expand Down Expand Up @@ -143,17 +243,61 @@ static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixe
}
}

static void mix_s32_gain(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples,
const struct cir_buf_ptr *source,
int32_t sample_count, uint16_t gain)
{
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;
int32_t *dst = (int32_t *)sink->ptr + start_sample;
int32_t *src = source->ptr;

assert(mixed_samples >= start_sample);
samples_to_mix = mixed_samples - start_sample;
samples_to_mix = MIN(samples_to_mix, sample_count);
samples_to_copy = sample_count - samples_to_mix;

for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
/* calculate the remaining samples*/
nmax = (int32_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int32_t *)sink->buf_end - dst;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = sat_int32((int64_t)*dst +
q_mults_32x32(*src, gain, IPC4_MIXIN_GAIN_SHIFT));
src++;
dst++;
}
}

for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) {
src = cir_buf_wrap(src, source->buf_start, source->buf_end);
dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end);
nmax = (int32_t *)source->buf_end - src;
n = MIN(left_samples, nmax);
nmax = (int32_t *)sink->buf_end - dst;
n = MIN(n, nmax);
for (i = 0; i < n; i++) {
*dst = q_mults_32x32(*src, gain, IPC4_MIXIN_GAIN_SHIFT);
src++;
dst++;
}
}
}
#endif /* CONFIG_FORMAT_S32LE */

const struct mix_func_map mix_func_map[] = {
#if CONFIG_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, mix_s16 },
{ SOF_IPC_FRAME_S16_LE, mix_s16, mix_s16_gain },
#endif
#if CONFIG_FORMAT_S24LE
{ SOF_IPC_FRAME_S24_4LE, mix_s24 },
{ SOF_IPC_FRAME_S24_4LE, mix_s24, mix_s24_gain },
#endif
#if CONFIG_FORMAT_S32LE
{ SOF_IPC_FRAME_S32_LE, mix_s32 }
{ SOF_IPC_FRAME_S32_LE, mix_s32, mix_s32_gain }
#endif
};

Expand Down
Loading

0 comments on commit 0fb796f

Please sign in to comment.