EQ FIR: Updates for component initialization and cache functions

This patch delays FIR initialization until prepare() to avoid unnecessary
initialization for not final channels amount when in idle. It avoids
a number of malloc and free operations. The FIR delaylines allocation
is brought easier visible via addition for FIR delay address and size
pointers to component data. There's no more need to look it up from inside
of FIR channel instances.

The FIR channel bypass feature is now supported with assign of response
number -1 into channel similarly as in IIR. The same change is done
for generic C and optimized FIR cores.

The cache invalidate functions are cleaned up to perform the operation
into single allocated buffer instead of multiple.

FIR reconfigure during playback is prevented due to still incomplete
implementation for runtime changes.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
This commit is contained in:
Seppo Ingalsuo 2018-09-27 13:56:04 +03:00
parent 299ccbce58
commit 7a0d5f6246
9 changed files with 197 additions and 226 deletions

View File

@ -61,6 +61,8 @@ struct comp_data {
struct fir_state_32x16 fir[PLATFORM_MAX_CHANNELS];
struct sof_eq_fir_config *config;
uint32_t period_bytes;
int32_t *fir_delay;
size_t fir_delay_size;
void (*eq_fir_func)(struct fir_state_32x16 fir[],
struct comp_buffer *source,
struct comp_buffer *sink,
@ -89,60 +91,38 @@ static void eq_fir_passthrough(struct fir_state_32x16 fir[],
static void eq_fir_free_parameters(struct sof_eq_fir_config **config)
{
if (*config)
rfree(*config);
rfree(*config);
*config = NULL;
}
static void eq_fir_clear_delaylines(struct fir_state_32x16 fir[])
static void eq_fir_free_delaylines(struct comp_data *cd)
{
struct fir_state_32x16 *fir = cd->fir;
int i = 0;
/* 1st active EQ data is at beginning of the single allocated buffer */
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
if (fir[i].delay) {
memset(fir[i].delay, 0,
fir[i].length * sizeof(int32_t));
}
}
}
static void eq_fir_free_delaylines(struct fir_state_32x16 fir[])
{
int i = 0;
int32_t *data = NULL;
/* 1st active EQ data is at beginning of the single allocated buffer */
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
if (fir[i].delay && !data)
data = (int32_t *)fir[i].delay;
/* Set all to NULL to avoid duplicated free later */
/* Free the common buffer for all EQs and point then
* each FIR channel delay line to NULL.
*/
rfree(cd->fir_delay);
cd->fir_delay_size = 0;
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
fir[i].delay = NULL;
}
if (data) {
trace_eq("fr1");
rfree(data);
trace_eq("fr2");
}
}
static int eq_fir_setup(struct fir_state_32x16 fir[],
struct sof_eq_fir_config *config, int nch)
static int eq_fir_setup(struct comp_data *cd, int nch)
{
struct fir_state_32x16 *fir = cd->fir;
struct sof_eq_fir_config *config = cd->config;
struct sof_eq_fir_coef_data *lookup[SOF_EQ_FIR_MAX_RESPONSES];
struct sof_eq_fir_coef_data *eq;
int32_t *fir_delay;
int16_t *coef_data;
int16_t *assign_response;
int resp;
int i;
int j;
int idx;
int length;
int resp;
int32_t *fir_data;
int16_t *coef_data, *assign_response;
int response_index[PLATFORM_MAX_CHANNELS];
int length_sum = 0;
size_t s;
size_t size_sum = 0;
trace_eq("fse");
trace_value(config->channels_in_config);
@ -153,94 +133,105 @@ static int eq_fir_setup(struct fir_state_32x16 fir[],
return -EINVAL;
}
/* Sanity checks */
if (nch > PLATFORM_MAX_CHANNELS ||
config->channels_in_config > PLATFORM_MAX_CHANNELS ||
!config->channels_in_config) {
trace_eq_error("ech");
return -EINVAL;
}
if (config->number_of_responses > SOF_EQ_FIR_MAX_RESPONSES) {
trace_eq_error("enr");
return -EINVAL;
}
/* Collect index of respose start positions in all_coefficients[] */
j = 0;
assign_response = &config->data[0];
coef_data = &config->data[config->channels_in_config];
trace_eq("idx");
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
for (i = 0; i < SOF_EQ_FIR_MAX_RESPONSES; i++) {
if (i < config->number_of_responses) {
response_index[i] = j;
trace_value(j);
eq = (struct sof_eq_fir_coef_data *)&coef_data[j];
lookup[i] = eq;
j += SOF_EQ_FIR_COEF_NHEADER + coef_data[j];
} else {
response_index[i] = 0;
lookup[i] = NULL;
}
}
/* Free existing FIR channels data if it was allocated */
eq_fir_free_delaylines(fir);
/* Initialize 1st phase */
trace_eq("asr");
for (i = 0; i < nch; i++) {
/* If the configuration blob contains less channels for
* response assign to channels than the current channels count
* use the first channel response to remaining channels. E.g.
* a blob that contains just a mono EQ can be used for stereo
* stream by using the same response for all channels.
/* Check for not reading past blob response to channel assign
* map. If the blob has smaller channel map then apply for
* additional channels the response that was used for the first
* channel. This allows to use mono blobs to setup multi
* channel equalization without stopping to an error.
*/
if (i < config->channels_in_config)
resp = assign_response[i];
else
resp = assign_response[0];
trace_value(resp);
if (resp >= config->number_of_responses || resp < 0) {
trace_eq_error("eas");
trace_value(resp);
return -EINVAL;
if (resp < 0) {
/* Initialize EQ channel to bypass and continue with
* next channel response.
*/
fir_reset(&fir[i]);
continue;
}
/* Initialize EQ coefficients. Each channel EQ returns the
* number of samples it needs to store into the delay line. The
* sum is used to allocate storate for all EQs.
*/
idx = response_index[resp];
length = fir_init_coef(&fir[i], &coef_data[idx]);
if (length > 0) {
length_sum += length;
} else {
trace_eq_error("ecl");
trace_value(length);
if (resp >= config->number_of_responses)
return -EINVAL;
/* Initialize EQ coefficients. */
eq = lookup[resp];
s = fir_init_coef(&fir[i], eq);
if (s > 0)
size_sum += s;
else
return -EINVAL;
}
}
trace_eq("all");
/* If all channels were set to bypass there's no need to
* allocate delay. Just return with success.
*/
cd->fir_delay = NULL;
cd->fir_delay_size = size_sum;
if (!size_sum)
return 0;
/* Allocate all FIR channels data in a big chunk and clear it */
fir_data = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM,
length_sum * sizeof(int32_t));
if (!fir_data)
cd->fir_delay = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, size_sum);
if (!cd->fir_delay)
return -ENOMEM;
/* Initialize 2nd phase to set EQ delay lines pointers */
trace_eq("ini");
fir_delay = cd->fir_delay;
for (i = 0; i < nch; i++) {
resp = assign_response[i];
if (resp >= 0) {
trace_value(fir->length);
fir_init_delay(&fir[i], &fir_data);
fir_init_delay(&fir[i], &fir_delay);
}
}
return 0;
}
static int eq_fir_switch_response(struct fir_state_32x16 fir[],
struct sof_eq_fir_config *config,
uint32_t ch, int32_t response)
static int eq_fir_switch_store(struct fir_state_32x16 fir[],
struct sof_eq_fir_config *config,
uint32_t ch, int32_t response)
{
int ret;
/* Copy assign response from update and re-initialize EQ */
if (!config || ch >= PLATFORM_MAX_CHANNELS)
/* Copy assign response from update. The EQ is initialized later
* when all channels have been updated.
*/
if (!config || ch >= config->channels_in_config)
return -EINVAL;
config->data[ch] = response;
ret = eq_fir_setup(fir, config, PLATFORM_MAX_CHANNELS);
return ret;
return 0;
}
/*
@ -309,7 +300,7 @@ static void eq_fir_free(struct comp_dev *dev)
trace_eq("fre");
eq_fir_free_delaylines(cd->fir);
eq_fir_free_delaylines(cd);
eq_fir_free_parameters(&cd->config);
rfree(cd);
@ -373,7 +364,7 @@ static int fir_cmd_get_data(struct comp_dev *dev,
}
break;
default:
trace_eq_error("egt");
trace_eq_error("egd");
ret = -EINVAL;
break;
}
@ -390,8 +381,6 @@ static int fir_cmd_set_data(struct comp_dev *dev,
int i;
int ret = 0;
/* TODO: determine if data is DMAed or appended to cdata */
/* Check version from ABI header */
if (cdata->data->comp_abi != SOF_EQ_FIR_ABI_VERSION) {
trace_eq_error("eab");
@ -407,10 +396,10 @@ static int fir_cmd_set_data(struct comp_dev *dev,
for (i = 0; i < (int)cdata->num_elems; i++) {
tracev_value(compv[i].index);
tracev_value(compv[i].svalue);
ret = eq_fir_switch_response(cd->fir,
cd->config,
compv[i].index,
compv[i].svalue);
ret = eq_fir_switch_store(cd->fir,
cd->config,
compv[i].index,
compv[i].svalue);
if (ret < 0) {
trace_eq_error("esw");
return -EINVAL;
@ -425,6 +414,17 @@ static int fir_cmd_set_data(struct comp_dev *dev,
case SOF_CTRL_CMD_BINARY:
trace_eq("sbi");
if (dev->state != COMP_STATE_READY) {
/* It is a valid request but currently this is not
* supported during playback/capture. The driver will
* re-send data in next resume when idle and the new
* EQ configuration will be used when playback/capture
* starts.
*/
trace_eq_error("esr");
return -EBUSY;
}
/* Check and free old config */
eq_fir_free_parameters(&cd->config);
@ -437,40 +437,21 @@ static int fir_cmd_set_data(struct comp_dev *dev,
cfg = (struct sof_eq_fir_config *)cdata->data->data;
bs = cfg->size;
trace_value(bs);
if (bs > SOF_EQ_FIR_MAX_SIZE || bs < 1)
if (bs > SOF_EQ_FIR_MAX_SIZE || bs == 0)
return -EINVAL;
/* Allocate buffer for copy of the blob. */
cd->config = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, bs);
if (!cd->config)
return -EINVAL;
memcpy(cd->config, cdata->data->data, bs);
ret = eq_fir_setup(cd->fir, cd->config, PLATFORM_MAX_CHANNELS);
if (ret == 0) {
#if 1
#if FIR_GENERIC
cd->eq_fir_func = eq_fir_s32;
cd->eq_fir_func_odd = eq_fir_s32;
#endif
#if FIR_HIFIEP
cd->eq_fir_func = eq_fir_2x_s32_hifiep;
cd->eq_fir_func_odd = eq_fir_s32_hifiep;
#endif
#if FIR_HIFI3
cd->eq_fir_func = eq_fir_2x_s32_hifi3;
cd->eq_fir_func_odd = eq_fir_s32_hifi3;
#endif
#endif
trace_eq("fok");
} else {
cd->eq_fir_func = eq_fir_passthrough;
cd->eq_fir_func_odd = eq_fir_passthrough;
trace_eq_error("ept");
return -EINVAL;
}
/* Just copy the configuration. The EQ will be initialized in
* prepare().
*/
memcpy(cd->config, cfg, bs);
break;
default:
trace_eq_error("ecm");
trace_eq_error("esd");
ret = -EINVAL;
break;
}
@ -493,6 +474,15 @@ static int eq_fir_cmd(struct comp_dev *dev, int cmd, void *data)
case COMP_CMD_GET_DATA:
ret = fir_cmd_get_data(dev, cdata);
break;
case COMP_CMD_SET_VALUE:
trace_eq("isv");
break;
case COMP_CMD_GET_VALUE:
trace_eq("igv");
break;
default:
trace_eq_error("ecm");
ret = -EINVAL;
}
return ret;
@ -559,7 +549,7 @@ static int eq_fir_prepare(struct comp_dev *dev)
/* Initialize EQ */
cd->eq_fir_func = eq_fir_passthrough;
if (cd->config) {
ret = eq_fir_setup(cd->fir, cd->config, dev->params.channels);
ret = eq_fir_setup(cd, dev->params.channels);
if (ret < 0) {
comp_set_state(dev, COMP_TRIGGER_RESET);
return ret;
@ -586,11 +576,17 @@ static int eq_fir_prepare(struct comp_dev *dev)
static int eq_fir_reset(struct comp_dev *dev)
{
int i;
struct comp_data *cd = comp_get_drvdata(dev);
trace_eq("res");
eq_fir_clear_delaylines(cd->fir);
eq_fir_free_delaylines(cd);
cd->eq_fir_func = eq_fir_passthrough;
cd->eq_fir_func_odd = eq_fir_passthrough;
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
fir_reset(&cd->fir[i]);
comp_set_state(dev, COMP_TRIGGER_RESET);
return 0;
@ -599,24 +595,18 @@ static int eq_fir_reset(struct comp_dev *dev)
static void eq_fir_cache(struct comp_dev *dev, int cmd)
{
struct comp_data *cd;
int i;
switch (cmd) {
case COMP_CACHE_WRITEBACK_INV:
trace_eq("wtb");
cd = comp_get_drvdata(dev);
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
if (cd->fir[i].delay)
dcache_writeback_invalidate_region
(cd->fir[i].delay,
cd->fir[i].length * sizeof(int32_t));
}
if (cd->config)
dcache_writeback_invalidate_region(cd->config,
cd->config->size);
if (cd->fir_delay)
dcache_writeback_invalidate_region(cd->fir_delay,
cd->fir_delay_size);
dcache_writeback_invalidate_region(cd, sizeof(*cd));
dcache_writeback_invalidate_region(dev, sizeof(*dev));
@ -627,19 +617,19 @@ static void eq_fir_cache(struct comp_dev *dev, int cmd)
dcache_invalidate_region(dev, sizeof(*dev));
/* Note: The component data need to be retrieved after
* the dev data has been invalidated.
*/
cd = comp_get_drvdata(dev);
dcache_invalidate_region(cd, sizeof(*cd));
if (cd->fir_delay)
dcache_invalidate_region(cd->fir_delay,
cd->fir_delay_size);
if (cd->config)
dcache_invalidate_region(cd->config,
cd->config->size);
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
if (cd->fir[i].delay)
dcache_invalidate_region
(cd->fir[i].delay,
cd->fir[i].length * sizeof(int32_t));
}
break;
}
}

View File

@ -50,7 +50,6 @@ void fir_reset(struct fir_state_32x16 *fir)
{
fir->rwi = 0;
fir->length = 0;
fir->delay_size = 0;
fir->out_shift = 0;
fir->coef = NULL;
/* There may need to know the beginning of dynamic allocation after
@ -58,17 +57,14 @@ void fir_reset(struct fir_state_32x16 *fir)
*/
}
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config)
{
struct sof_eq_fir_coef_data *setup;
setup = (struct sof_eq_fir_coef_data *)config;
fir->rwi = 0;
fir->length = (int)setup->length;
fir->out_shift = (int)setup->out_shift;
fir->coef = &setup->coef[0];
fir->length = (int)config->length;
fir->out_shift = (int)config->out_shift;
fir->coef = &config->coef[0];
fir->delay = NULL;
fir->delay_size = 0;
/* Check for sane FIR length. The length is constrained to be a
* multiple of 4 for optimized code.
@ -76,14 +72,13 @@ int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
if (fir->length > SOF_EQ_FIR_MAX_LENGTH || fir->length < 1)
return -EINVAL;
return fir->length;
return fir->length * sizeof(int32_t);
}
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data)
{
fir->delay = *data;
fir->delay_size = fir->length;
*data += fir->delay_size; /* Point to next delay line start */
*data += fir->length; /* Point to next delay line start */
}
void eq_fir_s32(struct fir_state_32x16 fir[], struct comp_buffer *source,

View File

@ -42,7 +42,6 @@
struct fir_state_32x16 {
int rwi; /* Circular read and write index */
int length; /* Number of FIR taps */
int delay_size; /* Actual delay lentgh, must be >= length */
int out_shift; /* Amount of right shifts at output */
int16_t *coef; /* Pointer to FIR coefficients */
int32_t *delay; /* Pointer to FIR delay line */
@ -50,7 +49,8 @@ struct fir_state_32x16 {
void fir_reset(struct fir_state_32x16 *fir);
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[]);
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config);
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data);
@ -80,6 +80,10 @@ static inline int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x)
int i = 0; /* Start from 1st tap */
int tmp_ri;
/* Bypass is set with length set to zero. */
if (!fir->length)
return x;
/* Write sample to delay */
fir->delay[fir->rwi] = x;
@ -89,7 +93,7 @@ static inline int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x)
n1 = fir->rwi + 1;
/* Point to newest sample and advance read index */
tmp_ri = (fir->rwi)++;
if (fir->rwi == fir->delay_size)
if (fir->rwi == fir->length)
fir->rwi = 0;
if (n1 > fir->length) {
@ -104,7 +108,7 @@ static inline int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x)
fir_part_32x16(&y, n1, fir->coef, &i, fir->delay, &tmp_ri);
/* Part 2, unwrap fir_ri, continue rest of filter */
tmp_ri = fir->delay_size - 1;
tmp_ri = fir->length - 1;
fir_part_32x16(&y, n2, fir->coef, &i, fir->delay, &tmp_ri);
}
/* Q9.39 -> Q9.24, saturate to Q8.24 */

View File

@ -58,10 +58,11 @@
#if XCHAL_HAVE_HIFI2EP == 1
#define FIR_HIFIEP 1
#define FIR_HIFI3 0
#endif
#if XCHAL_HAVE_HIFI3 == 1
#elif XCHAL_HAVE_HIFI3 == 1
#define FIR_HIFI3 1
#define FIR_HIFIEP 0
#else
#error "No HIFIEP or HIFI3 found. Cannot build FIR module."
#endif
#else
/* GCC */

View File

@ -48,34 +48,28 @@
void fir_reset(struct fir_state_32x16 *fir)
{
fir->mute = 1;
fir->taps = 0;
fir->length = 0;
fir->out_shift = 0;
fir->rwp = NULL;
fir->delay = NULL;
fir->delay_end = NULL;
fir->coef = NULL;
/* There may need to know the beginning of dynamic allocation after
* reset so omitting setting also fir->delay to NULL.
*/
}
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config)
{
struct sof_eq_fir_coef_data *setup;
/* The length is taps plus two since the filter computes two
* samples per call. Length plus one would be minimum but the add
* must be even. The even length is needed for 64 bit loads from delay
* lines with 32 bit samples.
*/
setup = (struct sof_eq_fir_coef_data *)config;
fir->mute = 0;
fir->rwp = NULL;
fir->taps = (int)setup->length;
fir->taps = (int)config->length;
fir->length = fir->taps + 2;
fir->out_shift = (int)setup->out_shift;
fir->coef = (ae_p16x2s *)&setup->coef[0];
fir->out_shift = (int)config->out_shift;
fir->coef = (ae_p16x2s *)&config->coef[0];
fir->delay = NULL;
fir->delay_end = NULL;
@ -86,7 +80,7 @@ int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
if (fir->taps & 3)
return -EINVAL;
return fir->length;
return fir->length * sizeof(int32_t);
}
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data)
@ -100,13 +94,8 @@ void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data)
void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift,
int *rshift)
{
if (fir->mute) {
*lshift = 0;
*rshift = 31;
} else {
*lshift = (fir->out_shift < 0) ? -fir->out_shift : 0;
*rshift = (fir->out_shift > 0) ? fir->out_shift : 0;
}
*lshift = (fir->out_shift < 0) ? -fir->out_shift : 0;
*rshift = (fir->out_shift > 0) ? fir->out_shift : 0;
}
/* For even frame lengths use FIR filter that processes two sequential

View File

@ -44,7 +44,6 @@ struct fir_state_32x16 {
ae_p24f *delay; /* Pointer to FIR delay line */
ae_p24f *delay_end; /* Pointer to FIR delay line end */
ae_p16x2s *coef; /* Pointer to FIR coefficients */
int mute; /* Set to 1 to mute EQ output, 0 otherwise */
int taps; /* Number of FIR taps */
int length; /* Number of FIR taps plus input length (even) */
int in_shift; /* Amount of right shifts at input */
@ -53,7 +52,8 @@ struct fir_state_32x16 {
void fir_reset(struct fir_state_32x16 *fir);
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[]);
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config);
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data);
@ -65,18 +65,6 @@ void eq_fir_2x_s32_hifiep(struct fir_state_32x16 fir[],
void eq_fir_s32_hifiep(struct fir_state_32x16 fir[], struct comp_buffer *source,
struct comp_buffer *sink, int frames, int nch);
/* The next trivial functions are inlined */
static inline void fir_mute(struct fir_state_32x16 *fir)
{
fir->mute = 1;
}
static inline void fir_unmute(struct fir_state_32x16 *fir)
{
fir->mute = 0;
}
/* Setup circular buffer for FIR input data delay */
static inline void fir_hifiep_setup_circular(struct fir_state_32x16 *fir)
{
@ -114,6 +102,12 @@ static inline void fir_32x16_hifiep(struct fir_state_32x16 *fir, int32_t *x,
const int taps_div_4 = fir->taps >> 2;
const int inc = sizeof(int32_t);
/* Bypass samples if taps count is zero. */
if (!taps_div_4) {
*y = *x;
return;
}
/* Write sample to delay */
a = AE_LQ32F_I((ae_q32s *)x, 0);
AE_SQ32F_C(a, (ae_q32s *)fir->rwp, -sizeof(int32_t));
@ -184,6 +178,13 @@ static inline void fir_32x16_2x_hifiep(struct fir_state_32x16 *fir, int32_t *x0,
const int taps_div_4 = fir->taps >> 2;
const int inc = 2 * sizeof(int32_t);
/* Bypass samples if taps count is zero. */
if (!taps_div_4) {
*y0 = *x0;
*y1 = *x1;
return;
}
/* Write samples to delay */
a = AE_LQ32F_I((ae_q32s *)x0, 0);
AE_SQ32F_C(a, (ae_q32s *)fir->rwp, -sizeof(int32_t));

View File

@ -48,34 +48,28 @@
void fir_reset(struct fir_state_32x16 *fir)
{
fir->mute = 1;
fir->taps = 0;
fir->length = 0;
fir->out_shift = 0;
fir->rwp = NULL;
fir->delay = NULL;
fir->delay_end = NULL;
fir->coef = NULL;
/* There may need to know the beginning of dynamic allocation after
* reset so omitting setting also fir->delay to NULL.
*/
}
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config)
{
struct sof_eq_fir_coef_data *setup;
/* The length is taps plus two since the filter computes two
* samples per call. Length plus one would be minimum but the add
* must be even. The even length is needed for 64 bit loads from delay
* lines with 32 bit samples.
*/
setup = (struct sof_eq_fir_coef_data *)config;
fir->mute = 0;
fir->rwp = NULL;
fir->taps = (int)setup->length;
fir->taps = (int)config->length;
fir->length = fir->taps + 2;
fir->out_shift = (int)setup->out_shift;
fir->coef = (ae_f16x4 *)&setup->coef[0];
fir->out_shift = (int)config->out_shift;
fir->coef = (ae_f16x4 *)&config->coef[0];
fir->delay = NULL;
fir->delay_end = NULL;
@ -86,7 +80,7 @@ int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
if (fir->taps & 3)
return -EINVAL;
return fir->length;
return fir->length * sizeof(int32_t);
}
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data)
@ -100,13 +94,8 @@ void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data)
void fir_get_lrshifts(struct fir_state_32x16 *fir, int *lshift,
int *rshift)
{
if (fir->mute) {
*lshift = 0;
*rshift = 31;
} else {
*lshift = (fir->out_shift < 0) ? -fir->out_shift : 0;
*rshift = (fir->out_shift > 0) ? fir->out_shift : 0;
}
*lshift = (fir->out_shift < 0) ? -fir->out_shift : 0;
*rshift = (fir->out_shift > 0) ? fir->out_shift : 0;
}
/* For even frame lengths use FIR filter that processes two sequential
@ -131,8 +120,7 @@ void eq_fir_2x_s32_hifi3(struct fir_state_32x16 fir[],
int inc = nch << 1;
for (ch = 0; ch < nch; ch++) {
/* Get FIR instance and get shifts to e.g. apply mute
* without overhead.
/* Get FIR instance and get shifts.
*/
f = &fir[ch];
fir_get_lrshifts(f, &lshift, &rshift);

View File

@ -44,7 +44,6 @@ struct fir_state_32x16 {
ae_int32 *delay; /* Pointer to FIR delay line */
ae_int32 *delay_end; /* Pointer to FIR delay line end */
ae_f16x4 *coef; /* Pointer to FIR coefficients */
int mute; /* Set to 1 to mute EQ output, 0 otherwise */
int taps; /* Number of FIR taps */
int length; /* Number of FIR taps plus input length (even) */
int in_shift; /* Amount of right shifts at input */
@ -53,7 +52,8 @@ struct fir_state_32x16 {
void fir_reset(struct fir_state_32x16 *fir);
int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[]);
size_t fir_init_coef(struct fir_state_32x16 *fir,
struct sof_eq_fir_coef_data *config);
void fir_init_delay(struct fir_state_32x16 *fir, int32_t **data);
@ -64,18 +64,6 @@ void eq_fir_2x_s32_hifi3(struct fir_state_32x16 fir[],
void eq_fir_s32_hifi3(struct fir_state_32x16 fir[], struct comp_buffer *source,
struct comp_buffer *sink, int frames, int nch);
/* The next trivial functions are inlined */
static inline void fir_mute(struct fir_state_32x16 *fir)
{
fir->mute = 1;
}
static inline void fir_unmute(struct fir_state_32x16 *fir)
{
fir->mute = 0;
}
/* Setup circular buffer for FIR input data delay */
static inline void fir_hifi3_setup_circular(struct fir_state_32x16 *fir)
{
@ -114,6 +102,12 @@ static inline void fir_32x16_hifi3(struct fir_state_32x16 *fir, int32_t *x,
const int taps_div_4 = fir->taps >> 2;
const int inc = sizeof(int32_t);
/* Bypass samples if taps count is zero. */
if (!taps_div_4) {
*y = *x;
return;
}
/* Write sample to delay */
AE_S32_L_XC((ae_int32)*x, fir->rwp, -sizeof(int32_t));
@ -188,6 +182,13 @@ static inline void fir_32x16_2x_hifi3(struct fir_state_32x16 *fir, int32_t *x0,
const int taps_div_4 = fir->taps >> 2;
const int inc = 2 * sizeof(int32_t);
/* Bypass samples if taps count is zero. */
if (!taps_div_4) {
*y0 = *x0;
*y1 = *x1;
return;
}
/* Write samples to delay */
AE_S32_L_XC((ae_int32)*x0, fir->rwp, -sizeof(int32_t));
dp = (ae_f32x2 *)fir->rwp;

View File

@ -44,6 +44,8 @@
#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */
#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */
/*
* eq_fir_configuration data structure contains this information
* uint32_t size