[Sound-open-firmware] [PATCH] EQ IIR: Get filter config and response switch via ABI
Seppo Ingalsuo
seppo.ingalsuo at linux.intel.com
Mon Sep 25 15:13:59 CEST 2017
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 at 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 at 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 */
+
--
2.11.0
More information about the Sound-open-firmware
mailing list