Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
404 changes: 218 additions & 186 deletions src/audio/mixin_mixout/mixin_mixout.c

Large diffs are not rendered by default.

53 changes: 18 additions & 35 deletions src/audio/mixin_mixout/mixin_mixout.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,60 +102,43 @@ struct ipc4_mixer_mode_config {
struct ipc4_mixer_mode_sink_config mixer_mode_sink_configs[1];
} __packed __aligned(4);

/**
* \brief normal mode mixin_mixout processing function interface
*/
typedef void (*normal_mix_func)(struct audio_stream *sink, int32_t start_frame,
int32_t mixed_frames,
const struct audio_stream *source,
int32_t frame_count, uint16_t gain);
/* Pointer to data in circular buffer together with buffer boundaries */
struct cir_buf_ptr {
void *buf_start;
void *buf_end;
void *ptr;
};

/**
* \brief mixin_mixout mute processing function interface
* \brief mixin processing function interface
*/
typedef void (*mute_func) (struct audio_stream *stream, int32_t channel_index,
int32_t start_frame, int32_t mixed_frames, int32_t frame_count);
typedef void (*mix_func)(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);

/**
* @brief mixin_mixout processing functions map.
* @brief mixin processing functions map.
*/
struct mix_func_map {
uint16_t frame_fmt; /* frame format */
normal_mix_func normal_func; /* normal mode mixin_mixout processing function */
mute_func mute_func; /* mute processing function */
uint16_t frame_fmt; /* frame format */
mix_func func; /* mixin processing function */
};

extern const struct mix_func_map mix_func_map[];
extern const size_t mix_count;
/**
* \brief Retrievies normal mode mixer processing function.
* \param[in] fmt stream PCM frame format
*/
static inline normal_mix_func normal_mix_get_processing_function(int fmt)
{
int i;

/* map the normal mode mixin_mixout 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].normal_func;
}

return NULL;
}

/**
* \brief Retrievies normal mode mixer processing function.
* \brief Retrievies mixin processing function.
* \param[in] fmt stream PCM frame format
*/
static inline mute_func mute_mix_get_processing_function(int fmt)
static inline mix_func mixin_get_processing_function(int fmt)
{
int i;

/* map the mute function for source and sink buffers */
/* 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].mute_func;
return mix_func_map[i].func;
}

return NULL;
Expand Down
234 changes: 73 additions & 161 deletions src/audio/mixin_mixout/mixin_mixout_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,132 +12,86 @@
#ifdef MIXIN_MIXOUT_GENERIC

#if CONFIG_FORMAT_S16LE
/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source),
* sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse
* the function to also mix an entire stream. In this case the function is called with fake stream
* parameters: multichannel stream is treated as single channel and so the entire stream
* contents is mixed.
*/
static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_frame,
int32_t mixed_frames,
const struct audio_stream *source,
int32_t frame_count, uint16_t gain)
static void mix_s16(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 frames_to_mix, frames_to_copy, left_frames;
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;

/* audio_stream_wrap() is required and is done below in a loop */
int16_t *dst = (int16_t *)audio_stream_get_wptr(sink) + start_frame;
int16_t *src = audio_stream_get_rptr(source);
/* 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_frames >= start_frame);
frames_to_mix = mixed_frames - start_frame;
frames_to_mix = MIN(frames_to_mix, frame_count);
frames_to_copy = frame_count - frames_to_mix;
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_frames = frames_to_mix; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
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 = audio_stream_samples_without_wrap_s16(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s16(sink, dst);
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(*dst + *src++);
dst++;
}
}

for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
nmax = audio_stream_samples_without_wrap_s16(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s16(sink, 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);
memcpy_s(dst, n * sizeof(int16_t), src, n * sizeof(int16_t));
dst += n;
src += n;
}
}

static void mute_channel_s16(struct audio_stream *stream, int32_t channel_index,
int32_t start_frame, int32_t mixed_frames, int32_t frame_count)
{
int32_t skip_mixed_frames, n, left_frames, i, channel_count, frames, samples;
int16_t *ptr;

assert(mixed_frames >= start_frame);
skip_mixed_frames = mixed_frames - start_frame;

if (frame_count <= skip_mixed_frames)
return;
frame_count -= skip_mixed_frames;
channel_count = audio_stream_get_channels(stream);
/* audio_stream_wrap() is needed here and it is just below in a loop */
ptr = (int16_t *)audio_stream_get_wptr(stream) +
mixed_frames * audio_stream_get_channels(stream) +
channel_index;

for (left_frames = frame_count; left_frames; left_frames -= frames) {
ptr = audio_stream_wrap(stream, ptr);
n = audio_stream_samples_without_wrap_s16(stream, ptr);
samples = left_frames * channel_count;
n = MIN(samples, n);
frames = 0;
for (i = 0; i < n; i += channel_count) {
*ptr = 0;
ptr += channel_count;
frames++;
}
}
}
#endif /* CONFIG_FORMAT_S16LE */

#if CONFIG_FORMAT_S24LE
/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source),
* sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse
* the function to also mix an entire stream. In this case the function is called with fake stream
* parameters: multichannel stream is treated as single channel and so the entire stream
* contents is mixed.
*/
static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_frame,
int32_t mixed_frames,
const struct audio_stream *source,
int32_t frame_count, uint16_t gain)
static void mix_s24(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 frames_to_mix, frames_to_copy, left_frames;
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;
/* audio_stream_wrap() is required and is done below in a loop */
int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame;
int32_t *src = audio_stream_get_rptr(source);

assert(mixed_frames >= start_frame);
frames_to_mix = mixed_frames - start_frame;
frames_to_mix = MIN(frames_to_mix, frame_count);
frames_to_copy = frame_count - frames_to_mix;

for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
/* 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 = audio_stream_samples_without_wrap_s24(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s24(sink, dst);
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) + sign_extend_s24(*src++));
dst++;
}
}

for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
nmax = audio_stream_samples_without_wrap_s24(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s24(sink, 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);
memcpy_s(dst, n * sizeof(int32_t), src, n * sizeof(int32_t));
dst += n;
Expand All @@ -148,47 +102,40 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram
#endif /* CONFIG_FORMAT_S24LE */

#if CONFIG_FORMAT_S32LE
/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source),
* sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse
* the function to also mix an entire stream. In this case the function is called with fake stream
* parameters: multichannel stream is treated as single channel and so the entire stream
* contents is mixed.
*/
static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_frame,
int32_t mixed_frames,
const struct audio_stream *source,
int32_t frame_count, uint16_t gain)
static void mix_s32(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 frames_to_mix, frames_to_copy, left_frames;
int32_t samples_to_mix, samples_to_copy, left_samples;
int32_t n, nmax, i;
int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame;
int32_t *src = audio_stream_get_rptr(source);
int32_t *dst = (int32_t *)sink->ptr + start_sample;
int32_t *src = source->ptr;

assert(mixed_frames >= start_frame);
frames_to_mix = mixed_frames - start_frame;
frames_to_mix = MIN(frames_to_mix, frame_count);
frames_to_copy = frame_count - frames_to_mix;
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_frames = frames_to_mix; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
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 = audio_stream_samples_without_wrap_s32(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s32(sink, dst);
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 + (int64_t)*src++);
dst++;
}
}

for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) {
src = audio_stream_wrap(source, src);
dst = audio_stream_wrap(sink, dst);
nmax = audio_stream_samples_without_wrap_s32(source, src);
n = MIN(left_frames, nmax);
nmax = audio_stream_samples_without_wrap_s32(sink, 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);
memcpy_s(dst, n * sizeof(int32_t), src, n * sizeof(int32_t));
dst += n;
Expand All @@ -198,50 +145,15 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram

#endif /* CONFIG_FORMAT_S32LE */

#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE
static void mute_channel_s32(struct audio_stream *stream, int32_t channel_index,
int32_t start_frame, int32_t mixed_frames, int32_t frame_count)
{
int32_t skip_mixed_frames, left_frames, n, channel_count, i, frames, samples;
int32_t *ptr;

assert(mixed_frames >= start_frame);
skip_mixed_frames = mixed_frames - start_frame;

if (frame_count <= skip_mixed_frames)
return;
frame_count -= skip_mixed_frames;
channel_count = audio_stream_get_channels(stream);

ptr = (int32_t *)audio_stream_get_wptr(stream) +
mixed_frames * audio_stream_get_channels(stream) +
channel_index;

for (left_frames = frame_count; left_frames > 0; left_frames -= frames) {
ptr = audio_stream_wrap(stream, ptr);
n = audio_stream_samples_without_wrap_s32(stream, ptr);
samples = left_frames * channel_count;
n = MIN(samples, n);
frames = 0;
for (i = 0; i < n; i += channel_count) {
*ptr = 0;
ptr += channel_count;
frames++;
}
}
}

#endif

const struct mix_func_map mix_func_map[] = {
#if CONFIG_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, normal_mix_channel_s16, mute_channel_s16},
{ SOF_IPC_FRAME_S16_LE, mix_s16 },
#endif
#if CONFIG_FORMAT_S24LE
{ SOF_IPC_FRAME_S24_4LE, normal_mix_channel_s24, mute_channel_s32},
{ SOF_IPC_FRAME_S24_4LE, mix_s24 },
#endif
#if CONFIG_FORMAT_S32LE
{ SOF_IPC_FRAME_S32_LE, normal_mix_channel_s32, mute_channel_s32}
{ SOF_IPC_FRAME_S32_LE, mix_s32 }
#endif
};

Expand Down
Loading