From 837c9951e9725a2f70a1d1d9facff16c3c7cd2aa Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Thu, 24 Oct 2019 14:50:29 +0200 Subject: [PATCH 01/15] dma: change signatures of copy buffer functions Changes signatures of copy DMA buffer functions to differentiate between source and sink bytes. Process function from now on will work on provided samples to handle different formats on input and output. Signed-off-by: Tomasz Lauda --- src/audio/dai.c | 9 ++++---- src/audio/host.c | 9 ++++---- src/include/sof/audio/buffer.h | 10 ++++----- src/include/sof/lib/dma.h | 16 +++++++++----- src/lib/dma.c | 40 +++++++++++++++++++--------------- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/audio/dai.c b/src/audio/dai.c index aa2aee015c12..9629a7b53a79 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -108,16 +108,17 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_cb_data *next) local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - dma_buffer_copy_to(local_buffer, dd->dma_buffer, dd->process, - bytes); + dma_buffer_copy_to(local_buffer, bytes, dd->dma_buffer, bytes, + dd->process, bytes / comp_sample_bytes(dev)); buffer_ptr = local_buffer->r_ptr; } else { local_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - dma_buffer_copy_from(dd->dma_buffer, local_buffer, dd->process, - bytes); + dma_buffer_copy_from(dd->dma_buffer, bytes, local_buffer, bytes, + dd->process, + bytes / comp_sample_bytes(dev)); buffer_ptr = local_buffer->w_ptr; } diff --git a/src/audio/host.c b/src/audio/host.c index f4d0841e60df..a9dd343c477f 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -141,13 +141,14 @@ static void host_update_position(struct comp_dev *dev, uint32_t bytes) if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) { local_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - dma_buffer_copy_from(hd->dma_buffer, local_buffer, hd->process, - bytes); + dma_buffer_copy_from(hd->dma_buffer, bytes, local_buffer, bytes, + hd->process, + bytes / comp_sample_bytes(dev)); } else { local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - dma_buffer_copy_to(local_buffer, hd->dma_buffer, hd->process, - bytes); + dma_buffer_copy_to(local_buffer, bytes, hd->dma_buffer, bytes, + hd->process, bytes / comp_sample_bytes(dev)); } dev->position += bytes; diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 583628eb404a..63e4c7ae4a52 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -230,15 +230,14 @@ static inline void buffer_init(struct comp_buffer *buffer, uint32_t size, } static inline void buffer_copy_s16(struct comp_buffer *source, - struct comp_buffer *sink, uint32_t bytes) + struct comp_buffer *sink, uint32_t samples) { - uint32_t frames = bytes / sizeof(int16_t); uint32_t buff_frag = 0; int16_t *src; int16_t *dst; uint32_t i; - for (i = 0; i < frames; i++) { + for (i = 0; i < samples; i++) { src = buffer_read_frag_s16(source, buff_frag); dst = buffer_write_frag_s16(sink, buff_frag); *dst = *src; @@ -248,15 +247,14 @@ static inline void buffer_copy_s16(struct comp_buffer *source, } static inline void buffer_copy_s32(struct comp_buffer *source, - struct comp_buffer *sink, uint32_t bytes) + struct comp_buffer *sink, uint32_t samples) { - uint32_t frames = bytes / sizeof(int32_t); uint32_t buff_frag = 0; int32_t *src; int32_t *dst; uint32_t i; - for (i = 0; i < frames; i++) { + for (i = 0; i < samples; i++) { src = buffer_read_frag_s32(source, buff_frag); dst = buffer_write_frag_s32(sink, buff_frag); *dst = *src; diff --git a/src/include/sof/lib/dma.h b/src/include/sof/lib/dma.h index d8eaa126c855..1cfc3050dd25 100644 --- a/src/include/sof/lib/dma.h +++ b/src/include/sof/lib/dma.h @@ -509,14 +509,18 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) } /* copies data from DMA buffer using provided processing function */ -void dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - void (*process)(struct comp_buffer *, struct comp_buffer *, uint32_t), - uint32_t bytes); +void dma_buffer_copy_from(struct comp_buffer *source, uint32_t source_bytes, + struct comp_buffer *sink, uint32_t sink_bytes, + void (*process)(struct comp_buffer *, + struct comp_buffer *, uint32_t), + uint32_t samples); /* copies data to DMA buffer using provided processing function */ -void dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - void (*process)(struct comp_buffer *, struct comp_buffer *, uint32_t), - uint32_t bytes); +void dma_buffer_copy_to(struct comp_buffer *source, uint32_t source_bytes, + struct comp_buffer *sink, uint32_t sink_bytes, + void (*process)(struct comp_buffer *, + struct comp_buffer *, uint32_t), + uint32_t samples); /* generic DMA DSP <-> Host copier */ diff --git a/src/lib/dma.c b/src/lib/dma.c index f473ceb9ab2e..81a3560c067a 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -189,17 +189,19 @@ void dma_sg_free(struct dma_sg_elem_array *elem_array) dma_sg_init(elem_array); } -void dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - void (*process)(struct comp_buffer *, struct comp_buffer *, uint32_t), - uint32_t bytes) +void dma_buffer_copy_from(struct comp_buffer *source, uint32_t source_bytes, + struct comp_buffer *sink, uint32_t sink_bytes, + void (*process)(struct comp_buffer *, + struct comp_buffer *, uint32_t), + uint32_t samples) { - uint32_t head = bytes; + uint32_t head = source_bytes; uint32_t tail = 0; /* source buffer contains data copied by DMA */ - if ((char *)source->r_ptr + bytes > (char *)source->end_addr) { + if ((char *)source->r_ptr + source_bytes > (char *)source->end_addr) { head = (char *)source->end_addr - (char *)source->r_ptr; - tail = bytes - head; + tail = source_bytes - head; } dcache_invalidate_region(source->r_ptr, head); @@ -207,44 +209,46 @@ void dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, dcache_invalidate_region(source->addr, tail); /* process data */ - process(source, sink, bytes); + process(source, sink, samples); - source->r_ptr = (char *)source->r_ptr + bytes; + source->r_ptr = (char *)source->r_ptr + source_bytes; /* check for pointer wrap */ if (source->r_ptr >= source->end_addr) source->r_ptr = (char *)source->addr + ((char *)source->r_ptr - (char *)source->end_addr); - comp_update_buffer_produce(sink, bytes); + comp_update_buffer_produce(sink, sink_bytes); } -void dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - void (*process)(struct comp_buffer *, struct comp_buffer *, uint32_t), - uint32_t bytes) +void dma_buffer_copy_to(struct comp_buffer *source, uint32_t source_bytes, + struct comp_buffer *sink, uint32_t sink_bytes, + void (*process)(struct comp_buffer *, + struct comp_buffer *, uint32_t), + uint32_t samples) { - uint32_t head = bytes; + uint32_t head = sink_bytes; uint32_t tail = 0; /* process data */ - process(source, sink, bytes); + process(source, sink, samples); /* sink buffer contains data meant to copied to DMA */ - if ((char *)sink->w_ptr + bytes > (char *)sink->end_addr) { + if ((char *)sink->w_ptr + sink_bytes > (char *)sink->end_addr) { head = (char *)sink->end_addr - (char *)sink->w_ptr; - tail = bytes - head; + tail = sink_bytes - head; } dcache_writeback_region(sink->w_ptr, head); if (tail) dcache_writeback_region(sink->addr, tail); - sink->w_ptr = (char *)sink->w_ptr + bytes; + sink->w_ptr = (char *)sink->w_ptr + sink_bytes; /* check for pointer wrap */ if (sink->w_ptr >= sink->end_addr) sink->w_ptr = (char *)sink->addr + ((char *)sink->w_ptr - (char *)sink->end_addr); - comp_update_buffer_consume(source, bytes); + comp_update_buffer_consume(source, source_bytes); } From fe30d8d79f48cea9267b146e17360abcf600ce55 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 15:24:58 +0100 Subject: [PATCH 02/15] common: add IS_ALIGNED macro Implements macro to check whether value is aligned. Signed-off-by: Tomasz Lauda --- src/include/sof/common.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/sof/common.h b/src/include/sof/common.h index 2f908285d7ff..05a433b2a8a8 100644 --- a/src/include/sof/common.h +++ b/src/include/sof/common.h @@ -19,8 +19,9 @@ (type *)((char *)__memberptr - offsetof(type, member)); }) /* Align the number to the nearest alignment value */ +#define IS_ALIGNED(size, alignment) ((size) % (alignment) == 0) #define ALIGN_UP(size, alignment) \ - (((size) % (alignment) == 0) ? (size) : \ + (IS_ALIGNED(size, alignment) ? (size) : \ ((size) - ((size) % (alignment)) + (alignment))) #define ALIGN_DOWN(size, alignment) \ ((size) - ((size) % (alignment))) From e8015198d90caf6dfd07a5635d9ee8d81ab4c8b1 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Thu, 24 Oct 2019 15:05:53 +0200 Subject: [PATCH 03/15] pcm_converter: add generic implementation Implements generic version of PCM converter library component. This module provides static functions, which allows to copy buffer data with frame format conversion. Signed-off-by: Tomasz Lauda --- src/audio/CMakeLists.txt | 1 + src/audio/pcm_converter/CMakeLists.txt | 3 + .../pcm_converter/pcm_converter_generic.c | 154 ++++++++++++++++++ src/include/sof/audio/pcm_converter.h | 63 +++++++ 4 files changed, 221 insertions(+) create mode 100644 src/audio/pcm_converter/CMakeLists.txt create mode 100644 src/audio/pcm_converter/pcm_converter_generic.c create mode 100644 src/include/sof/audio/pcm_converter.h diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index fbd488f8aa2c..13af9f91bf96 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -57,6 +57,7 @@ if(NOT BUILD_LIBRARY) detect_test.c ) endif() + add_subdirectory(pcm_converter) return() endif() diff --git a/src/audio/pcm_converter/CMakeLists.txt b/src/audio/pcm_converter/CMakeLists.txt new file mode 100644 index 000000000000..febd65d6ffee --- /dev/null +++ b/src/audio/pcm_converter/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof pcm_converter_generic.c) diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c new file mode 100644 index 000000000000..4bedbb8f21f9 --- /dev/null +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Author: Tomasz Lauda + +/** + * \file audio/pcm_converter/pcm_converter_generic.c + * \brief PCM converter generic processing implementation + * \authors Tomasz Lauda + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + +static void pcm_convert_s16_to_s24(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int16_t *src; + int32_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s16(source, buff_frag); + dst = buffer_write_frag_s32(sink, buff_frag); + *dst = *src << 8; + buff_frag++; + } +} + +static void pcm_convert_s24_to_s16(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int32_t *src; + int16_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s32(source, buff_frag); + dst = buffer_write_frag_s16(sink, buff_frag); + *dst = sat_int16(Q_SHIFT_RND(sign_extend_s24(*src), 23, 15)); + buff_frag++; + } +} + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + +static void pcm_convert_s16_to_s32(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int16_t *src; + int32_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s16(source, buff_frag); + dst = buffer_write_frag_s32(sink, buff_frag); + *dst = *src << 16; + buff_frag++; + } +} + +static void pcm_convert_s32_to_s16(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int32_t *src; + int16_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s32(source, buff_frag); + dst = buffer_write_frag_s16(sink, buff_frag); + *dst = sat_int16(Q_SHIFT_RND(*src, 31, 15)); + buff_frag++; + } +} + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + +static void pcm_convert_s24_to_s32(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int32_t *src; + int32_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s32(source, buff_frag); + dst = buffer_write_frag_s32(sink, buff_frag); + *dst = *src << 8; + buff_frag++; + } +} + +static void pcm_convert_s32_to_s24(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + uint32_t buff_frag = 0; + int32_t *src; + int32_t *dst; + uint32_t i; + + for (i = 0; i < samples; i++) { + src = buffer_read_frag_s32(source, buff_frag); + dst = buffer_write_frag_s32(sink, buff_frag); + *dst = sat_int24(Q_SHIFT_RND(*src, 31, 23)); + buff_frag++; + } +} + +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ + +const struct pcm_func_map pcm_func_map[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, buffer_copy_s16 }, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, buffer_copy_s32 }, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, buffer_copy_s32 }, +#endif /* CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s32_to_s16 }, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 }, +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ +}; + +const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h new file mode 100644 index 000000000000..842bb825f8ab --- /dev/null +++ b/src/include/sof/audio/pcm_converter.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +/** + * \file audio/pcm_converter.h + * \brief PCM converter header file + * \authors Tomasz Lauda + */ + +#ifndef __SOF_AUDIO_PCM_CONVERTER_H__ +#define __SOF_AUDIO_PCM_CONVERTER_H__ + +#include +#include +#include + +struct comp_buffer; + +/** \brief PCM conversion functions map. */ +struct pcm_func_map { + enum sof_ipc_frame source; /**< source frame format */ + enum sof_ipc_frame sink; /**< sink frame format */ + /**< PCM conversion function */ + void (*func)(struct comp_buffer *source, struct comp_buffer *sink, + uint32_t samples); +}; + +/** \brief Map of formats with dedicated conversion functions. */ +extern const struct pcm_func_map pcm_func_map[]; + +/** \brief Number of conversion functions. */ +extern const uint32_t pcm_func_count; + +typedef void (*conversion)(struct comp_buffer *, struct comp_buffer *, + uint32_t); + +/** + * \brief Retrieves PCM conversion function. + * \param[in] in Source frame format. + * \param[in] out Sink frame format. + */ +static inline conversion pcm_get_conversion_function(enum sof_ipc_frame in, + enum sof_ipc_frame out) +{ + uint32_t i; + + for (i = 0; i < pcm_func_count; i++) { + if (in != pcm_func_map[i].source) + continue; + if (out != pcm_func_map[i].sink) + continue; + + return pcm_func_map[i].func; + } + + return NULL; +} + +#endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */ From 70f8f05c75c83d9fe51ff9124b5f2a583359c9cb Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 12:16:25 +0100 Subject: [PATCH 04/15] pcm_converter: add HiFi3 implementation HiFi3 implementation of PCM converter is optimized to process either two samples at once for 32 bit data or four samples for 16 bit data. Signed-off-by: Tomasz Lauda --- src/audio/pcm_converter/CMakeLists.txt | 2 +- .../pcm_converter/pcm_converter_generic.c | 7 +- src/audio/pcm_converter/pcm_converter_hifi3.c | 592 ++++++++++++++++++ src/include/sof/audio/pcm_converter.h | 15 + 4 files changed, 614 insertions(+), 2 deletions(-) create mode 100644 src/audio/pcm_converter/pcm_converter_hifi3.c diff --git a/src/audio/pcm_converter/CMakeLists.txt b/src/audio/pcm_converter/CMakeLists.txt index febd65d6ffee..8100bec72125 100644 --- a/src/audio/pcm_converter/CMakeLists.txt +++ b/src/audio/pcm_converter/CMakeLists.txt @@ -1,3 +1,3 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof pcm_converter_generic.c) +add_local_sources(sof pcm_converter_generic.c pcm_converter_hifi3.c) diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 4bedbb8f21f9..23249e85a938 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -10,9 +10,12 @@ * \authors Tomasz Lauda */ +#include + +#ifdef PCM_CONVERTER_GENERIC + #include #include -#include #include #include #include @@ -152,3 +155,5 @@ const struct pcm_func_map pcm_func_map[] = { }; const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); + +#endif diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c new file mode 100644 index 000000000000..525662b08ef3 --- /dev/null +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Author: Tomasz Lauda + +/** + * \file audio/pcm_converter/pcm_converter_hifi3.c + * \brief PCM converter HiFi3 processing implementation + * \authors Tomasz Lauda + */ + +#include + +#ifdef PCM_CONVERTER_HIFI3 + +#include +#include +#include +#include +#include +#include +#include + +/** + * \brief Sets buffer to be circular using HiFi3 functions. + * \param[in,out] buffer Circular buffer. + */ +static void pcm_converter_setup_circular(struct comp_buffer *buffer) +{ + AE_SETCBEGIN0(buffer->addr); + AE_SETCEND0(buffer->end_addr); +} + +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + +/** + * \brief HiFi3 enabled PCM conversion from 16 bit to 24 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s16_to_s24(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int16 *in = (ae_int16 *)source->r_ptr; + ae_int32 *out = (ae_int32 *)sink->w_ptr; + ae_int16x4 sample = AE_ZERO16(); + ae_valign align_out = AE_ZALIGN64(); + ae_int16x4 *in16x4; + ae_int32x2 *out32x2; + int i = 0; + + /* required alignment for AE_L16X4_XC */ + while (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 16 bit sample */ + AE_L16_XC(sample, in, sizeof(ae_int16)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store one 32 bit sample */ + AE_S32_L_XC(AE_SRAI32(AE_CVT32X2F16_32(sample), 8), out, + sizeof(ae_int32)); + + if (++i == samples) + return; + } + + in16x4 = (ae_int16x4 *)in; + out32x2 = (ae_int32x2 *)out; + + /* main loop processes 4 samples at a time */ + while (i < samples - 3) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load four 16 bit samples */ + AE_L16X4_XC(sample, in16x4, sizeof(ae_int16x4)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store four 32 bit samples */ + AE_SA32X2_IC(AE_SRAI32(AE_CVT32X2F16_32(sample), 8), align_out, + out32x2); + AE_SA32X2_IC(AE_SRAI32(AE_CVT32X2F16_10(sample), 8), align_out, + out32x2); + + i += 4; + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out32x2); + + in = (ae_int16 *)in16x4; + out = (ae_int32 *)out32x2; + + while (i++ != samples) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 16 bit sample */ + AE_L16_XC(sample, in, sizeof(ae_int16)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store one 32 bit sample */ + AE_S32_L_XC(AE_SRAI32(AE_CVT32X2F16_32(sample), 8), out, + sizeof(ae_int32)); + } +} + +/** + * \brief HiFi3 enabled PCM shift from 24 bit to 16 bit. + * \param[in] sample Input sample. + * \return Shifted sample. + */ +static ae_int32x2 pcm_shift_s24_to_s16(ae_int32x2 sample) +{ + /* shift with saturation and rounding */ + sample = AE_SLAA32(sample, 8); + sample = AE_SRAI32R(sample, 16); + sample = AE_SLAI32S(sample, 16); + sample = AE_SRAI32(sample, 16); + + return sample; +} + +/** + * \brief HiFi3 enabled PCM conversion from 24 bit to 16 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s24_to_s16(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int32x2 *in = (ae_int32x2 *)source->r_ptr; + ae_int16x4 *out = (ae_int16x4 *)sink->w_ptr; + ae_int16x4 sample = AE_ZERO16(); + ae_int32x2 sample_1 = AE_ZERO32(); + ae_int32x2 sample_2 = AE_ZERO32(); + ae_valign align_out = AE_ZALIGN64(); + int i = 0; + int leftover; + + /* required alignment for AE_L32X2_XC */ + if (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample_1, (ae_int32 *)in, sizeof(ae_int32)); + + /* shift and round */ + sample_1 = pcm_shift_s24_to_s16(sample_1); + sample = AE_MOVINT16X4_FROMINT32X2(sample_1); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_0(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + samples--; + } + + /* main loop processes 4 samples at a time */ + while (i < samples - 3) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load four 32 bit samples */ + AE_L32X2_XC(sample_1, in, sizeof(ae_int32x2)); + AE_L32X2_XC(sample_2, in, sizeof(ae_int32x2)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift and round */ + sample_1 = pcm_shift_s24_to_s16(sample_1); + sample_2 = pcm_shift_s24_to_s16(sample_2); + + /* store four 16 bit samples */ + sample = AE_CVT16X4(sample_1, sample_2); + AE_SA16X4_IC(sample, align_out, out); + + i += 4; + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out); + + leftover = samples - i; + + while (leftover) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load two 32 bit samples */ + AE_L32X2_XC(sample_1, in, sizeof(ae_int32x2)); + + /* shift and round */ + sample_1 = pcm_shift_s24_to_s16(sample_1); + sample = AE_MOVINT16X4_FROMINT32X2(sample_1); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_2(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + /* no more samples to process */ + if (leftover == 1) + return; + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_0(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + leftover -= 2; + } +} + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + +/** + * \brief HiFi3 enabled PCM conversion from 16 bit to 32 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s16_to_s32(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int16 *in = (ae_int16 *)source->r_ptr; + ae_int32 *out = (ae_int32 *)sink->w_ptr; + ae_int16x4 sample = AE_ZERO16(); + ae_valign align_out = AE_ZALIGN64(); + ae_int16x4 *in16x4; + ae_int32x2 *out32x2; + int i = 0; + + /* required alignment for AE_L16X4_XC */ + while (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 16 bit sample */ + AE_L16_XC(sample, in, sizeof(ae_int16)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 32 bit sample */ + AE_S32_L_XC(AE_CVT32X2F16_32(sample), out, sizeof(ae_int32)); + + if (++i == samples) + return; + } + + in16x4 = (ae_int16x4 *)in; + out32x2 = (ae_int32x2 *)out; + + /* main loop processes 4 samples at a time */ + while (i < samples - 3) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load four 16 bit samples */ + AE_L16X4_XC(sample, in16x4, sizeof(ae_int16x4)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store two 32 bit samples */ + AE_SA32X2_IC(AE_CVT32X2F16_32(sample), align_out, out32x2); + AE_SA32X2_IC(AE_CVT32X2F16_10(sample), align_out, out32x2); + + i += 4; + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out32x2); + + in = (ae_int16 *)in16x4; + out = (ae_int32 *)out32x2; + + while (i++ != samples) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 16 bit sample */ + AE_L16_XC(sample, in, sizeof(ae_int16)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 32 bit sample */ + AE_S32_L_XC(AE_CVT32X2F16_32(sample), out, sizeof(ae_int32)); + } +} + +/** + * \brief HiFi3 enabled PCM conversion from 32 bit to 16 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s32_to_s16(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int32x2 *in = (ae_int32x2 *)source->r_ptr; + ae_int16x4 *out = (ae_int16x4 *)sink->w_ptr; + ae_int16x4 sample = AE_ZERO16(); + ae_int32x2 sample_1 = AE_ZERO32(); + ae_int32x2 sample_2 = AE_ZERO32(); + ae_valign align_out = AE_ZALIGN64(); + int i = 0; + int leftover; + + /* required alignment for AE_L32X2_XC */ + if (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample_1, (ae_int32 *)in, sizeof(ae_int32)); + + /* shift and round */ + sample = AE_ROUND16X4F32SSYM(sample_1, sample_1); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_0(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + samples--; + } + + /* main loop processes 4 samples at a time */ + while (i < samples - 3) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load four 32 bit samples */ + AE_L32X2_XC(sample_1, in, sizeof(ae_int32x2)); + AE_L32X2_XC(sample_2, in, sizeof(ae_int32x2)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift and round */ + sample = AE_ROUND16X4F32SSYM(sample_1, sample_2); + + /* store four 16 bit samples */ + AE_SA16X4_IC(sample, align_out, out); + + i += 4; + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out); + + leftover = samples - i; + + while (leftover) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load two 32 bit samples */ + AE_L32X2_XC(sample_1, in, sizeof(ae_int32x2)); + + /* shift and round */ + sample = AE_ROUND16X4F32SSYM(sample_1, sample_1); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_1(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + /* no more samples to process */ + if (leftover == 1) + return; + + /* store one 16 bit sample */ + AE_S16_0_XC(AE_MOVAD16_0(sample), (ae_int16 *)out, + sizeof(ae_int16)); + + leftover -= 2; + } +} + +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ + +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + +/** + * \brief HiFi3 enabled PCM conversion from 24 bit to 32 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s24_to_s32(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int32x2 *in = (ae_int32x2 *)source->r_ptr; + ae_int32x2 *out = (ae_int32x2 *)sink->w_ptr; + ae_int32x2 sample = AE_ZERO32(); + ae_valign align_out = AE_ZALIGN64(); + int i; + + /* required alignment for AE_L32X2_XC */ + if (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample, (ae_int32 *)in, sizeof(ae_int32)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift left and store one 32 bit sample */ + AE_S32_L_XC(AE_SLAI32(sample, 8), (ae_int32 *)out, + sizeof(ae_int32)); + + samples--; + } + + /* main loop processes 2 samples at a time */ + for (i = 0; i < samples / 2; i++) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load two 32 bit samples */ + AE_L32X2_XC(sample, in, sizeof(ae_int32x2)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift left and store two 32 bit samples */ + AE_SA32X2_IC(AE_SLAI32(sample, 8), align_out, out); + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out); + + /* no more samples to process */ + if (!(samples % 2)) + return; + + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample, (ae_int32 *)in, 0); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift left and store one 32 bit sample */ + AE_S32_L_XC(AE_SLAI32(sample, 8), (ae_int32 *)out, 0); +} + +/** + * \brief HiFi3 enabled PCM shift from 32 bit to 24 bit. + * \param[in] sample Input sample. + * \return Shifted sample. + */ +static ae_int32x2 pcm_shift_s32_to_s24(ae_int32x2 sample) +{ + /* shift with saturation and rounding */ + sample = AE_SRAI32R(sample, 8); + sample = AE_SLAI32S(sample, 8); + sample = AE_SRAI32(sample, 8); + + return sample; +} + +/** + * \brief HiFi3 enabled PCM conversion from 32 bit to 24 bit. + * \param[in,out] source Source buffer. + * \param[in,out] sink Destination buffer. + * \param[in] samples Number of samples to process. + */ +static void pcm_convert_s32_to_s24(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t samples) +{ + ae_int32x2 *in = (ae_int32x2 *)source->r_ptr; + ae_int32x2 *out = (ae_int32x2 *)sink->w_ptr; + ae_int32x2 sample = AE_ZERO32(); + ae_valign align_out = AE_ZALIGN64(); + int i; + + /* required alignment for AE_L32X2_XC */ + if (!IS_ALIGNED((uintptr_t)in, 8)) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample, (ae_int32 *)in, sizeof(ae_int32)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store one 32 bit sample */ + sample = pcm_shift_s32_to_s24(sample); + AE_S32_L_XC(sample, (ae_int32 *)out, sizeof(ae_int32)); + + samples--; + } + + /* main loop processes 2 samples at a time */ + for (i = 0; i < samples / 2; i++) { + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load two 32 bit samples */ + AE_L32X2_XC(sample, in, sizeof(ae_int32x2)); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store two 32 bit samples */ + sample = pcm_shift_s32_to_s24(sample); + AE_SA32X2_IC(sample, align_out, out); + } + + /* flush align_out register to memory */ + AE_SA64POS_FC(align_out, out); + + /* no more samples to process */ + if (!(samples % 2)) + return; + + /* set source as circular buffer */ + pcm_converter_setup_circular(source); + + /* load one 32 bit sample */ + AE_L32_XC(sample, (ae_int32 *)in, 0); + + /* set sink as circular buffer */ + pcm_converter_setup_circular(sink); + + /* shift right and store one 32 bit sample */ + sample = pcm_shift_s32_to_s24(sample); + AE_S32_L_XC(sample, (ae_int32 *)out, 0); +} + +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ + +const struct pcm_func_map pcm_func_map[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, buffer_copy_s16 }, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, buffer_copy_s32 }, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, buffer_copy_s32 }, +#endif /* CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s32_to_s16 }, +#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 }, +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ +}; + +const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); + +#endif diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index 842bb825f8ab..9e0e1bdd16dc 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -20,6 +20,21 @@ struct comp_buffer; +#define PCM_CONVERTER_GENERIC + +#if __XCC__ + +#include + +#if XCHAL_HAVE_HIFI3 + +#undef PCM_CONVERTER_GENERIC +#define PCM_CONVERTER_HIFI3 + +#endif + +#endif + /** \brief PCM conversion functions map. */ struct pcm_func_map { enum sof_ipc_frame source; /**< source frame format */ From 04347a83a9d91799e1c0f0ea97c82d133b8ac557 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 08:26:18 +0100 Subject: [PATCH 05/15] format: add sample_bytes and frame_bytes functions Implements functions for sample bytes and frame bytes calculations based on provided frame format and channels. Signed-off-by: Tomasz Lauda --- src/include/sof/audio/format.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/include/sof/audio/format.h b/src/include/sof/audio/format.h index 9c27df1b92bc..fcd6f0140ae3 100644 --- a/src/include/sof/audio/format.h +++ b/src/include/sof/audio/format.h @@ -10,6 +10,7 @@ #ifndef __SOF_AUDIO_FORMAT_H__ #define __SOF_AUDIO_FORMAT_H__ +#include #include /* Maximum and minimum values for 24 bit */ @@ -160,4 +161,14 @@ static inline int32_t sign_extend_s24(int32_t x) return (x << 8) >> 8; } +static inline uint32_t sample_bytes(enum sof_ipc_frame fmt) +{ + return fmt == SOF_IPC_FRAME_S16_LE ? 2 : 4; +} + +static inline uint32_t frame_bytes(enum sof_ipc_frame fmt, uint32_t channels) +{ + return sample_bytes(fmt) * channels; +} + #endif /* __SOF_AUDIO_FORMAT_H__ */ From da670eeeb0dc855645fc664580c9e745162bdcfd Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 08:30:31 +0100 Subject: [PATCH 06/15] component: use frame_bytes and sample_bytes functions Uses newly added frame_bytes and sample_bytes methods in its own component based functions. Signed-off-by: Tomasz Lauda --- src/include/sof/audio/component.h | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index acd0bdbb3be8..af2249ddb276 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -17,6 +17,7 @@ #define __SOF_AUDIO_COMPONENT_H__ #include +#include #include #include #include @@ -611,17 +612,7 @@ static inline struct comp_dev *comp_get_previous(struct comp_dev *dev, int dir) */ static inline uint32_t comp_frame_bytes(struct comp_dev *dev) { - /* calculate period size based on params */ - switch (dev->params.frame_fmt) { - case SOF_IPC_FRAME_S16_LE: - return 2 * dev->params.channels; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - case SOF_IPC_FRAME_FLOAT: - return 4 * dev->params.channels; - default: - return 0; - } + return frame_bytes(dev->params.frame_fmt, dev->params.channels); } /** @@ -631,17 +622,7 @@ static inline uint32_t comp_frame_bytes(struct comp_dev *dev) */ static inline uint32_t comp_sample_bytes(struct comp_dev *dev) { - /* calculate period size based on params */ - switch (dev->params.frame_fmt) { - case SOF_IPC_FRAME_S16_LE: - return 2; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - case SOF_IPC_FRAME_FLOAT: - return 4; - default: - return 0; - } + return sample_bytes(dev->params.frame_fmt); } /** From 2529e785e84d2a5c4ea279ce7a76dde2eab0c9ee Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Fri, 25 Oct 2019 10:06:56 +0200 Subject: [PATCH 07/15] dai: volume: make pcm conversion in dai component Changes processing flow and moves pcm frame format conversion from volume to dai component. This way we'll no longer need to artificially add volume into the pipelines, where it's not really needed but frame format change is e.g. KPD topology. Dai is the perfect place for conversion, since it's format is pretty much predefined and comes from topology. Rest of the pipeline is configured from the host. Signed-off-by: Tomasz Lauda --- src/audio/dai.c | 68 +++--- src/audio/eq_fir/eq_fir.c | 4 +- src/audio/eq_iir/eq_iir.c | 4 +- src/audio/selector/selector.c | 4 +- src/audio/src/src.c | 4 +- src/audio/volume/volume.c | 46 +--- src/audio/volume/volume_generic.c | 113 ++++----- src/audio/volume/volume_hifi3.c | 144 +++++------ src/include/sof/audio/component.h | 26 -- src/include/sof/audio/volume.h | 10 +- test/cmocka/src/audio/volume/volume_process.c | 231 +++++++----------- 11 files changed, 263 insertions(+), 391 deletions(-) diff --git a/src/audio/dai.c b/src/audio/dai.c index 9629a7b53a79..7a43f061c657 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -57,6 +59,7 @@ struct dai_data { struct dai *dai; struct dma *dma; uint32_t frame_bytes; + enum sof_ipc_frame frame_fmt; int xrun; /* true if we are doing xrun recovery */ /* processing function */ @@ -78,6 +81,7 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_cb_data *next) struct comp_dev *dev = (struct comp_dev *)data; struct dai_data *dd = comp_get_drvdata(dev); uint32_t bytes = next->elem.size; + uint32_t samples = bytes / sample_bytes(dd->frame_fmt); struct comp_buffer *local_buffer; void *buffer_ptr; @@ -108,17 +112,18 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_cb_data *next) local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - dma_buffer_copy_to(local_buffer, bytes, dd->dma_buffer, bytes, - dd->process, bytes / comp_sample_bytes(dev)); + dma_buffer_copy_to(local_buffer, + samples * comp_sample_bytes(dev), + dd->dma_buffer, bytes, dd->process, samples); buffer_ptr = local_buffer->r_ptr; } else { local_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - dma_buffer_copy_from(dd->dma_buffer, bytes, local_buffer, bytes, - dd->process, - bytes / comp_sample_bytes(dev)); + dma_buffer_copy_from(dd->dma_buffer, bytes, local_buffer, + samples * comp_sample_bytes(dev), + dd->process, samples); buffer_ptr = local_buffer->w_ptr; } @@ -226,10 +231,14 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, uint32_t fifo; int err; + /* set processing function */ + dd->process = pcm_get_conversion_function(dev->params.frame_fmt, + dd->frame_fmt); + /* set up DMA configuration */ config->direction = DMA_DIR_MEM_TO_DEV; - config->src_width = comp_sample_bytes(dev); - config->dest_width = comp_sample_bytes(dev); + config->src_width = sample_bytes(dd->frame_fmt); + config->dest_width = sample_bytes(dd->frame_fmt); config->cyclic = 1; config->irq_disabled = pipeline_is_timer_driven(dev->pipeline); config->dest_dev = dai_get_handshake(dd->dai, dev->params.direction, @@ -275,6 +284,10 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, uint32_t fifo; int err; + /* set processing function */ + dd->process = pcm_get_conversion_function(dd->frame_fmt, + dev->params.frame_fmt); + /* set up DMA configuration */ config->direction = DMA_DIR_DEV_TO_MEM; config->cyclic = 1; @@ -293,8 +306,8 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, config->src_width = 4; config->dest_width = 4; } else { - config->src_width = comp_sample_bytes(dev); - config->dest_width = comp_sample_bytes(dev); + config->src_width = sample_bytes(dd->frame_fmt); + config->dest_width = sample_bytes(dd->frame_fmt); } trace_dai_with_ids(dev, "dai_capture_params() " @@ -329,8 +342,8 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, static int dai_params(struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct sof_ipc_comp_config *dconfig = COMP_GET_CONFIG(dev); + struct dai_data *dd = comp_get_drvdata(dev); uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; @@ -354,23 +367,6 @@ static int dai_params(struct comp_dev *dev) return -EINVAL; } - /* for DAI, we should configure its frame_fmt from topology */ - dev->params.frame_fmt = dconfig->frame_fmt; - - /* set processing function */ - if (dev->params.frame_fmt == SOF_IPC_FRAME_S16_LE) - dd->process = buffer_copy_s16; - else - dd->process = buffer_copy_s32; - - /* calculate period size based on config */ - dd->frame_bytes = comp_frame_bytes(dev); - if (!dd->frame_bytes) { - trace_dai_error_with_ids(dev, "dai_params() error: " - "comp_frame_bytes() returned 0."); - return -EINVAL; - } - err = dma_get_attribute(dd->dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); if (err < 0) { @@ -398,6 +394,12 @@ static int dai_params(struct comp_dev *dev) return -EINVAL; } + dd->frame_fmt = dconfig->frame_fmt; + + /* calculate frame size */ + dd->frame_bytes = frame_bytes(dd->frame_fmt, dev->params.channels); + + /* calculate period size */ period_bytes = dev->frames * dd->frame_bytes; if (!period_bytes) { trace_dai_error_with_ids(dev, "dai_params() error: invalid " @@ -622,6 +624,8 @@ static int dai_copy(struct comp_dev *dev) uint32_t avail_bytes = 0; uint32_t free_bytes = 0; uint32_t copy_bytes = 0; + uint32_t src_samples; + uint32_t sink_samples; int ret = 0; tracev_dai_with_ids(dev, "dai_copy()"); @@ -637,11 +641,17 @@ static int dai_copy(struct comp_dev *dev) if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) { local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - copy_bytes = MIN(local_buffer->avail, free_bytes); + src_samples = local_buffer->avail / comp_sample_bytes(dev); + sink_samples = free_bytes / sample_bytes(dd->frame_fmt); + copy_bytes = MIN(src_samples, sink_samples) * + sample_bytes(dd->frame_fmt); } else { local_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - copy_bytes = MIN(avail_bytes, local_buffer->free); + src_samples = avail_bytes / sample_bytes(dd->frame_fmt); + sink_samples = local_buffer->free / comp_sample_bytes(dev); + copy_bytes = MIN(src_samples, sink_samples) * + sample_bytes(dd->frame_fmt); } tracev_dai_with_ids(dev, "dai_copy(), copy_bytes = 0x%x", copy_bytes); diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index 4069f728d05a..efb3920cbe27 100644 --- a/src/audio/eq_fir/eq_fir.c +++ b/src/audio/eq_fir/eq_fir.c @@ -784,10 +784,10 @@ static int eq_fir_prepare(struct comp_dev *dev) struct comp_buffer, source_list); /* get source data format */ - cd->source_format = comp_frame_fmt(sourceb->source); + cd->source_format = sourceb->source->params.frame_fmt; /* get sink data format and period bytes */ - cd->sink_format = comp_frame_fmt(sinkb->sink); + cd->sink_format = sinkb->sink->params.frame_fmt; sink_period_bytes = comp_period_bytes(sinkb->sink, dev->frames); /* Rewrite params format for this component to match the host side. */ diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 904b094d1268..82d7f196d9e3 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -826,10 +826,10 @@ static int eq_iir_prepare(struct comp_dev *dev) struct comp_buffer, source_list); /* get source data format */ - cd->source_format = comp_frame_fmt(sourceb->source); + cd->source_format = sourceb->source->params.frame_fmt; /* get sink data format and period bytes */ - cd->sink_format = comp_frame_fmt(sinkb->sink); + cd->sink_format = sinkb->sink->params.frame_fmt; sink_period_bytes = comp_period_bytes(sinkb->sink, dev->frames); /* Rewrite params format for this component to match the host side. */ diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 20523846d7e4..9d890026cc0d 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -373,12 +373,12 @@ static int selector_prepare(struct comp_dev *dev) source_list); /* get source data format and period bytes */ - cd->source_format = comp_frame_fmt(sourceb->source); + cd->source_format = sourceb->source->params.frame_fmt; cd->source_period_bytes = comp_period_bytes(sourceb->source, dev->frames); /* get sink data format and period bytes */ - cd->sink_format = comp_frame_fmt(sinkb->sink); + cd->sink_format = sinkb->sink->params.frame_fmt; cd->sink_period_bytes = comp_period_bytes(sinkb->sink, dev->frames); /* There is an assumption that sink component will report out diff --git a/src/audio/src/src.c b/src/audio/src/src.c index 58f0c13fe30c..011982a92030 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -838,11 +838,11 @@ static int src_prepare(struct comp_dev *dev) struct comp_buffer, source_list); /* get source data format and period bytes */ - cd->source_format = comp_frame_fmt(sourceb->source); + cd->source_format = sourceb->source->params.frame_fmt; source_period_bytes = comp_period_bytes(sourceb->source, dev->frames); /* get sink data format and period bytes */ - cd->sink_format = comp_frame_fmt(sinkb->sink); + cd->sink_format = sinkb->sink->params.frame_fmt; sink_period_bytes = comp_period_bytes(sinkb->sink, dev->frames); /* Rewrite params format for this component to match the host side. */ diff --git a/src/audio/volume/volume.c b/src/audio/volume/volume.c index 3816b4de8cc7..a785c54cb9ab 100644 --- a/src/audio/volume/volume.c +++ b/src/audio/volume/volume.c @@ -598,9 +598,7 @@ static int volume_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sinkb; - struct comp_buffer *sourceb; struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev); - uint32_t source_period_bytes; uint32_t sink_period_bytes; int i; int ret; @@ -614,26 +612,13 @@ static int volume_prepare(struct comp_dev *dev) if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP; - /* volume components will only ever have 1 source and 1 sink buffer */ - sourceb = list_first_item(&dev->bsource_list, - struct comp_buffer, sink_list); + /* volume component will only ever have 1 sink buffer */ sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - /* get source data format and period bytes */ - cd->source_format = comp_frame_fmt(sourceb->source); - source_period_bytes = comp_period_bytes(sourceb->source, dev->frames); - - /* get sink data format and period bytes */ - cd->sink_format = comp_frame_fmt(sinkb->sink); + /* get sink period bytes */ sink_period_bytes = comp_period_bytes(sinkb->sink, dev->frames); - /* Rewrite params format for this component to match the host side. */ - if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) - dev->params.frame_fmt = cd->source_format; - else - dev->params.frame_fmt = cd->sink_format; - if (sinkb->size < config->periods_sink * sink_period_bytes) { trace_volume_error_with_ids(dev, "volume_prepare() error: " "sink buffer size is insufficient"); @@ -641,31 +626,12 @@ static int volume_prepare(struct comp_dev *dev) goto err; } - /* validate */ - if (!sink_period_bytes) { - trace_volume_error_with_ids(dev, "volume_prepare() error: " - "sink_period_bytes = 0, " - "dev->frames = %u", dev->frames); - ret = -EINVAL; - goto err; - } - if (!source_period_bytes) { - trace_volume_error_with_ids(dev, "volume_prepare() error: " - "source_period_bytes = 0, " - "dev->frames = %u", dev->frames); - ret = -EINVAL; - goto err; - } - cd->scale_vol = vol_get_processing_function(dev); if (!cd->scale_vol) { - trace_volume_error_with_ids(dev, "volume_prepare() error: " - "invalid cd->scale_vol, " - "cd->source_format = %u, " - "cd->sink_format = %u, " - "dev->params.channels = %u", - cd->source_format, cd->sink_format, - dev->params.channels); + trace_volume_error_with_ids + (dev, + "volume_prepare() error: invalid cd->scale_vol, dev->params.frame_fmt = %u, dev->params.channels = %u", + dev->params.frame_fmt, dev->params.channels); ret = -EINVAL; goto err; } diff --git a/src/audio/volume/volume_generic.c b/src/audio/volume/volume_generic.c index 24895ee459db..b6672fe22310 100644 --- a/src/audio/volume/volume_generic.c +++ b/src/audio/volume/volume_generic.c @@ -26,6 +26,10 @@ #include #include +#if 0 + +/* Currently unused, but may come in handy in the future */ + #if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE /** * \brief Volume gain function @@ -69,7 +73,7 @@ static void vol_s16_to_s24(struct comp_dev *dev, struct comp_buffer *sink, { struct comp_data *cd = comp_get_drvdata(dev); int16_t *src; - int32_t *dest; + int16_t *dest; int32_t i; uint32_t channel; uint32_t buff_frag = 0; @@ -102,7 +106,7 @@ static void vol_s24_to_s16(struct comp_dev *dev, struct comp_buffer *sink, { struct comp_data *cd = comp_get_drvdata(dev); int32_t *src; - int16_t *dest; + int32_t *dest; int32_t i; uint32_t channel; uint32_t buff_frag = 0; @@ -111,7 +115,7 @@ static void vol_s24_to_s16(struct comp_dev *dev, struct comp_buffer *sink, for (i = 0; i < frames; i++) { for (channel = 0; channel < dev->params.channels; channel++) { src = buffer_read_frag_s32(source, buff_frag); - dest = buffer_write_frag_s16(sink, buff_frag); + dest = buffer_write_frag_s32(sink, buff_frag); *dest = vol_mult_s24_to_s16(*src, cd->volume[channel]); @@ -204,32 +208,31 @@ static void vol_s32_to_s16(struct comp_dev *dev, struct comp_buffer *sink, } #endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S24LE +#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE /** - * \brief Volume s24 to s24 multiply function + * \brief Volume s32 to s24 multiply function * \param[in] x input sample. * \param[in] vol gain. * \return output sample. * - * Volume multiply for 24 bit input and 24 bit bit output. + * Volume multiply for 32 bit input and 24 bit bit output. */ -static inline int32_t vol_mult_s24_to_s24(int32_t x, int32_t vol) +static inline int32_t vol_mult_s32_to_s24(int32_t x, int32_t vol) { - return q_multsr_sat_32x32_24(sign_extend_s24(x), vol, - Q_SHIFT_BITS_64(23, 16, 23)); + return q_multsr_sat_32x32_24(x, vol, Q_SHIFT_BITS_64(31, 16, 23)); } /** - * \brief Volume processing from 24/32 bit to 24/32 bit. + * \brief Volume processing from 32 bit to 24/32 bit. * \param[in,out] dev Volume base component device. * \param[in,out] sink Destination buffer. * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. * - * Copy and scale volume from 24/32 bit source buffer + * Copy and scale volume from 32 bit source buffer * to 24/32 bit destination buffer. */ -static void vol_s24_to_s24(struct comp_dev *dev, struct comp_buffer *sink, +static void vol_s32_to_s24(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); @@ -239,45 +242,30 @@ static void vol_s24_to_s24(struct comp_dev *dev, struct comp_buffer *sink, uint32_t channel; uint32_t buff_frag = 0; - /* Samples are Q1.23 --> Q1.23 and volume is Q8.16 */ + /* Samples are Q1.31 --> Q1.23 and volume is Q8.16 */ for (i = 0; i < frames; i++) { for (channel = 0; channel < dev->params.channels; channel++) { src = buffer_read_frag_s32(source, buff_frag); dest = buffer_write_frag_s32(sink, buff_frag); - *dest = vol_mult_s24_to_s24(*src, cd->volume[channel]); + *dest = vol_mult_s32_to_s24(*src, cd->volume[channel]); buff_frag++; } } } -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE /** - * \brief Volume s32 to s24 multiply function - * \param[in] x input sample. - * \param[in] vol gain. - * \return output sample. - * - * Volume multiply for 32 bit input and 24 bit bit output. - */ -static inline int32_t vol_mult_s32_to_s24(int32_t x, int32_t vol) -{ - return q_multsr_sat_32x32_24(x, vol, Q_SHIFT_BITS_64(31, 16, 23)); -} - -/** - * \brief Volume processing from 32 bit to 24/32 bit. + * \brief Volume processing from 24/32 bit to 32 bit. * \param[in,out] dev Volume base component device. * \param[in,out] sink Destination buffer. * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. * - * Copy and scale volume from 32 bit source buffer - * to 24/32 bit destination buffer. + * Copy and scale volume from 24/32 bit source buffer + * to 32 bit destination buffer. */ -static void vol_s32_to_s24(struct comp_dev *dev, struct comp_buffer *sink, +static void vol_s24_to_s32(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); @@ -287,30 +275,51 @@ static void vol_s32_to_s24(struct comp_dev *dev, struct comp_buffer *sink, uint32_t channel; uint32_t buff_frag = 0; - /* Samples are Q1.31 --> Q1.23 and volume is Q8.16 */ + /* Samples are Q1.23 --> Q1.31 and volume is Q8.16 */ for (i = 0; i < frames; i++) { for (channel = 0; channel < dev->params.channels; channel++) { src = buffer_read_frag_s32(source, buff_frag); dest = buffer_write_frag_s32(sink, buff_frag); - *dest = vol_mult_s32_to_s24(*src, cd->volume[channel]); + *dest = q_multsr_sat_32x32 + (sign_extend_s24(*src), cd->volume[channel], + Q_SHIFT_BITS_64(23, 16, 31)); buff_frag++; } } } +#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ + +#endif + +#if CONFIG_FORMAT_S24LE /** - * \brief Volume processing from 24/32 bit to 32 bit. + * \brief Volume s24 to s24 multiply function + * \param[in] x input sample. + * \param[in] vol gain. + * \return output sample. + * + * Volume multiply for 24 bit input and 24 bit bit output. + */ +static inline int32_t vol_mult_s24_to_s24(int32_t x, int32_t vol) +{ + return q_multsr_sat_32x32_24(sign_extend_s24(x), vol, + Q_SHIFT_BITS_64(23, 16, 23)); +} + +/** + * \brief Volume processing from 24/32 bit to 24/32 bit. * \param[in,out] dev Volume base component device. * \param[in,out] sink Destination buffer. * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. * * Copy and scale volume from 24/32 bit source buffer - * to 32 bit destination buffer. + * to 24/32 bit destination buffer. */ -static void vol_s24_to_s32(struct comp_dev *dev, struct comp_buffer *sink, +static void vol_s24_to_s24(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); @@ -320,22 +329,19 @@ static void vol_s24_to_s32(struct comp_dev *dev, struct comp_buffer *sink, uint32_t channel; uint32_t buff_frag = 0; - /* Samples are Q1.23 --> Q1.31 and volume is Q8.16 */ + /* Samples are Q1.23 --> Q1.23 and volume is Q8.16 */ for (i = 0; i < frames; i++) { for (channel = 0; channel < dev->params.channels; channel++) { src = buffer_read_frag_s32(source, buff_frag); dest = buffer_write_frag_s32(sink, buff_frag); - *dest = q_multsr_sat_32x32 - (sign_extend_s24(*src), cd->volume[channel], - Q_SHIFT_BITS_64(23, 16, 31)); + *dest = vol_mult_s24_to_s24(*src, cd->volume[channel]); buff_frag++; } } } - -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ +#endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE /** @@ -411,28 +417,15 @@ static void vol_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink, } #endif /* CONFIG_FORMAT_S16LE */ - const struct comp_func_map func_map[] = { #if CONFIG_FORMAT_S16LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, vol_s16_to_s16}, + { SOF_IPC_FRAME_S16_LE, vol_s16_to_s16 }, #endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, vol_s16_to_s24}, - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, vol_s24_to_s16}, -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, vol_s16_to_s32}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, vol_s32_to_s16}, -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ #if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24}, + { SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24 }, #endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, vol_s32_to_s24}, - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, vol_s24_to_s32}, -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ #if CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, vol_s32_to_s32}, + { SOF_IPC_FRAME_S32_LE, vol_s32_to_s32 }, #endif /* CONFIG_FORMAT_S32LE */ }; diff --git a/src/audio/volume/volume_hifi3.c b/src/audio/volume/volume_hifi3.c index c7305a83e11e..e59d412b4b68 100644 --- a/src/audio/volume/volume_hifi3.c +++ b/src/audio/volume/volume_hifi3.c @@ -32,59 +32,9 @@ static void vol_setup_circular(struct comp_buffer *buffer) AE_SETCEND0(buffer->end_addr); } -#if CONFIG_FORMAT_S16LE -/** - * \brief HiFi3 enabled volume processing from 16 bit to 16 bit. - * \param[in,out] dev Volume base component device. - * \param[in,out] sink Destination buffer. - * \param[in,out] source Source buffer. - * \param[in] frames Number of frames to process. - */ -static void vol_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink, - struct comp_buffer *source, uint32_t frames) -{ - struct comp_data *cd = comp_get_drvdata(dev); - ae_f64 mult; - ae_f32x2 volume; - ae_f32x2 out_sample; - ae_f16x4 in_sample = AE_ZERO16(); - size_t channel; - int i; - ae_int16 *in = (ae_int16 *)source->r_ptr; - ae_int16 *out = (ae_int16 *)sink->w_ptr; - - /* Main processing loop */ - for (i = 0; i < frames; i++) { - /* Processing per channel */ - for (channel = 0; channel < dev->params.channels; channel++) { - /* Set source as circular buffer */ - vol_setup_circular(source); - - /* Load the input sample */ - AE_L16_XC(in_sample, in, sizeof(ae_int16)); - - /* Load volume */ - volume = (ae_f32x2)cd->volume[channel]; - - /* Multiply the input sample */ - mult = AE_MULF32X16_L0(volume, in_sample); - - /* Multiply of Q1.31 x Q1.15 gives Q1.47. Multiply of - * Q8.16 x Q1.15 gives Q8.32, so need to shift left - * by 31 to get Q1.63. Sample is Q1.31. - */ - out_sample = AE_ROUND32F64SSYM(AE_SLAI64S(mult, 31)); +#if 0 - /* Set sink as circular buffer */ - vol_setup_circular(sink); - - /* Round to Q1.15 and store the output sample */ - AE_S16_0_XC(AE_ROUND16X4F32SSYM(out_sample, out_sample), - out, sizeof(ae_int16)); - } - } -} -#endif /* CONFIG_FORMAT_S16LE */ +/* Currently unused, but may come in handy in the future */ #if CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) /** @@ -210,6 +160,8 @@ static void vol_sX_to_s16(struct comp_dev *dev, struct comp_buffer *sink, } #endif /* CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) */ +#endif + #if CONFIG_FORMAT_S24LE /** * \brief HiFi3 enabled volume processing from 24/32 bit to 24/32 or 32 bit. @@ -228,14 +180,10 @@ static void vol_s24_to_s24_s32(struct comp_dev *dev, struct comp_buffer *sink, ae_f32x2 volume; size_t channel; int i; - int shift = 0; + int shift = 8; ae_int32 *in = (ae_int32 *)source->r_ptr; ae_int32 *out = (ae_int32 *)sink->w_ptr; - /* Get value of shift left */ - if (cd->sink_format == SOF_IPC_FRAME_S24_4LE) - shift = 8; - /* Main processing loop */ for (i = 0; i < frames; i++) { /* Processing per channel */ @@ -296,10 +244,6 @@ static void vol_s32_to_s24_s32(struct comp_dev *dev, struct comp_buffer *sink, ae_int32 *in = (ae_int32 *)source->r_ptr; ae_int32 *out = (ae_int32 *)sink->w_ptr; - /* Get value of shift right */ - if (cd->sink_format == SOF_IPC_FRAME_S24_4LE) - shift = 8; - /* Main processing loop */ for (i = 0; i < frames; i++) { /* Processing per channel */ @@ -338,28 +282,70 @@ static void vol_s32_to_s24_s32(struct comp_dev *dev, struct comp_buffer *sink, } #endif /* CONFIG_FORMAT_S32LE */ -const struct comp_func_map func_map[] = { #if CONFIG_FORMAT_S16LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, vol_s16_to_s16}, +/** + * \brief HiFi3 enabled volume processing from 16 bit to 16 bit. + * \param[in,out] dev Volume base component device. + * \param[in,out] sink Destination buffer. + * \param[in,out] source Source buffer. + * \param[in] frames Number of frames to process. + */ +static void vol_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames) +{ + struct comp_data *cd = comp_get_drvdata(dev); + ae_f64 mult; + ae_f32x2 volume; + ae_f32x2 out_sample; + ae_f16x4 in_sample = AE_ZERO16(); + size_t channel; + int i; + ae_int16 *in = (ae_int16 *)source->r_ptr; + ae_int16 *out = (ae_int16 *)sink->w_ptr; + + /* Main processing loop */ + for (i = 0; i < frames; i++) { + /* Processing per channel */ + for (channel = 0; channel < dev->params.channels; channel++) { + /* Set source as circular buffer */ + vol_setup_circular(source); + + /* Load the input sample */ + AE_L16_XC(in_sample, in, sizeof(ae_int16)); + + /* Load volume */ + volume = (ae_f32x2)cd->volume[channel]; + + /* Multiply the input sample */ + mult = AE_MULF32X16_L0(volume, in_sample); + + /* Multiply of Q1.31 x Q1.15 gives Q1.47. Multiply of + * Q8.16 x Q1.15 gives Q8.32, so need to shift left + * by 31 to get Q1.63. Sample is Q1.31. + */ + out_sample = AE_ROUND32F64SSYM(AE_SLAI64S(mult, 31)); + + /* Set sink as circular buffer */ + vol_setup_circular(sink); + + /* Round to Q1.15 and store the output sample */ + AE_S16_0_XC(AE_ROUND16X4F32SSYM(out_sample, out_sample), + out, sizeof(ae_int16)); + } + } +} #endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, vol_s16_to_sX}, - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, vol_sX_to_s16}, -#endif /* CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) */ -#if CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, vol_s16_to_sX}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, vol_sX_to_s16}, -#endif /* CONFIG_FORMAT_S16LE && CONFIG_FORMAT_S32LE */ + +const struct comp_func_map func_map[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, vol_s16_to_s16 }, +#endif #if CONFIG_FORMAT_S24LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24_s32}, -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, vol_s24_to_s24_s32}, - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, vol_s32_to_s24_s32}, -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */ + { SOF_IPC_FRAME_S24_4LE, vol_s24_to_s24_s32 }, +#endif #if CONFIG_FORMAT_S32LE - {SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, vol_s32_to_s24_s32}, -#endif /* CONFIG_FORMAT_S32LE */ + { SOF_IPC_FRAME_S32_LE, vol_s32_to_s24_s32 }, +#endif }; const size_t func_count = ARRAY_SIZE(func_map); diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index af2249ddb276..6fd8ea630a39 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -645,32 +645,6 @@ static inline uint32_t comp_avail_frames(struct comp_buffer *source, return MIN(src_frames, sink_frames); } -/** - * Returns frame format based on component device's type. - * @param dev Component device. - * @return Frame format. - */ -static inline enum sof_ipc_frame comp_frame_fmt(struct comp_dev *dev) -{ - struct sof_ipc_comp_config *sconfig; - enum sof_ipc_frame frame_fmt; - - switch (dev->comp.type) { - case SOF_COMP_DAI: - case SOF_COMP_SG_DAI: - /* format comes from DAI/comp config */ - sconfig = COMP_GET_CONFIG(dev); - frame_fmt = sconfig->frame_fmt; - break; - default: - /* format comes from IPC params */ - frame_fmt = dev->params.frame_fmt; - break; - } - - return frame_fmt; -} - /** * Returns component state based on requested command. * @param cmd Request command. diff --git a/src/include/sof/audio/volume.h b/src/include/sof/audio/volume.h index 819bb46f28a6..684be0ac3d6c 100644 --- a/src/include/sof/audio/volume.h +++ b/src/include/sof/audio/volume.h @@ -110,8 +110,6 @@ struct comp_data { int32_t vol_min; /**< minimum volume */ int32_t vol_max; /**< maximum volume */ int32_t vol_ramp_range; /**< max ramp transition */ - enum sof_ipc_frame source_format; /**< source frame format */ - enum sof_ipc_frame sink_format; /**< sink frame format */ /**< volume processing function */ void (*scale_vol)(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames); @@ -119,8 +117,7 @@ struct comp_data { /** \brief Volume processing functions map. */ struct comp_func_map { - uint16_t source; /**< source frame format */ - uint16_t sink; /**< sink frame format */ + uint16_t frame_fmt; /**< frame format */ /**< volume processing function */ void (*func)(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames); @@ -141,14 +138,11 @@ typedef void (*scale_vol)(struct comp_dev *, struct comp_buffer *, */ static inline scale_vol vol_get_processing_function(struct comp_dev *dev) { - struct comp_data *cd = comp_get_drvdata(dev); int i; /* map the volume function for source and sink buffers */ for (i = 0; i < func_count; i++) { - if (cd->source_format != func_map[i].source) - continue; - if (cd->sink_format != func_map[i].sink) + if (dev->params.frame_fmt != func_map[i].frame_fmt) continue; return func_map[i].func; diff --git a/test/cmocka/src/audio/volume/volume_process.c b/test/cmocka/src/audio/volume/volume_process.c index bcdb49a5cb11..506bb5c4aab8 100644 --- a/test/cmocka/src/audio/volume/volume_process.c +++ b/test/cmocka/src/audio/volume/volume_process.c @@ -67,19 +67,17 @@ static int setup(void **state) /* allocate and set new device */ vol_state->dev = test_malloc(COMP_SIZE(struct sof_ipc_comp_volume)); vol_state->dev->params.channels = parameters->channels; + vol_state->dev->params.frame_fmt = parameters->sink_format; vol_state->dev->frames = parameters->frames; /* allocate and set new data */ cd = test_malloc(sizeof(*cd)); comp_set_drvdata(vol_state->dev, cd); - cd->source_format = parameters->source_format; - cd->sink_format = parameters->sink_format; cd->scale_vol = vol_get_processing_function(vol_state->dev); set_volume(cd->volume, parameters->volume, parameters->channels); /* allocate new sink buffer */ vol_state->sink = test_malloc(sizeof(*vol_state->sink)); - vol_state->dev->params.frame_fmt = parameters->sink_format; size = parameters->frames * comp_frame_bytes(vol_state->dev); vol_state->sink->w_ptr = test_calloc(parameters->buffer_size_ms, size); @@ -168,12 +166,28 @@ static void verify_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink, } #endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) -static void verify_s16_to_sX(struct comp_dev *dev, struct comp_buffer *sink, - struct comp_buffer *source) +#if CONFIG_FORMAT_S24LE +static void fill_source_s24(struct vol_test_state *vol_state) +{ + int64_t val; + int32_t *src = (int32_t *)vol_state->source->r_ptr; + int i; + int sign = 1; + + for (i = 0; i < vol_state->source->size / sizeof(int32_t); i++) { + val = (INT24_MIN + (i >> 1)) * sign; + val = (val > INT24_MAX) ? INT24_MAX : val; + src[i] = (int32_t)val; + sign = -sign; + } +} + +static void verify_s24_to_s24_s32(struct comp_dev *dev, + struct comp_buffer *sink, + struct comp_buffer *source) { struct comp_data *cd = comp_get_drvdata(dev); - const int16_t *src = (int16_t *)source->r_ptr; + const int32_t *src = (int32_t *)source->r_ptr; const int32_t *dst = (int32_t *)sink->w_ptr; double processed; int32_t dst_sample; @@ -182,17 +196,11 @@ static void verify_s16_to_sX(struct comp_dev *dev, struct comp_buffer *sink, int channel; int delta; int i; - int shift = 0; - - /* get shift value */ - if (cd->sink_format == SOF_IPC_FRAME_S24_4LE) - shift = 8; - else if (cd->sink_format == SOF_IPC_FRAME_S32_LE) - shift = 0; + int shift = 8; for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) { for (channel = 0; channel < channels; channel++) { - processed = 65536.0 * (double)src[i + channel] * + processed = (src[i + channel] << 8) * (double)cd->volume[channel] / (double)VOL_ZERO_DB + 0.5 * (1 << shift); if (processed > INT32_MAX) @@ -213,48 +221,10 @@ static void verify_s16_to_sX(struct comp_dev *dev, struct comp_buffer *sink, } } } +#endif /* CONFIG_FORMAT_S24LE */ -static void verify_sX_to_s16(struct comp_dev *dev, struct comp_buffer *sink, - struct comp_buffer *source) -{ - struct comp_data *cd = comp_get_drvdata(dev); - const int32_t *src = (int32_t *)source->r_ptr; - const int16_t *dst = (int16_t *)sink->w_ptr; - double processed; - int channels = dev->params.channels; - int channel; - int delta; - int i; - int shift = 0; - int16_t sample; - - /* get shift value */ - if (cd->source_format == SOF_IPC_FRAME_S24_4LE) - shift = 8; - - for (i = 0; i < sink->size / sizeof(uint16_t); i += channels) { - for (channel = 0; channel < channels; channel++) { - processed = (double)(src[i + channel] << shift) * - (double)cd->volume[channel] / - (double)VOL_ZERO_DB; - processed = processed / 65536.0 + 0.5; - if (processed > INT16_MAX) - processed = INT16_MAX; - - if (processed < INT16_MIN) - processed = INT16_MIN; - - sample = (int16_t)processed; - delta = dst[i + channel] - sample; - if (delta > 1 || delta < -1) - assert_int_equal(dst[i + channel], sample); - } - } -} -#endif /* CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) */ - -#if CONFIG_FORMAT_S24LE -static void fill_source_s24(struct vol_test_state *vol_state) +#if CONFIG_FORMAT_S32LE +static void fill_source_s32(struct vol_test_state *vol_state) { int64_t val; int32_t *src = (int32_t *)vol_state->source->r_ptr; @@ -262,21 +232,21 @@ static void fill_source_s24(struct vol_test_state *vol_state) int sign = 1; for (i = 0; i < vol_state->source->size / sizeof(int32_t); i++) { - val = (INT24_MIN + (i >> 1)) * sign; - val = (val > INT24_MAX) ? INT24_MAX : val; + val = (INT32_MIN + (i >> 1)) * sign; + val = (val > INT32_MAX) ? INT32_MAX : val; src[i] = (int32_t)val; sign = -sign; } } -static void verify_s24_to_s24_s32(struct comp_dev *dev, +static void verify_s32_to_s24_s32(struct comp_dev *dev, struct comp_buffer *sink, struct comp_buffer *source) { struct comp_data *cd = comp_get_drvdata(dev); + double processed; const int32_t *src = (int32_t *)source->r_ptr; const int32_t *dst = (int32_t *)sink->w_ptr; - double processed; int32_t dst_sample; int32_t sample; int channels = dev->params.channels; @@ -285,15 +255,11 @@ static void verify_s24_to_s24_s32(struct comp_dev *dev, int i; int shift = 0; - /* get shift value */ - if (cd->sink_format == SOF_IPC_FRAME_S24_4LE) - shift = 8; - for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) { for (channel = 0; channel < channels; channel++) { - processed = (src[i + channel] << 8) * - (double)cd->volume[channel] / - (double)VOL_ZERO_DB + 0.5 * (1 << shift); + processed = src[i + channel] * + (double)cd->volume[channel] / + (double)VOL_ZERO_DB + 0.5 * (1 << shift); if (processed > INT32_MAX) processed = INT32_MAX; @@ -312,32 +278,18 @@ static void verify_s24_to_s24_s32(struct comp_dev *dev, } } } -#endif /* CONFIG_FORMAT_S24LE */ +#endif /* CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S32LE -static void fill_source_s32(struct vol_test_state *vol_state) -{ - int64_t val; - int32_t *src = (int32_t *)vol_state->source->r_ptr; - int i; - int sign = 1; +#if 0 - for (i = 0; i < vol_state->source->size / sizeof(int32_t); i++) { - val = (INT32_MIN + (i >> 1)) * sign; - val = (val > INT32_MAX) ? INT32_MAX : val; - src[i] = (int32_t)val; - sign = -sign; - } -} - -static void verify_s32_to_s24_s32(struct comp_dev *dev, - struct comp_buffer *sink, - struct comp_buffer *source) +#if CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) +static void verify_s16_to_sX(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source) { struct comp_data *cd = comp_get_drvdata(dev); - double processed; - const int32_t *src = (int32_t *)source->r_ptr; + const int16_t *src = (int16_t *)source->r_ptr; const int32_t *dst = (int32_t *)sink->w_ptr; + double processed; int32_t dst_sample; int32_t sample; int channels = dev->params.channels; @@ -349,12 +301,14 @@ static void verify_s32_to_s24_s32(struct comp_dev *dev, /* get shift value */ if (cd->sink_format == SOF_IPC_FRAME_S24_4LE) shift = 8; + else if (cd->sink_format == SOF_IPC_FRAME_S32_LE) + shift = 0; for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) { for (channel = 0; channel < channels; channel++) { - processed = src[i + channel] * - (double)cd->volume[channel] / - (double)VOL_ZERO_DB + 0.5 * (1 << shift); + processed = 65536.0 * (double)src[i + channel] * + (double)cd->volume[channel] / + (double)VOL_ZERO_DB + 0.5 * (1 << shift); if (processed > INT32_MAX) processed = INT32_MAX; @@ -373,14 +327,54 @@ static void verify_s32_to_s24_s32(struct comp_dev *dev, } } } -#endif /* CONFIG_FORMAT_S32LE */ + +static void verify_sX_to_s16(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source) +{ + struct comp_data *cd = comp_get_drvdata(dev); + const int32_t *src = (int32_t *)source->r_ptr; + const int16_t *dst = (int16_t *)sink->w_ptr; + double processed; + int channels = dev->params.channels; + int channel; + int delta; + int i; + int shift = 0; + int16_t sample; + + /* get shift value */ + if (cd->source_format == SOF_IPC_FRAME_S24_4LE) + shift = 8; + + for (i = 0; i < sink->size / sizeof(uint16_t); i += channels) { + for (channel = 0; channel < channels; channel++) { + processed = (double)(src[i + channel] << shift) * + (double)cd->volume[channel] / + (double)VOL_ZERO_DB; + processed = processed / 65536.0 + 0.5; + if (processed > INT16_MAX) + processed = INT16_MAX; + + if (processed < INT16_MIN) + processed = INT16_MIN; + + sample = (int16_t)processed; + delta = dst[i + channel] - sample; + if (delta > 1 || delta < -1) + assert_int_equal(dst[i + channel], sample); + } + } +} +#endif /* CONFIG_FORMAT_S16LE && (CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE) */ + +#endif static void test_audio_vol(void **state) { struct vol_test_state *vol_state = *state; struct comp_data *cd = comp_get_drvdata(vol_state->dev); - switch (cd->source_format) { + switch (vol_state->dev->params.frame_fmt) { case SOF_IPC_FRAME_S16_LE: fill_source_s16(vol_state); break; @@ -418,59 +412,14 @@ static struct vol_test_parameters parameters[] = { SOF_IPC_FRAME_S24_4LE, verify_s24_to_s24_s32 }, /* 6 */ #endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S16LE - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX }, /* 7 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX }, /* 8 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX }, /* 9 */ - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 10 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 11 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 12 */ -#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S16LE */ - #if CONFIG_FORMAT_S32LE { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 13 */ + SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 7 */ { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 14 */ + SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 8 */ { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 15 */ + SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 }, /* 9 */ #endif /* CONFIG_FORMAT_S32LE */ - -#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S32_LE, verify_s16_to_sX }, /* 16 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S32_LE, verify_s16_to_sX }, /* 17 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S32_LE, verify_s16_to_sX }, /* 18 */ - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 19 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 20 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 }, /* 21 */ -#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE */ - -#if CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 }, /* 22 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 }, /* 23 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 }, /* 24 */ - { VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 }, /* 25 */ - { VOL_ZERO_DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 }, /* 26 */ - { VOL_MINUS_80DB, 2, 48, 1, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 }, /* 27 */ -#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S16LE */ }; int main(void) From e93454b521c74a1410bc430a48418066ef22416c Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 10:46:12 +0100 Subject: [PATCH 08/15] dai: remove unused code Removes unused code from dai_config. Frame bytes are always calculated from scratch in dai_params, so no point in keeping this dead code. Signed-off-by: Tomasz Lauda --- src/audio/dai.c | 100 ++---------------------------------------------- 1 file changed, 3 insertions(+), 97 deletions(-) diff --git a/src/audio/dai.c b/src/audio/dai.c index 7a43f061c657..92c4aad798f3 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -58,7 +58,6 @@ struct dai_data { struct dai *dai; struct dma *dma; - uint32_t frame_bytes; enum sof_ipc_frame frame_fmt; int xrun; /* true if we are doing xrun recovery */ @@ -344,6 +343,7 @@ static int dai_params(struct comp_dev *dev) { struct sof_ipc_comp_config *dconfig = COMP_GET_CONFIG(dev); struct dai_data *dd = comp_get_drvdata(dev); + uint32_t frame_size; uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; @@ -397,10 +397,10 @@ static int dai_params(struct comp_dev *dev) dd->frame_fmt = dconfig->frame_fmt; /* calculate frame size */ - dd->frame_bytes = frame_bytes(dd->frame_fmt, dev->params.channels); + frame_size = frame_bytes(dd->frame_fmt, dev->params.channels); /* calculate period size */ - period_bytes = dev->frames * dd->frame_bytes; + period_bytes = dev->frames * frame_size; if (!period_bytes) { trace_dai_error_with_ids(dev, "dai_params() error: invalid " "period_bytes."); @@ -688,7 +688,6 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) struct dai_data *dd = comp_get_drvdata(dev); struct sof_ipc_comp_dai *dai = (struct sof_ipc_comp_dai *)&dev->comp; int channel = 0; - int i; int handshake; trace_dai_with_ids(dev, "config comp %d pipe %d dai %d type %d", @@ -706,71 +705,21 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) case SOF_DAI_INTEL_SSP: /* set dma burst elems to slot number */ dd->config.burst_elems = config->ssp.tdm_slots; - - /* calc frame bytes */ - switch (config->ssp.sample_valid_bits) { - case 16: - dd->frame_bytes = 2 * config->ssp.tdm_slots; - break; - case 17 ... 32: - dd->frame_bytes = 4 * config->ssp.tdm_slots; - break; - default: - break; - } break; case SOF_DAI_INTEL_DMIC: - /* The frame bytes setting follows only FIFO A setting in - * this DMIC driver version. - */ trace_dai_with_ids(dev, "dai_config(), config->type = " "SOF_DAI_INTEL_DMIC"); /* We can use always the largest burst length. */ dd->config.burst_elems = 8; - /* Set frame size in bytes to match the configuration. The - * actual width of FIFO appears in IPC always in fifo_bits_a - * for both FIFOs A and B. - */ trace_dai_with_ids(dev, "dai_config(), " "config->dmic.fifo_bits = %u; " "config->dmic.num_pdm_active = %u;", config->dmic.fifo_bits, config->dmic.num_pdm_active); - dd->frame_bytes = 0; - for (i = 0; i < config->dmic.num_pdm_active; i++) { - trace_dai_with_ids(dev, "dai_config, " - "config->dmic.pdm[%u].enable_mic_a = %u; ", - config->dmic.pdm[i].id, - config->dmic.pdm[i].enable_mic_a); - trace_dai_with_ids(dev, "dai_config, " - "config->dmic.pdm[%u].enable_mic_b = %u; ", - config->dmic.pdm[i].id, - config->dmic.pdm[i].enable_mic_b); - dd->frame_bytes += (config->dmic.fifo_bits >> 3) * - (config->dmic.pdm[i].enable_mic_a + - config->dmic.pdm[i].enable_mic_b); - } - - /* Packing of mono streams from several PDM controllers is not - * supported. In such cases the stream needs to be two - * channels. - */ - if (config->dmic.num_pdm_active > 1) { - dd->frame_bytes = 2 * config->dmic.num_pdm_active * - (config->dmic.fifo_bits >> 3); - } - - trace_dai_with_ids(dev, "dai_config(), dd->frame_bytes = %u", - dd->frame_bytes); break; case SOF_DAI_INTEL_HDA: - /* set to some non-zero value to satisfy the condition below, - * it is recalculated in dai_params() later - * this is temp until dai/hda model is changed. - */ - dd->frame_bytes = 4; channel = config->hda.link_dma_ch; trace_dai_with_ids(dev, "dai_config(), channel = %d", channel); @@ -788,11 +737,6 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) } break; case SOF_DAI_INTEL_ALH: - /* set to some non-zero value to satisfy the condition below, - * it is recalculated in dai_params() later - */ - dd->frame_bytes = 4; - /* SDW HW FIFO always requires 32bit MSB aligned sample data for * all formats, such as 8/16/24/32 bits. */ @@ -811,18 +755,6 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) dd->stream_id); channel = EDMA_HS_GET_CHAN(handshake); - switch (dev->params.frame_fmt) { - case SOF_IPC_FRAME_S16_LE: - dd->frame_bytes = 2; - break; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - dd->frame_bytes = 4; - break; - default: - return -EINVAL; - } - dd->config.burst_elems = dd->dai->plat_data.fifo[dai->direction].depth; break; @@ -831,26 +763,6 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) dd->stream_id); channel = EDMA_HS_GET_CHAN(handshake); - switch (dev->params.frame_fmt) { -#if CONFIG_FORMAT_S16LE - case SOF_IPC_FRAME_S16_LE: - dd->frame_bytes = 2; - break; -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE - case SOF_IPC_FRAME_S24_4LE: - dd->frame_bytes = 4; - break; -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - case SOF_IPC_FRAME_S32_LE: - dd->frame_bytes = 4; - break; -#endif /* CONFIG_FORMAT_S32LE */ - default: - trace_dai_error_with_ids(dev, "dai_config() unsupported frame_fmt"); - } - dd->config.burst_elems = dd->dai->plat_data.fifo[dai->direction].depth; break; @@ -865,12 +777,6 @@ static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config) break; } - if (!dd->frame_bytes) { - trace_dai_error_with_ids(dev, "dai_config() error: " - "dd->frame_bytes == 0"); - return -EINVAL; - } - if (channel != DMA_CHAN_INVALID) { if (!dd->chan) /* get dma channel at first config only */ From dc09ee551cb02f3229a9a29ffbc3b68afaa490ac Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Tue, 29 Oct 2019 15:41:54 +0100 Subject: [PATCH 09/15] host: use copy functions from pcm_converter Uses pcm_converter to choose the right processing function. Signed-off-by: Tomasz Lauda --- src/audio/host.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/audio/host.c b/src/audio/host.c index a9dd343c477f..f297a975e196 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -587,10 +588,8 @@ static int host_params(struct comp_dev *dev) dma_set_cb(hd->chan, DMA_CB_TYPE_COPY, host_dma_cb, dev); /* set processing function */ - if (dev->params.frame_fmt == SOF_IPC_FRAME_S16_LE) - hd->process = buffer_copy_s16; - else - hd->process = buffer_copy_s32; + hd->process = pcm_get_conversion_function(dev->params.frame_fmt, + dev->params.frame_fmt); return 0; } From b12f90f107b5ef296e7cc566c65bcdc158779fca Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 28 Oct 2019 10:54:03 +0100 Subject: [PATCH 10/15] topology: kwd: remove volume from pipeline Removes volume component from KWD pipeline. It was only required to perform pcm conversion, but since DAI is now capable of doing that, usage of volume is deprecated. Signed-off-by: Tomasz Lauda --- tools/topology/sof/pipe-kfbm-capture.m4 | 36 +++---------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/tools/topology/sof/pipe-kfbm-capture.m4 b/tools/topology/sof/pipe-kfbm-capture.m4 index ebb9ff9b6df9..99853a306096 100644 --- a/tools/topology/sof/pipe-kfbm-capture.m4 +++ b/tools/topology/sof/pipe-kfbm-capture.m4 @@ -44,25 +44,6 @@ C_CONTROLBYTES(KPB, PIPELINE_ID, , KPB_priv) -# Volume Mixer control with max value of 80 -C_CONTROLMIXER(KWD Capture Volume, PIPELINE_ID, - CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256), - CONTROLMIXER_MAX(, 80), - false, - CONTROLMIXER_TLV(TLV 80 steps from -50dB to +30dB for 1dB, vtlv_m50s1), - Channel register and shift for Front Left/Right, - LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1))) - -# -# Volume configuration -# - -W_VENDORTUPLES(capture_pga_tokens, sof_volume_tokens, -LIST(` ', `SOF_TKN_VOLUME_RAMP_STEP_TYPE "0"' - ` ', `SOF_TKN_VOLUME_RAMP_STEP_MS "250"')) - -W_DATA(capture_pga_conf, capture_pga_tokens) - # # Components and Buffers # @@ -71,9 +52,6 @@ W_DATA(capture_pga_conf, capture_pga_tokens) # with 0 sink and 2 source periods W_PCM_CAPTURE(PCM_ID, Sound Trigger Capture, 0, 2, 2) -# "Volume" has x source and 2 sink periods -W_PGA(0, PIPELINE_FORMAT, 2, DAI_PERIODS, capture_pga_conf, LIST(` ', "PIPELINE_ID KWD Capture Volume")) - # "KPBM" has 2 source and 2 sink periods W_KPBM(0, PIPELINE_FORMAT, 2, 2, PIPELINE_ID, LIST(` ', "KPB")) @@ -85,25 +63,19 @@ W_BUFFER(0, COMP_BUFFER_SIZE(DAI_PERIODS, W_BUFFER(1, COMP_BUFFER_SIZE(2, COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), PLATFORM_HOST_MEM_CAP) -# Capture Buffers -W_BUFFER(2, COMP_BUFFER_SIZE(2, - COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), - PLATFORM_HOST_MEM_CAP) # # Pipeline Graph # -# host PCM_C <-- B2 <--+- KPBM 0 <-- B1 <-- volume 0 <-- B0 <-- source DAI0 +# host PCM_C <-- B1 <--+- KPBM 0 <-- B0 <-- source DAI0 # | # Others <-- P_GRAPH(pipe-kpbm-capture-PIPELINE_ID, PIPELINE_ID, LIST(` ', - `dapm(N_PCMC(PCM_ID), N_BUFFER(2))', - `dapm(N_BUFFER(2), N_KPBM(0, PIPELINE_ID))', - `dapm(N_KPBM(0, PIPELINE_ID), N_BUFFER(1))', - `dapm(N_BUFFER(1), N_PGA(0, PIPELINE_ID))', - `dapm(N_PGA(0, PIPELINE_ID), N_BUFFER(0))')) + `dapm(N_PCMC(PCM_ID), N_BUFFER(1))', + `dapm(N_BUFFER(1), N_KPBM(0, PIPELINE_ID))', + `dapm(N_KPBM(0, PIPELINE_ID), N_BUFFER(0))')) # # Pipeline Source and Sinks From c07e4799ab2b9f42c428ac630f1d3413417eb7df Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 20 Nov 2019 14:05:44 +0100 Subject: [PATCH 11/15] buffer: selective build by CONFIG_FORMAT Builds buffer_copy functions based on the selected formats in kconfig. Signed-off-by: Tomasz Lauda --- src/include/sof/audio/buffer.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 63e4c7ae4a52..ecca811c36e3 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -229,6 +230,8 @@ static inline void buffer_init(struct comp_buffer *buffer, uint32_t size, buffer_zero(buffer); } +#if CONFIG_FORMAT_S16LE + static inline void buffer_copy_s16(struct comp_buffer *source, struct comp_buffer *sink, uint32_t samples) { @@ -246,6 +249,10 @@ static inline void buffer_copy_s16(struct comp_buffer *source, } } +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE + static inline void buffer_copy_s32(struct comp_buffer *source, struct comp_buffer *sink, uint32_t samples) { @@ -263,4 +270,6 @@ static inline void buffer_copy_s32(struct comp_buffer *source, } } +#endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ + #endif /* __SOF_AUDIO_BUFFER_H__ */ From fbc102db05946c81cc744d04f4fc226c1ec5988d Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 20 Nov 2019 14:16:15 +0100 Subject: [PATCH 12/15] buffer: reimplement copy functions to faster versions Reimplements buffer_copy functions to use memcpy_s instead of fragment API. Based on my tests it gives 20% better performance than previous implementation. Note that memcpy_s function uses vec_memcpy when built using XCC. Signed-off-by: Tomasz Lauda --- src/include/sof/audio/buffer.h | 61 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index ecca811c36e3..68a8911bcb35 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -10,9 +10,12 @@ #include #include +#include #include #include #include +#include +#include #include #include #include @@ -230,23 +233,44 @@ static inline void buffer_init(struct comp_buffer *buffer, uint32_t size, buffer_zero(buffer); } +static inline void buffer_copy(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t bytes) +{ + void *src = source->r_ptr; + void *snk = sink->w_ptr; + uint32_t bytes_src; + uint32_t bytes_snk; + uint32_t bytes_copied; + int ret; + + while (bytes) { + bytes_src = (char *)source->end_addr - (char *)src; + bytes_snk = (char *)sink->end_addr - (char *)snk; + bytes_copied = MIN(bytes, MIN(bytes_src, bytes_snk)); + + ret = memcpy_s(snk, bytes_snk, src, bytes_copied); + assert(!ret); + + bytes -= bytes_copied; + src = (char *)src + bytes_copied; + snk = (char *)snk + bytes_copied; + + if (src >= source->end_addr) + src = (char *)source->addr + + ((char *)src - (char *)source->end_addr); + + if (snk >= sink->end_addr) + snk = (char *)sink->addr + + ((char *)snk - (char *)sink->end_addr); + } +} + #if CONFIG_FORMAT_S16LE static inline void buffer_copy_s16(struct comp_buffer *source, struct comp_buffer *sink, uint32_t samples) { - uint32_t buff_frag = 0; - int16_t *src; - int16_t *dst; - uint32_t i; - - for (i = 0; i < samples; i++) { - src = buffer_read_frag_s16(source, buff_frag); - dst = buffer_write_frag_s16(sink, buff_frag); - *dst = *src; - - buff_frag++; - } + buffer_copy(source, sink, samples * sizeof(int16_t)); } #endif /* CONFIG_FORMAT_S16LE */ @@ -256,18 +280,7 @@ static inline void buffer_copy_s16(struct comp_buffer *source, static inline void buffer_copy_s32(struct comp_buffer *source, struct comp_buffer *sink, uint32_t samples) { - uint32_t buff_frag = 0; - int32_t *src; - int32_t *dst; - uint32_t i; - - for (i = 0; i < samples; i++) { - src = buffer_read_frag_s32(source, buff_frag); - dst = buffer_write_frag_s32(sink, buff_frag); - *dst = *src; - - buff_frag++; - } + buffer_copy(source, sink, samples * sizeof(int32_t)); } #endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ From 623a2f1190e21ff5bf10aba47007cc4ba0f4ae55 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 20 Nov 2019 14:27:08 +0100 Subject: [PATCH 13/15] src: use buffer_copy function Uses buffer_copy function for bypass mode to avoid code duplication. Signed-off-by: Tomasz Lauda --- src/audio/src/src.c | 56 ++++----------------------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/src/audio/src/src.c b/src/audio/src/src.c index 011982a92030..0d3ac6ff0b25 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -439,34 +439,10 @@ static void src_copy_s32(struct comp_dev *dev, int *n_read, int *n_written) { struct comp_data *cd = comp_get_drvdata(dev); - int32_t *src = (int32_t *)source->r_ptr; - int32_t *snk = (int32_t *)sink->w_ptr; int frames = cd->param.blk_in; - int n; - int n_wrap_src; - int n_wrap_snk; - int n_wrap_min; - int n_copy; - int ret; - n = frames * dev->params.channels; - while (n > 0) { - n_wrap_src = (int32_t *)source->end_addr - src; - n_wrap_snk = (int32_t *)sink->end_addr - snk; - n_wrap_min = (n_wrap_src < n_wrap_snk) ? - n_wrap_src : n_wrap_snk; - n_copy = (n < n_wrap_min) ? n : n_wrap_min; - ret = memcpy_s(snk, n_copy * sizeof(int32_t), src, - n_copy * sizeof(int32_t)); - assert(!ret); - - /* Update and check both source and destination for wrap */ - n -= n_copy; - src += n_copy; - snk += n_copy; - src_inc_wrap(&src, source->end_addr, source->size); - src_inc_wrap(&snk, sink->end_addr, sink->size); - } + buffer_copy_s32(source, sink, frames * dev->params.channels); + *n_read = frames; *n_written = frames; } @@ -477,34 +453,10 @@ static void src_copy_s16(struct comp_dev *dev, int *n_read, int *n_written) { struct comp_data *cd = comp_get_drvdata(dev); - int16_t *src = (int16_t *)source->r_ptr; - int16_t *snk = (int16_t *)sink->w_ptr; int frames = cd->param.blk_in; - int n; - int n_wrap_src; - int n_wrap_snk; - int n_wrap_min; - int n_copy; - int ret; - n = frames * dev->params.channels; - while (n > 0) { - n_wrap_src = (int16_t *)source->end_addr - src; - n_wrap_snk = (int16_t *)sink->end_addr - snk; - n_wrap_min = (n_wrap_src < n_wrap_snk) ? - n_wrap_src : n_wrap_snk; - n_copy = (n < n_wrap_min) ? n : n_wrap_min; - ret = memcpy_s(snk, n_copy * sizeof(int16_t), src, - n_copy * sizeof(int16_t)); - assert(!ret); - - /* Update and check both source and destination for wrap */ - n -= n_copy; - src += n_copy; - snk += n_copy; - src_inc_wrap_s16(&src, source->end_addr, source->size); - src_inc_wrap_s16(&snk, sink->end_addr, sink->size); - } + buffer_copy_s16(source, sink, frames * dev->params.channels); + *n_read = frames; *n_written = frames; } From ec20241f532ffdf02cc9edbcbdf68d00bcde0925 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 20 Nov 2019 14:31:11 +0100 Subject: [PATCH 14/15] eq_fir: use buffer_copy function Uses buffer_copy function for bypass mode to avoid code duplication. Signed-off-by: Tomasz Lauda --- src/audio/eq_fir/eq_fir.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index efb3920cbe27..a8f5a5fd9f02 100644 --- a/src/audio/eq_fir/eq_fir.c +++ b/src/audio/eq_fir/eq_fir.c @@ -192,16 +192,7 @@ static void eq_fir_s16_passthrough(struct fir_state_32x16 fir[], struct comp_buffer *sink, int frames, int nch) { - int16_t *x; - int16_t *y; - int i; - int n = frames * nch; - - for (i = 0; i < n; i++) { - x = buffer_read_frag_s16(source, i); - y = buffer_write_frag_s16(sink, i); - *y = *x; - } + buffer_copy_s16(source, sink, frames * nch); } #endif /* CONFIG_FORMAT_S16LE */ @@ -211,16 +202,7 @@ static void eq_fir_s32_passthrough(struct fir_state_32x16 fir[], struct comp_buffer *sink, int frames, int nch) { - int32_t *x; - int32_t *y; - int i; - int n = frames * nch; - - for (i = 0; i < n; i++) { - x = buffer_read_frag_s32(source, i); - y = buffer_write_frag_s32(sink, i); - *y = *x; - } + buffer_copy_s32(source, sink, frames * nch); } #endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */ From e78627da3b70105331fcfd85e9272c5fcbdd8ec7 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 20 Nov 2019 14:34:36 +0100 Subject: [PATCH 15/15] eq_iir: use buffer_copy function Uses buffer_copy function for bypass mode to avoid code duplication. Signed-off-by: Tomasz Lauda --- src/audio/eq_iir/eq_iir.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 82d7f196d9e3..7153af7690c4 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -225,16 +225,7 @@ static void eq_iir_s16_pass(struct comp_dev *dev, struct comp_buffer *sink, uint32_t frames) { - int16_t *x; - int16_t *y; - int i; - int n = frames * dev->params.channels; - - for (i = 0; i < n; i++) { - x = buffer_read_frag_s16(source, i); - y = buffer_write_frag_s16(sink, i); - *y = *x; - } + buffer_copy_s16(source, sink, frames * dev->params.channels); } #endif /* CONFIG_FORMAT_S16LE */ @@ -244,16 +235,7 @@ static void eq_iir_s32_pass(struct comp_dev *dev, struct comp_buffer *sink, uint32_t frames) { - int32_t *x; - int32_t *y; - int i; - int n = frames * dev->params.channels; - - for (i = 0; i < n; i++) { - x = buffer_read_frag_s32(source, i); - y = buffer_write_frag_s32(sink, i); - *y = *x; - } + buffer_copy_s32(source, sink, frames * dev->params.channels); } #endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */