1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2020 Google LLC. All rights reserved.
4  *
5  * Author: Sebastiano Carlucci <scarlucci@google.com>
6  */
7 #ifndef __SOF_AUDIO_CROSSOVER_CROSSOVER_H__
8 #define __SOF_AUDIO_CROSSOVER_CROSSOVER_H__
9 
10 #include <stdint.h>
11 #include <sof/platform.h>
12 #include <sof/math/iir_df2t.h>
13 #include <user/crossover.h>
14 
15 struct comp_buffer;
16 struct comp_dev;
17 
18 /* Maximum number of LR4 highpass OR lowpass filters */
19 #define CROSSOVER_MAX_LR4 3
20 /* Number of delay slots allocated for LR4 Filters */
21 #define CROSSOVER_NUM_DELAYS_LR4 4
22 
23 /* Number of sinks for a 2 way crossover filter */
24 #define CROSSOVER_2WAY_NUM_SINKS 2
25 /* Number of sinks for a 3 way crossover filter */
26 #define CROSSOVER_3WAY_NUM_SINKS 3
27 /* Number of sinks for a 4 way crossover filter */
28 #define CROSSOVER_4WAY_NUM_SINKS 4
29 
30 /**
31  * The Crossover filter will have from 2 to 4 outputs.
32  * Diagram of a 4-way Crossover filter (6 LR4 Filters).
33  *
34  *                             o---- LR4 LO-PASS --> y1(n)
35  *                             |
36  *          o--- LR4 LO-PASS --o
37  *          |                  |
38  *          |                  o--- LR4 HI-PASS --> y2(n)
39  * x(n) --- o
40  *          |                  o--- LR4 LO-PASS --> y3(n)
41  *          |                  |
42  *          o--- LR4 HI-PASS --o
43  *                             |
44  *                             o--- LR4 HI-PASS --> y4(n)
45  *
46  * Refer to include/user/crossover.h for diagrams of 2-way and 3-way crossovers
47  * The low and high pass LR4 filters have opposite phase responses, causing
48  * the intermediary outputs to be out of phase by 180 degrees.
49  * For 2-way and 3-way, the phases of the signals need to be synchronized.
50  *
51  * Each LR4 is made of two butterworth filters in series with the same params.
52  *
53  * x(n) --> BIQUAD --> z(n) --> BIQUAD --> y(n)
54  *
55  * In total, we keep track of the state of at most 6 IIRs each made of two
56  * biquads in series.
57  *
58  */
59 
60 /**
61  * Stores the state of one channel of the Crossover filter
62  */
63 struct crossover_state {
64 	/* Store the state for each LR4 filter. */
65 	struct iir_state_df2t lowpass[CROSSOVER_MAX_LR4];
66 	struct iir_state_df2t highpass[CROSSOVER_MAX_LR4];
67 };
68 
69 typedef void (*crossover_process)(const struct comp_dev *dev,
70 				  const struct comp_buffer *source,
71 				  struct comp_buffer *sinks[],
72 				  int32_t num_sinks,
73 				  uint32_t frames);
74 
75 typedef void (*crossover_split)(int32_t in, int32_t out[],
76 				struct crossover_state *state);
77 
78 /* Crossover component private data */
79 struct comp_data {
80 	/**< filter state */
81 	struct crossover_state state[PLATFORM_MAX_CHANNELS];
82 	struct sof_crossover_config *config;      /**< pointer to setup blob */
83 	struct sof_crossover_config *config_new;  /**< pointer to new setup */
84 	enum sof_ipc_frame source_format;         /**< source frame format */
85 	crossover_process crossover_process;      /**< processing function */
86 	crossover_split crossover_split;          /**< split function */
87 };
88 
89 struct crossover_proc_fnmap {
90 	enum sof_ipc_frame frame_fmt;
91 	crossover_process crossover_proc_func;
92 };
93 
94 extern const struct crossover_proc_fnmap crossover_proc_fnmap[];
95 extern const struct crossover_proc_fnmap crossover_proc_fnmap_pass[];
96 extern const size_t crossover_proc_fncount;
97 
98 /**
99  * \brief Returns Crossover processing function.
100  */
101 static inline crossover_process
crossover_find_proc_func(enum sof_ipc_frame src_fmt)102 	crossover_find_proc_func(enum sof_ipc_frame src_fmt)
103 {
104 	int i;
105 
106 	/* Find suitable processing function from map */
107 	for (i = 0; i < crossover_proc_fncount; i++)
108 		if (src_fmt == crossover_proc_fnmap[i].frame_fmt)
109 			return crossover_proc_fnmap[i].crossover_proc_func;
110 
111 	return NULL;
112 }
113 
114 /**
115  * \brief Returns Crossover passthrough functions.
116  */
117 static inline crossover_process
crossover_find_proc_func_pass(enum sof_ipc_frame src_fmt)118 	crossover_find_proc_func_pass(enum sof_ipc_frame src_fmt)
119 {
120 	int i;
121 
122 	/* Find suitable processing function from map */
123 	for (i = 0; i < crossover_proc_fncount; i++)
124 		if (src_fmt == crossover_proc_fnmap_pass[i].frame_fmt)
125 			return crossover_proc_fnmap_pass[i].crossover_proc_func;
126 
127 	return NULL;
128 }
129 
130 extern const crossover_split crossover_split_fnmap[];
131 extern const size_t crossover_split_fncount;
132 
133 /**
134  * \brief Returns Crossover split function.
135  */
crossover_find_split_func(int32_t num_sinks)136 static inline crossover_split crossover_find_split_func(int32_t num_sinks)
137 {
138 	if (num_sinks < CROSSOVER_2WAY_NUM_SINKS &&
139 	    num_sinks > CROSSOVER_4WAY_NUM_SINKS)
140 		return NULL;
141 	// The functions in the map are offset by 2 indices.
142 	return crossover_split_fnmap[num_sinks - CROSSOVER_2WAY_NUM_SINKS];
143 }
144 
145 /*
146  * \brief Runs input in through the LR4 filter and returns it's output.
147  */
crossover_generic_process_lr4(int32_t in,struct iir_state_df2t * lr4)148 static inline int32_t crossover_generic_process_lr4(int32_t in,
149 						    struct iir_state_df2t *lr4)
150 {
151 	/* Cascade two biquads with same coefficients in series. */
152 	return iir_df2t(lr4, in);
153 }
154 
155 #endif //  __SOF_AUDIO_CROSSOVER_CROSSOVER_H__
156