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/dai.c b/src/audio/dai.c index aa2aee015c12..92c4aad798f3 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -56,7 +58,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 +80,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,16 +111,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, dd->dma_buffer, dd->process, - bytes); + 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, local_buffer, dd->process, - bytes); + dma_buffer_copy_from(dd->dma_buffer, bytes, local_buffer, + samples * comp_sample_bytes(dev), + dd->process, samples); buffer_ptr = local_buffer->w_ptr; } @@ -225,10 +230,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, @@ -274,6 +283,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; @@ -292,8 +305,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() " @@ -328,8 +341,9 @@ 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 frame_size; uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; @@ -353,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) { @@ -397,7 +394,13 @@ static int dai_params(struct comp_dev *dev) return -EINVAL; } - period_bytes = dev->frames * dd->frame_bytes; + dd->frame_fmt = dconfig->frame_fmt; + + /* calculate frame size */ + frame_size = frame_bytes(dd->frame_fmt, dev->params.channels); + + /* calculate period size */ + period_bytes = dev->frames * frame_size; if (!period_bytes) { trace_dai_error_with_ids(dev, "dai_params() error: invalid " "period_bytes."); @@ -621,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()"); @@ -636,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); @@ -677,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", @@ -695,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); @@ -777,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. */ @@ -800,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; @@ -820,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; @@ -854,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 */ diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index 4069f728d05a..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 */ @@ -784,10 +766,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..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 */ @@ -826,10 +808,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/host.c b/src/audio/host.c index f4d0841e60df..f297a975e196 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -141,13 +142,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; @@ -586,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; } diff --git a/src/audio/pcm_converter/CMakeLists.txt b/src/audio/pcm_converter/CMakeLists.txt new file mode 100644 index 000000000000..8100bec72125 --- /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 pcm_converter_hifi3.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..23249e85a938 --- /dev/null +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -0,0 +1,159 @@ +// 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 + +#ifdef PCM_CONVERTER_GENERIC + +#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); + +#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/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..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; } @@ -838,11 +790,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/buffer.h b/src/include/sof/audio/buffer.h index 583628eb404a..68a8911bcb35 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -10,12 +10,16 @@ #include #include +#include #include #include #include +#include +#include #include #include #include +#include #include #include @@ -229,40 +233,56 @@ static inline void buffer_init(struct comp_buffer *buffer, uint32_t size, buffer_zero(buffer); } -static inline void buffer_copy_s16(struct comp_buffer *source, - struct comp_buffer *sink, uint32_t bytes) +static inline void buffer_copy(struct comp_buffer *source, + struct comp_buffer *sink, uint32_t bytes) { - 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++) { - src = buffer_read_frag_s16(source, buff_frag); - dst = buffer_write_frag_s16(sink, buff_frag); - *dst = *src; - - buff_frag++; + 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) +{ + buffer_copy(source, sink, samples * sizeof(int16_t)); +} + +#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 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++) { - 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 */ + #endif /* __SOF_AUDIO_BUFFER_H__ */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index acd0bdbb3be8..6fd8ea630a39 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); } /** @@ -664,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/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__ */ diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h new file mode 100644 index 000000000000..9e0e1bdd16dc --- /dev/null +++ b/src/include/sof/audio/pcm_converter.h @@ -0,0 +1,78 @@ +/* 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; + +#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 */ + 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__ */ 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/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))) 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); } 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) 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