[Sound-open-firmware] [PATCH] EQ IIR: Get filter config and response switch via ABI
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 */ +
participants (1)
-
Seppo Ingalsuo