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