1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2020 Intel Corporation. All rights reserved.
4  *
5  * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6  */
7 
8 #ifndef __SOF_AUDIO_TDFB_CONFIG_H__
9 #define __SOF_AUDIO_TDFB_CONFIG_H__
10 
11 #include <sof/audio/module_adapter/module/generic.h>
12 #include <sof/audio/audio_stream.h>
13 #include <sof/math/fir_generic.h>
14 #include <sof/math/fir_hifi2ep.h>
15 #include <sof/math/fir_hifi3.h>
16 #include <sof/math/iir_df1.h>
17 #include <sof/platform.h>
18 #include <user/tdfb.h>
19 
20 /* Select optimized code variant when xt-xcc compiler is used */
21 #if defined __XCC__
22 #include <xtensa/config/core-isa.h>
23 #if XCHAL_HAVE_HIFI2EP == 1
24 #define TDFB_GENERIC	0
25 #define TDFB_HIFIEP	1
26 #define TDFB_HIFI3	0
27 #elif XCHAL_HAVE_HIFI3 == 1
28 #define TDFB_HIFI3	1
29 #define TDFB_HIFIEP	0
30 #define TDFB_GENERIC	0
31 #else
32 #error "No HIFIEP or HIFI3 found. Cannot build TDFB module."
33 #endif
34 #else
35 /* GCC */
36 #define TDFB_GENERIC	1
37 #define TDFB_HIFIEP	0
38 #define TDFB_HIFI3	0
39 #endif
40 
41 #define TDFB_IN_BUF_LENGTH (2 * PLATFORM_MAX_CHANNELS)
42 #define TDFB_OUT_BUF_LENGTH (2 * PLATFORM_MAX_CHANNELS)
43 
44 /* When set to one only one IPC is sent to host. There is not other requests
45  * triggered. If set to zero the IPC sent will be empty and the driver will
46  * issue an actual control get. In simple  case with known # of control channels
47  * including is more efficient.
48  */
49 #define TDFB_ADD_DIRECTION_TO_GET_CMD 1
50 
51 /* Allocate size is header plus single control value */
52 #define TDFB_GET_CTRL_DATA_SIZE (sizeof(struct sof_ipc_ctrl_data) + \
53 	sizeof(struct sof_ipc_ctrl_value_chan))
54 
55 /* Process max 10% more frames than one period */
56 #define TDFB_MAX_FRAMES_MULT_Q14 Q_CONVERT_FLOAT(1.10, 14)
57 
58 /* TDFB component private data */
59 
60 struct tdfb_direction_data {
61 	struct iir_state_df1 emphasis[PLATFORM_MAX_CHANNELS];
62 	int32_t timediff[PLATFORM_MAX_CHANNELS];
63 	int32_t timediff_iter[PLATFORM_MAX_CHANNELS];
64 	int64_t level_ambient;
65 	uint32_t trigger;
66 	int32_t level;
67 	int32_t unit_delay; /* Q1.31 seconds */
68 	int32_t frame_count_since_control;
69 	int32_t *df1_delay;
70 	int32_t *r;
71 	int16_t *d;
72 	int16_t *d_end;
73 	int16_t *wp;
74 	int16_t *rp;
75 	int16_t step_sign;
76 	int16_t az_slow;
77 	int16_t az;
78 	int16_t max_lag;
79 	size_t d_size;
80 	size_t r_size;
81 	bool line_array; /* Limit scan to -90 to 90 degrees */
82 };
83 
84 struct tdfb_comp_data {
85 	struct fir_state_32x16 fir[SOF_TDFB_FIR_MAX_COUNT]; /**< FIR state */
86 	struct comp_data_blob_handler *model_handler;
87 	struct sof_tdfb_config *config;	    /**< pointer to setup blob */
88 	struct sof_tdfb_angle *filter_angles;
89 	struct sof_tdfb_mic_location *mic_locations;
90 	struct sof_ipc_ctrl_data *ctrl_data;
91 	struct ipc_msg *msg;
92 	struct tdfb_direction_data direction;
93 	int32_t in[TDFB_IN_BUF_LENGTH];	    /**< input samples buffer */
94 	int32_t out[TDFB_IN_BUF_LENGTH];    /**< output samples mix buffer */
95 	int32_t *fir_delay;		    /**< pointer to allocated RAM */
96 	int16_t *input_channel_select;	    /**< For each FIR define in ch */
97 	int16_t *output_channel_mix;	    /**< For each FIR define out ch */
98 	int16_t *output_stream_mix;         /**< for each FIR define stream */
99 	int16_t az_value;		    /**< beam steer azimuth as in control enum */
100 	int16_t az_value_estimate;	    /**< beam steer azimuth as in control enum */
101 	size_t fir_delay_size;              /**< allocated size */
102 	unsigned int max_frames;	    /**< max frames to process */
103 	bool direction_updates:1;	    /**< set true if direction angle control is updated */
104 	bool direction_change:1;	    /**< set if direction value has significant change */
105 	bool beam_on:1;			    /**< set true if beam is off */
106 	bool update:1;			    /**< set true if control enum has been received */
107 	void (*tdfb_func)(struct tdfb_comp_data *cd,
108 			  struct input_stream_buffer *bsource,
109 			  struct output_stream_buffer *bsink,
110 			  int frames);
111 };
112 
113 #if CONFIG_FORMAT_S16LE
114 void tdfb_fir_s16(struct tdfb_comp_data *cd,
115 		  struct input_stream_buffer *bsource,
116 		  struct output_stream_buffer *bsink, int frames);
117 #endif
118 
119 #if CONFIG_FORMAT_S24LE
120 void tdfb_fir_s24(struct tdfb_comp_data *cd,
121 		  struct input_stream_buffer *bsource,
122 		  struct output_stream_buffer *bsink, int frames);
123 #endif
124 
125 #if CONFIG_FORMAT_S32LE
126 void tdfb_fir_s32(struct tdfb_comp_data *cd,
127 		  struct input_stream_buffer *bsource,
128 		  struct output_stream_buffer *bsink, int frames);
129 #endif
130 
131 int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int channels);
132 void tdfb_direction_copy_emphasis(struct tdfb_comp_data *cd, int channels, int *channel, int32_t x);
133 void tdfb_direction_estimate(struct tdfb_comp_data *cd, int frames, int channels);
134 void tdfb_direction_free(struct tdfb_comp_data *cd);
135 
tdfb_cinc_s16(int16_t ** ptr,int16_t * end,size_t size)136 static inline void tdfb_cinc_s16(int16_t **ptr, int16_t *end, size_t size)
137 {
138 	if (*ptr >= end)
139 		*ptr = (int16_t *)((uint8_t *)*ptr - size);
140 }
141 
tdfb_cdec_s16(int16_t ** ptr,int16_t * start,size_t size)142 static inline void tdfb_cdec_s16(int16_t **ptr, int16_t *start, size_t size)
143 {
144 	if (*ptr < start)
145 		*ptr = (int16_t *)((uint8_t *)*ptr + size);
146 }
147 
148 #ifdef UNIT_TEST
149 void sys_comp_module_tdfb_interface_init(void);
150 #endif
151 
152 #endif /* __SOF_AUDIO_TDFB_CONFIG_H__ */
153