The IIR equalizer configure and control is updated to use the new component ABI. In addition there are checks added to protect IIR equalizer from invalid setup.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com --- src/audio/eq_iir.c | 76 +++++++++++++++++--------------- src/audio/eq_iir.h | 47 -------------------- src/include/uapi/eq.h | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 83 deletions(-) create mode 100644 src/include/uapi/eq.h
diff --git a/src/audio/eq_iir.c b/src/audio/eq_iir.c index 58a06a3..86f879a 100644 --- a/src/audio/eq_iir.c +++ b/src/audio/eq_iir.c @@ -44,6 +44,7 @@ #include <reef/audio/pipeline.h> #include <reef/audio/format.h> #include <uapi/ipc.h> +#include <uapi/eq.h> #include "eq_iir.h" #include "iir.h"
@@ -57,7 +58,7 @@
/* src component private data */ struct comp_data { - struct eq_iir_configuration *config; + struct sof_eq_iir_config *config; uint32_t period_bytes; struct iir_state_df2t iir[PLATFORM_MAX_CHANNELS]; void (*eq_iir_func)(struct comp_dev *dev, @@ -120,7 +121,7 @@ static void eq_iir_s32_default(struct comp_dev *dev, } }
-static void eq_iir_free_parameters(struct eq_iir_configuration **config) +static void eq_iir_free_parameters(struct sof_eq_iir_config **config) { if (*config != NULL) rfree(*config); @@ -150,27 +151,31 @@ static void eq_iir_free_delaylines(struct iir_state_df2t *iir) }
static int eq_iir_setup(struct iir_state_df2t iir[], - struct eq_iir_configuration *config, int nch) + struct sof_eq_iir_config *config, int nch) { int i, j, idx, resp; size_t s; size_t size_sum = 0; int64_t *iir_delay; /* TODO should not need to know the type */ + int32_t *coef_data, *assign_response; int response_index[PLATFORM_MAX_CHANNELS];
- if (nch > PLATFORM_MAX_CHANNELS) - return -EINVAL; - /* Free existing IIR channels data if it was allocated */ eq_iir_free_delaylines(iir);
+ if ((nch > PLATFORM_MAX_CHANNELS) + || (config->channels_in_config > PLATFORM_MAX_CHANNELS)) + 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]; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) { - if (i < config->number_of_responses_defined) { + if (i < config->number_of_responses) { response_index[i] = j; j += NHEADER_DF2T - + NBIQUAD_DF2T * config->all_coefficients[j]; + + NBIQUAD_DF2T * coef_data[j]; } else { response_index[i] = 0; } @@ -178,15 +183,17 @@ static int eq_iir_setup(struct iir_state_df2t iir[],
/* Initialize 1st phase */ for (i = 0; i < nch; i++) { - resp = config->assign_response[i]; + resp = assign_response[i]; + if (resp > config->number_of_responses - 1) + return -EINVAL; + if (resp < 0) { /* Initialize EQ channel to bypass */ iir_reset_df2t(&iir[i]); } else { /* Initialize EQ coefficients */ idx = response_index[resp]; - s = iir_init_coef_df2t(&iir[i], - &config->all_coefficients[idx]); + s = iir_init_coef_df2t(&iir[i], &coef_data[idx]); if (s > 0) size_sum += s; else @@ -204,9 +211,8 @@ static int eq_iir_setup(struct iir_state_df2t iir[],
/* Initialize 2nd phase to set EQ delay lines pointers */ for (i = 0; i < nch; i++) { - resp = config->assign_response[i]; + resp = assign_response[i]; if (resp >= 0) { - idx = response_index[resp]; iir_init_delay_df2t(&iir[i], &iir_delay); }
@@ -216,18 +222,19 @@ static int eq_iir_setup(struct iir_state_df2t iir[], }
static int eq_iir_switch_response(struct iir_state_df2t iir[], - struct eq_iir_configuration *config, struct eq_iir_update *update, - int nch) + struct sof_eq_iir_config *config, + struct sof_ipc_ctrl_value_comp compv[], uint32_t num_elemens, int nch) { - int i, ret; + int i, j, ret;
/* Copy assign response from update and re-initilize EQ */ if (config == NULL) return -EINVAL;
- for (i = 0; i < config->stream_max_channels; i++) { - if (i < update->stream_max_channels) - config->assign_response[i] = update->assign_response[i]; + for (i = 0; i < num_elemens; i++) { + j = compv[i].index; + if (j < config->channels_in_config) + config->data[i] = compv[i].svalue; }
ret = eq_iir_setup(iir, config, nch); @@ -293,7 +300,11 @@ static int eq_iir_params(struct comp_dev *dev)
trace_eq_iir("par");
- /* calculate period size based on config */ + /* Calculate period size based on config. First make sure that + * frame_bytes is set. + */ + dev->frame_bytes = + dev->params.sample_container_bytes * dev->params.channels; cd->period_bytes = dev->frames * dev->frame_bytes;
/* configure downstream buffer */ @@ -316,21 +327,21 @@ static int eq_iir_params(struct comp_dev *dev) static int iir_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) { struct comp_data *cd = comp_get_drvdata(dev); - struct eq_iir_update *iir_update; /* TODO: move to IPC header as part of ABI */ + struct sof_ipc_ctrl_value_comp *compv; int i, ret = 0; size_t bs;
switch (cdata->cmd) { case SOF_CTRL_CMD_EQ_SWITCH: trace_eq_iir("EFx"); - iir_update = (struct eq_iir_update *) cdata->data; + compv = (struct sof_ipc_ctrl_value_comp *) cdata->data->data; ret = eq_iir_switch_response(cd->iir, cd->config, - iir_update, PLATFORM_MAX_CHANNELS); + compv, cdata->num_elems, PLATFORM_MAX_CHANNELS);
/* Print trace information */ - tracev_value(iir_update->stream_max_channels); - for (i = 0; i < iir_update->stream_max_channels; i++) - tracev_value(iir_update->assign_response[i]); + tracev_value(cd->config->channels_in_config); + for (i = 0; i < cd->config->channels_in_config; i++) + tracev_value(cd->config->data[i]);
break; case SOF_CTRL_CMD_EQ_CONFIG: @@ -339,8 +350,8 @@ static int iir_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) eq_iir_free_parameters(&cd->config);
/* Copy new config, need to decode data to know the size */ - bs = cdata->num_elems; - if (bs > EQ_IIR_MAX_BLOB_SIZE) + bs = cdata->data->size; + if ((bs > SOF_EQ_IIR_MAX_SIZE) || (bs < 1)) return -EINVAL;
/* Allocate and make a copy of the blob and setup IIR */ @@ -348,18 +359,11 @@ static int iir_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) if (cd->config == NULL) return -EINVAL;
- memcpy(cd->config, cdata->data, bs); + memcpy(cd->config, cdata->data->data, bs); /* Initialize all channels, the actual number of channels may * not be set yet. */ ret = eq_iir_setup(cd->iir, cd->config, PLATFORM_MAX_CHANNELS); - - /* Print trace information */ - tracev_value(cd->config->stream_max_channels); - tracev_value(cd->config->number_of_responses_defined); - for (i = 0; i < cd->config->stream_max_channels; i++) - tracev_value(cd->config->assign_response[i]); - break; case SOF_CTRL_CMD_MUTE: trace_eq_iir("EFm"); diff --git a/src/audio/eq_iir.h b/src/audio/eq_iir.h index 42d95c1..e28a1a3 100644 --- a/src/audio/eq_iir.h +++ b/src/audio/eq_iir.h @@ -33,51 +33,4 @@ #ifndef EQ_IIR_H #define EQ_IIR_H
- - -/* eq_iir_configuration - * uint32_t platform max channels - * uint32_t number_of_responses_defined - * 0=no responses, 1=one response defined, 2=two responses defined, etc. - * uint32_t assign_response[PLATFORM_MAX_CHANNELS] - * -1 = not defined, 0 = use first response, 1 = use 2nd response, etc. - * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the - * same first defined response and leave channels 4-7 unequalized. - * all_coefficients[] - * <1st EQ> - * uint32_t num_biquads - * uint32_t num_biquads_in_series - * <1st biquad> - * int32_t coef_a2 Q2.30 format - * int32_t coef_a1 Q2.30 format - * int32_t coef_b2 Q2.30 format - * int32_t coef_b1 Q2.30 format - * int32_t coef_b0 Q2.30 format - * int32_t output_shift number of shifts right, shift left is negative - * int32_t output_gain Q2.14 format - * <2nd biquad> - * ... - * <2nd EQ> - * - * Note: A flat response biquad can be made with a section set to - * b0 = 1.0, gain = 1.0, and other parameters set to 0 - * {0, 0, 0, 0, 1073741824, 0, 16484} - */ - -#define EQ_IIR_MAX_BLOB_SIZE 1024 /* In bytes or size_t */ - -#define NHEADER_EQ_IIR_BLOB 2 /* Blob is two words plus asssigns plus coef */ - -struct eq_iir_configuration { - int32_t stream_max_channels; - int32_t number_of_responses_defined; - int32_t assign_response[PLATFORM_MAX_CHANNELS]; - int32_t all_coefficients[]; -}; - -struct eq_iir_update { - int32_t stream_max_channels; - int32_t assign_response[PLATFORM_MAX_CHANNELS]; -}; - #endif diff --git a/src/include/uapi/eq.h b/src/include/uapi/eq.h new file mode 100644 index 0000000..9c42a51 --- /dev/null +++ b/src/include/uapi/eq.h @@ -0,0 +1,119 @@ +/* + * 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 EQ_H +#define EQ_H + +/* FIR EQ type */ + +/* Component will reject non-matching configuration. The version number need + * to be incremented with any ABI changes in function fir_cmd(). + */ +#define SOF_EQ_FIR_ABI_VERSION 1 + +#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */ + +/* + * eq_fir_configuration data structure contains this information + * uint16_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint16_t number_of_responses + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int16_t data[] + * assign_response[STREAM_MAX_CHANNELS] + * -1 = not defined, 0 = use first response, 1 = use 2nd response, etc. + * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the + * same first defined response and leave channels 4-7 unequalized. + * coef_data[] + * Repeated data { filter_length, input_shift, output_shift, h[] } + * for every EQ response defined where vector h has filter_length + * number of coefficients. Coefficients in h[] are in Q1.15 format. + * E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts. + */ + +struct sof_eq_fir_config { + uint16_t channels_in_config; + uint16_t number_of_responses; + int16_t data[]; +}; + +/* IIR EQ type */ + +/* Component will reject non-matching configuration. The version number need + * to be incremented with any ABI changes in function fir_cmd(). + */ +#define SOF_EQ_FIR_ABI_VERSION 1 + +#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */ + +/* eq_iir_configuration + * uint32_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint32_t number_of_responses_defined + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int32_t data[] + * Data consist of two parts. First is the response assign vector that + * has length of channels_in_config. The latter part is coefficient + * data. + * uint32_t assign_response[channels_in_config] + * -1 = not defined, 0 = use first response, 1 = use 2nd, etc. + * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the + * same first defined response and leave channels 4-7 unequalized. + * coefficient_data[] + * <1st EQ> + * uint32_t num_biquads + * uint32_t num_biquads_in_series + * <1st biquad> + * int32_t coef_a2 Q2.30 format + * int32_t coef_a1 Q2.30 format + * int32_t coef_b2 Q2.30 format + * int32_t coef_b1 Q2.30 format + * int32_t coef_b0 Q2.30 format + * int32_t output_shift number of shifts right, shift left is negative + * int32_t output_gain Q2.14 format + * <2nd biquad> + * ... + * <2nd EQ> + * + * Note: A flat response biquad can be made with a section set to + * b0 = 1.0, gain = 1.0, and other parameters set to 0 + * {0, 0, 0, 0, 1073741824, 0, 16484} + */ + +struct sof_eq_iir_config { + uint32_t channels_in_config; + uint32_t number_of_responses; + int32_t data[]; +}; + +#endif /* EQ_H */ +