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