This patch adds missing S24_4LE format. Input and output format need to be still the same. The filter coefficient set is configured in src_config.h per platform. BYT uses a small int24 set, other use standard int24 set. SRC wasnot unmuted by pipeline so in this version SRC initialized to unmuted state.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com --- src/audio/src.c | 35 ++++++++++---- src/audio/src_config.h | 47 +++++++++++++++++++ src/audio/src_core.c | 124 ++++++++++++++++++++++++++++++++++++++++++------- src/audio/src_core.h | 12 +---- 4 files changed, 183 insertions(+), 35 deletions(-) create mode 100644 src/audio/src_config.h
diff --git a/src/audio/src.c b/src/audio/src.c index 2ecf025..bc32f95 100644 --- a/src/audio/src.c +++ b/src/audio/src.c @@ -57,10 +57,11 @@ struct comp_data { struct polyphase_src src[PLATFORM_MAX_CHANNELS]; int32_t *delay_lines; - int scratch_length; uint32_t sink_rate; uint32_t source_rate; uint32_t period_bytes; /* sink period */ + int scratch_length; /* Buffer for stage1-stage2 */ + int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */ void (*src_func)(struct comp_dev *dev, struct comp_buffer *source, struct comp_buffer *sink, @@ -154,12 +155,12 @@ static void src_2s_s32_default(struct comp_dev *dev, s1.x_size = source->size; s1.x_inc = nch; s1.y_end_addr = &cd->delay_lines[cd->scratch_length]; - s1.y_size = STAGE_BUF_SIZE * sizeof(int32_t); + s1.y_size = cd->scratch_length * sizeof(int32_t); s1.y_inc = 1;
s2.times = n_times2; s2.x_end_addr = &cd->delay_lines[cd->scratch_length]; - s2.x_size = STAGE_BUF_SIZE * sizeof(int32_t); + s2.x_size = cd->scratch_length * sizeof(int32_t); s2.x_inc = 1; s2.y_end_addr = sink->end_addr; s2.y_size = sink->size; @@ -180,9 +181,14 @@ static void src_2s_s32_default(struct comp_dev *dev, for (i = 0; i < source_frames - blk_in + 1; i += blk_in) { /* Reset output to buffer start, read interleaved */ s1.y_wptr = cd->delay_lines; - src_polyphase_stage_cir(&s1); s2.x_rptr = cd->delay_lines; - src_polyphase_stage_cir(&s2); + if (cd->sign_extend_s24) { + src_polyphase_stage_cir_s24(&s1); + src_polyphase_stage_cir_s24(&s2); + } else { + src_polyphase_stage_cir(&s1); + src_polyphase_stage_cir(&s2); + }
n_read += blk_in; n_written += blk_out; @@ -198,7 +204,6 @@ static void src_1s_s32_default(struct comp_dev *dev, uint32_t source_frames, uint32_t sink_frames) { int i, j; - //int32_t *xp, *yp; struct polyphase_src *s;
struct comp_data *cd = comp_get_drvdata(dev); @@ -236,7 +241,10 @@ static void src_1s_s32_default(struct comp_dev *dev, s1.stage = s->stage1;
for (i = 0; i + blk_in - 1 < source_frames; i += blk_in) { - src_polyphase_stage_cir(&s1); + if (cd->sign_extend_s24) + src_polyphase_stage_cir_s24(&s1); + else + src_polyphase_stage_cir(&s1);
n_read += blk_in; n_written += blk_out; @@ -317,8 +325,15 @@ static int src_params(struct comp_dev *dev)
trace_src("par");
- /* SRC supports only S32_LE PCM format */ - if (config->frame_fmt != SOF_IPC_FRAME_S32_LE) { + /* SRC supports S24_4LE and S32_LE formats */ + switch (config->frame_fmt) { + case SOF_IPC_FRAME_S24_4LE: + cd->sign_extend_s24 = 1; + break; + case SOF_IPC_FRAME_S32_LE: + cd->sign_extend_s24 = 0; + break; + default: trace_src_error("sr0"); return -EINVAL; } @@ -423,6 +438,8 @@ static int src_params(struct comp_dev *dev) err = buffer_set_size(sink, q * dev->frames * dev->frame_bytes); if (err < 0) { trace_src_error("eSz"); + trace_value(sink->alloc_size); + trace_value(q * dev->frames * dev->frame_bytes); return err; }
diff --git a/src/audio/src_config.h b/src/audio/src_config.h new file mode 100644 index 0000000..f983723 --- /dev/null +++ b/src/audio/src_config.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * + */ + +#ifndef SRC_CONFIG_H +#define SRC_CONFIG_H + +#include <config.h> + +#if CONFIG_BAYTRAIL +#define SRC_SHORT 0 +#include <reef/audio/coefficients/src/src_small_int24_define.h> +#include <reef/audio/coefficients/src/src_small_int24_table.h> +#else +#define SHORT_SHORT 0 +#include <reef/audio/coefficients/src/src_std_int24_define.h> +#include <reef/audio/coefficients/src/src_std_int24_table.h> +#endif + +#endif diff --git a/src/audio/src_core.c b/src/audio/src_core.c index a9331a0..342e8a7 100644 --- a/src/audio/src_core.c +++ b/src/audio/src_core.c @@ -43,13 +43,7 @@ #include <reef/audio/format.h> #include <reef/math/numbers.h> #include "src_core.h" - -/* Include conversion tables */ -#if SRC_SHORT == 1 -#include <reef/audio/coefficients/src/src_int16_table.h> -#else -#include <reef/audio/coefficients/src/src_int24_table.h> -#endif +#include "src_config.h"
/* TODO: These should be defined somewhere else. */ #define SOF_RATES_LENGTH 15 @@ -256,7 +250,7 @@ static int init_stages( void src_polyphase_reset(struct polyphase_src *src) {
- src->mute = 1; + src->mute = 0; src->number_of_stages = 0; src->blk_in = 0; src->blk_out = 0; @@ -401,15 +395,8 @@ static inline int32_t fir_filter(
void src_polyphase_stage_cir(struct src_stage_prm *s) { - int n; - int m; - int f; - int c; - int r; + int n, m, f, c, r, n_wrap_fir, n_wrap_buf, n_wrap_min; int32_t z; - int n_wrap_fir; - int n_wrap_buf; - int n_wrap_min;
for (n = 0; n < s->times; n++) { /* Input data */ @@ -510,6 +497,111 @@ void src_polyphase_stage_cir(struct src_stage_prm *s) } }
+void src_polyphase_stage_cir_s24(struct src_stage_prm *s) +{ + int n, m, f, c, r, n_wrap_fir, n_wrap_buf, n_wrap_min; + int32_t se, z; + + for (n = 0; n < s->times; n++) { + /* Input data */ + m = s->x_inc * s->stage->blk_in; + while (m > 0) { + n_wrap_fir = + (s->state->fir_delay_size - s->state->fir_wi) + * s->x_inc; + n_wrap_buf = s->x_end_addr - s->x_rptr; + n_wrap_min = (n_wrap_fir < n_wrap_buf) + ? n_wrap_fir : n_wrap_buf; + if (m < n_wrap_min) { + /* No circular wrap need */ + while (m > 0) { + se = *s->x_rptr << 8; + s->state->fir_delay[s->state->fir_wi++] + = se >> 8; + s->x_rptr += s->x_inc; + m -= s->x_inc; + } + } else { + /* Wrap in n_wrap_min/x_inc samples */ + while (n_wrap_min > 0) { + se = *s->x_rptr << 8; + s->state->fir_delay[s->state->fir_wi++] + = se >> 8; + s->x_rptr += s->x_inc; + n_wrap_min -= s->x_inc; + m -= s->x_inc; + } + /* Check both */ + if (s->x_rptr >= s->x_end_addr) + s->x_rptr = (int32_t *) + ((size_t) s->x_rptr - s->x_size); + if (s->state->fir_wi + == s->state->fir_delay_size) + s->state->fir_wi = 0; + } + } + + /* Filter */ + c = 0; + r = s->state->fir_wi - s->stage->blk_in + - (s->stage->num_of_subfilters - 1) * s->stage->idm; + if (r < 0) + r += s->state->fir_delay_size; + + s->state->out_wi = s->state->out_ri; + for (f = 0; f < s->stage->num_of_subfilters; f++) { + s->state->fir_ri = r; + z = fir_filter(s->state, s->stage->coefs, &c, + s->stage->subfilter_length, s->stage->shift); + r += s->stage->idm; + if (r > s->state->fir_delay_size - 1) + r -= s->state->fir_delay_size; + + s->state->out_delay[s->state->out_wi] = z; + s->state->out_wi += s->stage->odm; + if (s->state->out_wi > s->state->out_delay_size - 1) + s->state->out_wi -= s->state->out_delay_size; + } + + /* Output */ + m = s->y_inc * s->stage->num_of_subfilters; + while (m > 0) { + n_wrap_fir = + (s->state->out_delay_size - s->state->out_ri) + * s->y_inc; + n_wrap_buf = s->y_end_addr - s->y_wptr; + n_wrap_min = (n_wrap_fir < n_wrap_buf) + ? n_wrap_fir : n_wrap_buf; + if (m < n_wrap_min) { + /* No circular wrap need */ + while (m > 0) { + *s->y_wptr = s->state->out_delay[ + s->state->out_ri++]; + s->y_wptr += s->y_inc; + m -= s->y_inc; + } + } else { + /* Wrap in n_wrap_min/y_inc samples */ + while (n_wrap_min > 0) { + *s->y_wptr = s->state->out_delay[ + s->state->out_ri++]; + s->y_wptr += s->y_inc; + n_wrap_min -= s->y_inc; + m -= s->y_inc; + } + /* Check both */ + if (s->y_wptr >= s->y_end_addr) + s->y_wptr = + (int32_t *) + ((size_t) s->y_wptr - s->y_size); + + if (s->state->out_ri + == s->state->out_delay_size) + s->state->out_ri = 0; + } + } + } +}
#ifdef MODULE_TEST
diff --git a/src/audio/src_core.h b/src/audio/src_core.h index ae1223a..5977421 100644 --- a/src/audio/src_core.h +++ b/src/audio/src_core.h @@ -32,18 +32,8 @@ #ifndef SRC_CORE_H #define SRC_CORE_H
-/* TODO: This should be made per platform configurable */ -#define SRC_SHORT 1 - #define MAX(a, b) (((a) > (b)) ? (a) : (b))
-/* Include SRC min/max constants etc. */ -#if SRC_SHORT == 1 -#include <reef/audio/coefficients/src/src_int16_define.h> -#else -#include <reef/audio/coefficients/src/src_int24_define.h> -#endif - struct src_alloc { int fir_s1; int fir_s2; @@ -151,6 +141,8 @@ int src_polyphase(struct polyphase_src *src, int32_t x[], int32_t y[],
void src_polyphase_stage_cir(struct src_stage_prm *s);
+void src_polyphase_stage_cir_s24(struct src_stage_prm *s); + int src_buffer_lengths(struct src_alloc *a, int fs_in, int fs_out, int nch, int max_frames, int max_frames_is_for_source);