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 #include <stdint.h>
8 #include <sof/audio/format.h>
9 #include <sof/audio/eq_iir/iir.h>
10 #include <sof/audio/component.h>
11 #include <sof/audio/format.h>
12 #include <sof/audio/crossover/crossover.h>
13 
14 /*
15  * \brief Splits x into two based on the coefficients set in the lp
16  *        and hp filters. The output of the lp is in y1, the output of
17  *        the hp is in y2.
18  *
19  * As a side effect, this function mutates the delay values of both
20  * filters.
21  */
crossover_generic_lr4_split(struct iir_state_df2t * lp,struct iir_state_df2t * hp,int32_t x,int32_t * y1,int32_t * y2)22 static inline void crossover_generic_lr4_split(struct iir_state_df2t *lp,
23 					       struct iir_state_df2t *hp,
24 					       int32_t x, int32_t *y1,
25 					       int32_t *y2)
26 {
27 	*y1 = crossover_generic_process_lr4(x, lp);
28 	*y2 = crossover_generic_process_lr4(x, hp);
29 }
30 
31 /*
32  * \brief Splits input signal into two and merges it back to it's
33  *        original form.
34  *
35  * With 3-way crossovers, one output goes through only one LR4 filter,
36  * whereas the other two go through two LR4 filters. This causes the signals
37  * to be out of phase. We need to pass the signal through another set of LR4
38  * filters to align back the phase.
39  */
crossover_generic_lr4_merge(struct iir_state_df2t * lp,struct iir_state_df2t * hp,int32_t x,int32_t * y)40 static inline void crossover_generic_lr4_merge(struct iir_state_df2t *lp,
41 					       struct iir_state_df2t *hp,
42 					       int32_t x, int32_t *y)
43 {
44 	int32_t z1, z2;
45 
46 	z1 = crossover_generic_process_lr4(x, lp);
47 	z2 = crossover_generic_process_lr4(x, hp);
48 	*y = sat_int32(((int64_t)z1) + z2);
49 }
50 
crossover_generic_split_2way(int32_t in,int32_t out[],struct crossover_state * state)51 static void crossover_generic_split_2way(int32_t in,
52 					 int32_t out[],
53 					 struct crossover_state *state)
54 {
55 	crossover_generic_lr4_split(&state->lowpass[0], &state->highpass[0],
56 				    in, &out[0], &out[1]);
57 }
58 
crossover_generic_split_3way(int32_t in,int32_t out[],struct crossover_state * state)59 static void crossover_generic_split_3way(int32_t in,
60 					 int32_t out[],
61 					 struct crossover_state *state)
62 {
63 	int32_t z1, z2;
64 
65 	crossover_generic_lr4_split(&state->lowpass[0], &state->highpass[0],
66 				    in, &z1, &z2);
67 	/* Realign the phase of z1 */
68 	crossover_generic_lr4_merge(&state->lowpass[1], &state->highpass[1],
69 				    z1, &out[0]);
70 	crossover_generic_lr4_split(&state->lowpass[2], &state->highpass[2],
71 				    z2, &out[1], &out[2]);
72 }
73 
crossover_generic_split_4way(int32_t in,int32_t out[],struct crossover_state * state)74 static void crossover_generic_split_4way(int32_t in,
75 					 int32_t out[],
76 					 struct crossover_state *state)
77 {
78 	int32_t z1, z2;
79 
80 	crossover_generic_lr4_split(&state->lowpass[1], &state->highpass[1],
81 				    in, &z1, &z2);
82 	crossover_generic_lr4_split(&state->lowpass[0], &state->highpass[0],
83 				    z1, &out[0], &out[1]);
84 	crossover_generic_lr4_split(&state->lowpass[2], &state->highpass[2],
85 				    z2, &out[2], &out[3]);
86 }
87 
88 #if CONFIG_FORMAT_S16LE
crossover_s16_default_pass(const struct comp_dev * dev,const struct comp_buffer * source,struct comp_buffer * sinks[],int32_t num_sinks,uint32_t frames)89 static void crossover_s16_default_pass(const struct comp_dev *dev,
90 				       const struct comp_buffer *source,
91 				       struct comp_buffer *sinks[],
92 				       int32_t num_sinks,
93 				       uint32_t frames)
94 {
95 	const struct audio_stream *source_stream = &source->stream;
96 	int16_t *x;
97 	int32_t *y;
98 	int i, j;
99 	int n = source_stream->channels * frames;
100 
101 	for (i = 0; i < n; i++) {
102 		x = audio_stream_read_frag_s16(source_stream, i);
103 		for (j = 0; j < num_sinks; j++) {
104 			if (!sinks[j])
105 				continue;
106 			y = audio_stream_read_frag_s16((&sinks[j]->stream), i);
107 			*y = *x;
108 		}
109 	}
110 }
111 #endif /* CONFIG_FORMAT_S16LE */
112 
113 #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE
crossover_s32_default_pass(const struct comp_dev * dev,const struct comp_buffer * source,struct comp_buffer * sinks[],int32_t num_sinks,uint32_t frames)114 static void crossover_s32_default_pass(const struct comp_dev *dev,
115 				       const struct comp_buffer *source,
116 				       struct comp_buffer *sinks[],
117 				       int32_t num_sinks,
118 				       uint32_t frames)
119 {
120 	const struct audio_stream *source_stream = &source->stream;
121 	int32_t *x, *y;
122 	int i, j;
123 	int n = source_stream->channels * frames;
124 
125 	for (i = 0; i < n; i++) {
126 		x = audio_stream_read_frag_s32(source_stream, i);
127 		for (j = 0; j < num_sinks; j++) {
128 			if (!sinks[j])
129 				continue;
130 			y = audio_stream_read_frag_s32((&sinks[j]->stream), i);
131 			*y = *x;
132 		}
133 	}
134 }
135 #endif /* CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE */
136 
137 #if CONFIG_FORMAT_S16LE
crossover_s16_default(const struct comp_dev * dev,const struct comp_buffer * source,struct comp_buffer * sinks[],int32_t num_sinks,uint32_t frames)138 static void crossover_s16_default(const struct comp_dev *dev,
139 				  const struct comp_buffer *source,
140 				  struct comp_buffer *sinks[],
141 				  int32_t num_sinks,
142 				  uint32_t frames)
143 {
144 	struct comp_data *cd = comp_get_drvdata(dev);
145 	struct crossover_state *state;
146 	const struct audio_stream *source_stream = &source->stream;
147 	struct audio_stream *sink_stream;
148 	int16_t *x, *y;
149 	int ch, i, j;
150 	int idx;
151 	int nch = source_stream->channels;
152 	int32_t out[num_sinks];
153 
154 	for (ch = 0; ch < nch; ch++) {
155 		idx = ch;
156 		state = &cd->state[ch];
157 		for (i = 0; i < frames; i++) {
158 			x = audio_stream_read_frag_s16(source_stream, idx);
159 			cd->crossover_split(*x << 16, out, state);
160 
161 			for (j = 0; j < num_sinks; j++) {
162 				if (!sinks[j])
163 					continue;
164 				sink_stream = &sinks[j]->stream;
165 				y = audio_stream_read_frag_s16(sink_stream,
166 							       idx);
167 				*y = sat_int16(Q_SHIFT_RND(out[j], 31, 15));
168 			}
169 
170 			idx += nch;
171 		}
172 	}
173 }
174 #endif /* CONFIG_FORMAT_S16LE */
175 
176 #if CONFIG_FORMAT_S24LE
crossover_s24_default(const struct comp_dev * dev,const struct comp_buffer * source,struct comp_buffer * sinks[],int32_t num_sinks,uint32_t frames)177 static void crossover_s24_default(const struct comp_dev *dev,
178 				  const struct comp_buffer *source,
179 				  struct comp_buffer *sinks[],
180 				  int32_t num_sinks,
181 				  uint32_t frames)
182 {
183 	struct comp_data *cd = comp_get_drvdata(dev);
184 	struct crossover_state *state;
185 	const struct audio_stream *source_stream = &source->stream;
186 	struct audio_stream *sink_stream;
187 	int32_t *x, *y;
188 	int ch, i, j;
189 	int idx;
190 	int nch = source_stream->channels;
191 	int32_t out[num_sinks];
192 
193 	for (ch = 0; ch < nch; ch++) {
194 		idx = ch;
195 		state = &cd->state[ch];
196 		for (i = 0; i < frames; i++) {
197 			x = audio_stream_read_frag_s32(source_stream, idx);
198 			cd->crossover_split(*x << 8, out, state);
199 
200 			for (j = 0; j < num_sinks; j++) {
201 				if (!sinks[j])
202 					continue;
203 				sink_stream = &sinks[j]->stream;
204 				y = audio_stream_read_frag_s32(sink_stream,
205 							       idx);
206 				*y = sat_int24(Q_SHIFT_RND(out[j], 31, 23));
207 			}
208 
209 			idx += nch;
210 		}
211 	}
212 }
213 #endif /* CONFIG_FORMAT_S24LE */
214 
215 #if CONFIG_FORMAT_S32LE
crossover_s32_default(const struct comp_dev * dev,const struct comp_buffer * source,struct comp_buffer * sinks[],int32_t num_sinks,uint32_t frames)216 static void crossover_s32_default(const struct comp_dev *dev,
217 				  const struct comp_buffer *source,
218 				  struct comp_buffer *sinks[],
219 				  int32_t num_sinks,
220 				  uint32_t frames)
221 {
222 	struct comp_data *cd = comp_get_drvdata(dev);
223 	struct crossover_state *state;
224 	const struct audio_stream *source_stream = &source->stream;
225 	struct audio_stream *sink_stream;
226 	int32_t *x, *y;
227 	int ch, i, j;
228 	int idx;
229 	int nch = source_stream->channels;
230 	int32_t out[num_sinks];
231 
232 	for (ch = 0; ch < nch; ch++) {
233 		idx = ch;
234 		state = &cd->state[0];
235 		for (i = 0; i < frames; i++) {
236 			x = audio_stream_read_frag_s32(source_stream, idx);
237 			cd->crossover_split(*x, out, state);
238 
239 			for (j = 0; j < num_sinks; j++) {
240 				if (!sinks[j])
241 					continue;
242 				sink_stream = &sinks[j]->stream;
243 				y = audio_stream_read_frag_s32(sink_stream,
244 							       idx);
245 				*y = out[j];
246 			}
247 
248 			idx += nch;
249 		}
250 	}
251 }
252 #endif /* CONFIG_FORMAT_S32LE */
253 
254 const struct crossover_proc_fnmap crossover_proc_fnmap[] = {
255 /* { SOURCE_FORMAT , PROCESSING FUNCTION } */
256 #if CONFIG_FORMAT_S16LE
257 	{ SOF_IPC_FRAME_S16_LE, crossover_s16_default },
258 #endif /* CONFIG_FORMAT_S16LE */
259 
260 #if CONFIG_FORMAT_S24LE
261 	{ SOF_IPC_FRAME_S24_4LE, crossover_s24_default },
262 #endif /* CONFIG_FORMAT_S24LE */
263 
264 #if CONFIG_FORMAT_S32LE
265 	{ SOF_IPC_FRAME_S32_LE, crossover_s32_default },
266 #endif /* CONFIG_FORMAT_S32LE */
267 };
268 
269 const struct crossover_proc_fnmap crossover_proc_fnmap_pass[] = {
270 /* { SOURCE_FORMAT , PROCESSING FUNCTION } */
271 #if CONFIG_FORMAT_S16LE
272 	{ SOF_IPC_FRAME_S16_LE, crossover_s16_default_pass },
273 #endif /* CONFIG_FORMAT_S16LE */
274 
275 #if CONFIG_FORMAT_S24LE
276 	{ SOF_IPC_FRAME_S24_4LE, crossover_s32_default_pass },
277 #endif /* CONFIG_FORMAT_S24LE */
278 
279 #if CONFIG_FORMAT_S32LE
280 	{ SOF_IPC_FRAME_S32_LE, crossover_s32_default_pass },
281 #endif /* CONFIG_FORMAT_S32LE */
282 };
283 
284 const size_t crossover_proc_fncount = ARRAY_SIZE(crossover_proc_fnmap);
285 
286 const crossover_split crossover_split_fnmap[] = {
287 	crossover_generic_split_2way,
288 	crossover_generic_split_3way,
289 	crossover_generic_split_4way,
290 };
291 
292 const size_t crossover_split_fncount = ARRAY_SIZE(crossover_split_fnmap);
293