1 /**
2  *******************************************************************************
3  * @file    OpenPDMFilter.c
4  * @author  CL
5  * @version V1.0.0
6  * @date    9-September-2015
7  * @brief   Open PDM audio software decoding Library.
8  *          This Library is used to decode and reconstruct the audio signal
9  *          produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx).
10  *******************************************************************************
11  * @attention
12  *
13  * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
14  *
15  * Licensed under the Apache License, Version 2.0 (the "License");
16  * you may not use this file except in compliance with the License.
17  * You may obtain a copy of the License at
18  *
19  *  http://www.apache.org/licenses/LICENSE-2.0
20  *
21  * Unless required by applicable law or agreed to in writing, software
22  * distributed under the License is distributed on an "AS IS" BASIS,
23  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24  * See the License for the specific language governing permissions and
25  * limitations under the License.
26  *******************************************************************************
27  */
28 
29 
30 /* Includes ------------------------------------------------------------------*/
31 
32 #include "OpenPDMFilter.h"
33 
34 
35 /* Variables -----------------------------------------------------------------*/
36 
37 uint32_t div_const = 0;
38 int64_t sub_const = 0;
39 uint32_t sinc[DECIMATION_MAX * SINCN];
40 uint32_t sinc1[DECIMATION_MAX];
41 uint32_t sinc2[DECIMATION_MAX * 2];
42 uint32_t coef[SINCN][DECIMATION_MAX];
43 #ifdef USE_LUT
44 int32_t lut[256][DECIMATION_MAX / 8][SINCN];
45 #endif
46 
47 
48 /* Functions -----------------------------------------------------------------*/
49 
50 #ifdef USE_LUT
filter_table_mono_64(uint8_t * data,uint8_t sincn)51 int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn)
52 {
53   return (int32_t)
54     lut[data[0]][0][sincn] +
55     lut[data[1]][1][sincn] +
56     lut[data[2]][2][sincn] +
57     lut[data[3]][3][sincn] +
58     lut[data[4]][4][sincn] +
59     lut[data[5]][5][sincn] +
60     lut[data[6]][6][sincn] +
61     lut[data[7]][7][sincn];
62 }
filter_table_stereo_64(uint8_t * data,uint8_t sincn)63 int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn)
64 {
65   return (int32_t)
66     lut[data[0]][0][sincn] +
67     lut[data[2]][1][sincn] +
68     lut[data[4]][2][sincn] +
69     lut[data[6]][3][sincn] +
70     lut[data[8]][4][sincn] +
71     lut[data[10]][5][sincn] +
72     lut[data[12]][6][sincn] +
73     lut[data[14]][7][sincn];
74 }
filter_table_mono_128(uint8_t * data,uint8_t sincn)75 int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn)
76 {
77   return (int32_t)
78     lut[data[0]][0][sincn] +
79     lut[data[1]][1][sincn] +
80     lut[data[2]][2][sincn] +
81     lut[data[3]][3][sincn] +
82     lut[data[4]][4][sincn] +
83     lut[data[5]][5][sincn] +
84     lut[data[6]][6][sincn] +
85     lut[data[7]][7][sincn] +
86     lut[data[8]][8][sincn] +
87     lut[data[9]][9][sincn] +
88     lut[data[10]][10][sincn] +
89     lut[data[11]][11][sincn] +
90     lut[data[12]][12][sincn] +
91     lut[data[13]][13][sincn] +
92     lut[data[14]][14][sincn] +
93     lut[data[15]][15][sincn];
94 }
filter_table_stereo_128(uint8_t * data,uint8_t sincn)95 int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn)
96 {
97   return (int32_t)
98     lut[data[0]][0][sincn] +
99     lut[data[2]][1][sincn] +
100     lut[data[4]][2][sincn] +
101     lut[data[6]][3][sincn] +
102     lut[data[8]][4][sincn] +
103     lut[data[10]][5][sincn] +
104     lut[data[12]][6][sincn] +
105     lut[data[14]][7][sincn] +
106     lut[data[16]][8][sincn] +
107     lut[data[18]][9][sincn] +
108     lut[data[20]][10][sincn] +
109     lut[data[22]][11][sincn] +
110     lut[data[24]][12][sincn] +
111     lut[data[26]][13][sincn] +
112     lut[data[28]][14][sincn] +
113     lut[data[30]][15][sincn];
114 }
115 int32_t (* filter_tables_64[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64};
116 int32_t (* filter_tables_128[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128};
117 #else
filter_table(uint8_t * data,uint8_t sincn,TPDMFilter_InitStruct * param)118 int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param)
119 {
120   uint8_t c, i;
121   uint16_t data_index = 0;
122   uint32_t *coef_p = &coef[sincn][0];
123   int32_t F = 0;
124   uint8_t decimation = param->Decimation;
125   uint8_t channels = param->In_MicChannels;
126 
127   for (i = 0; i < decimation; i += 8) {
128     c = data[data_index];
129     F += ((c >> 7)       ) * coef_p[i    ] +
130          ((c >> 6) & 0x01) * coef_p[i + 1] +
131          ((c >> 5) & 0x01) * coef_p[i + 2] +
132          ((c >> 4) & 0x01) * coef_p[i + 3] +
133          ((c >> 3) & 0x01) * coef_p[i + 4] +
134          ((c >> 2) & 0x01) * coef_p[i + 5] +
135          ((c >> 1) & 0x01) * coef_p[i + 6] +
136          ((c     ) & 0x01) * coef_p[i + 7];
137     data_index += channels;
138   }
139   return F;
140 }
141 #endif
142 
convolve(uint32_t Signal[],unsigned short SignalLen,uint32_t Kernel[],unsigned short KernelLen,uint32_t Result[])143 void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
144               uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
145               uint32_t Result[/* SignalLen + KernelLen - 1 */])
146 {
147   uint16_t n;
148 
149   for (n = 0; n < SignalLen + KernelLen - 1; n++)
150   {
151     unsigned short kmin, kmax, k;
152 
153     Result[n] = 0;
154 
155     kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
156     kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
157 
158     for (k = kmin; k <= kmax; k++) {
159       Result[n] += Signal[k] * Kernel[n - k];
160     }
161   }
162 }
163 
Open_PDM_Filter_Init(TPDMFilter_InitStruct * Param)164 void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param)
165 {
166   uint16_t i, j;
167   int64_t sum = 0;
168 
169   uint8_t decimation = Param->Decimation;
170 
171   for (i = 0; i < SINCN; i++) {
172     Param->Coef[i] = 0;
173     Param->bit[i] = 0;
174   }
175   for (i = 0; i < decimation; i++) {
176     sinc1[i] = 1;
177   }
178 
179   Param->OldOut = Param->OldIn = Param->OldZ = 0;
180   Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);
181   Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);
182 
183   Param->FilterLen = decimation * SINCN;
184   sinc[0] = 0;
185   sinc[decimation * SINCN - 1] = 0;
186   convolve(sinc1, decimation, sinc1, decimation, sinc2);
187   convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);
188   for(j = 0; j < SINCN; j++) {
189     for (i = 0; i < decimation; i++) {
190       coef[j][i] = sinc[j * decimation + i];
191       sum += sinc[j * decimation + i];
192     }
193   }
194 
195   sub_const = sum >> 1;
196   div_const = sub_const * Param->MaxVolume / 32768 / FILTER_GAIN;
197   div_const = (div_const == 0 ? 1 : div_const);
198 
199 #ifdef USE_LUT
200   /* Look-Up Table. */
201   uint16_t c, d, s;
202   for (s = 0; s < SINCN; s++)
203   {
204     uint32_t *coef_p = &coef[s][0];
205     for (c = 0; c < 256; c++)
206       for (d = 0; d < decimation / 8; d++)
207         lut[c][d][s] = ((c >> 7)       ) * coef_p[d * 8    ] +
208                        ((c >> 6) & 0x01) * coef_p[d * 8 + 1] +
209                        ((c >> 5) & 0x01) * coef_p[d * 8 + 2] +
210                        ((c >> 4) & 0x01) * coef_p[d * 8 + 3] +
211                        ((c >> 3) & 0x01) * coef_p[d * 8 + 4] +
212                        ((c >> 2) & 0x01) * coef_p[d * 8 + 5] +
213                        ((c >> 1) & 0x01) * coef_p[d * 8 + 6] +
214                        ((c     ) & 0x01) * coef_p[d * 8 + 7];
215   }
216 #endif
217 }
218 
Open_PDM_Filter_64(uint8_t * data,uint16_t * dataOut,uint16_t volume,TPDMFilter_InitStruct * Param)219 void Open_PDM_Filter_64(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
220 {
221   uint8_t i, data_out_index;
222   uint8_t channels = Param->In_MicChannels;
223   uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels);
224   int64_t Z, Z0, Z1, Z2;
225   int64_t OldOut, OldIn, OldZ;
226 
227   OldOut = Param->OldOut;
228   OldIn = Param->OldIn;
229   OldZ = Param->OldZ;
230 
231 #ifdef USE_LUT
232   uint8_t j = channels - 1;
233 #endif
234 
235   for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
236 #ifdef USE_LUT
237     Z0 = filter_tables_64[j](data, 0);
238     Z1 = filter_tables_64[j](data, 1);
239     Z2 = filter_tables_64[j](data, 2);
240 #else
241     Z0 = filter_table(data, 0, Param);
242     Z1 = filter_table(data, 1, Param);
243     Z2 = filter_table(data, 2, Param);
244 #endif
245 
246     Z = Param->Coef[1] + Z2 - sub_const;
247     Param->Coef[1] = Param->Coef[0] + Z1;
248     Param->Coef[0] = Z0;
249 
250     OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
251     OldIn = Z;
252     OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
253 
254     Z = OldZ * volume;
255     Z = RoundDiv(Z, div_const);
256     Z = SaturaLH(Z, -32700, 32700);
257 
258     dataOut[data_out_index] = Z;
259     data += data_inc;
260   }
261 
262   Param->OldOut = OldOut;
263   Param->OldIn = OldIn;
264   Param->OldZ = OldZ;
265 }
266 
Open_PDM_Filter_128(uint8_t * data,uint16_t * dataOut,uint16_t volume,TPDMFilter_InitStruct * Param)267 void Open_PDM_Filter_128(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
268 {
269   uint8_t i, data_out_index;
270   uint8_t channels = Param->In_MicChannels;
271   uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels);
272   int64_t Z, Z0, Z1, Z2;
273   int64_t OldOut, OldIn, OldZ;
274 
275   OldOut = Param->OldOut;
276   OldIn = Param->OldIn;
277   OldZ = Param->OldZ;
278 
279 #ifdef USE_LUT
280   uint8_t j = channels - 1;
281 #endif
282 
283   for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
284 #ifdef USE_LUT
285     Z0 = filter_tables_128[j](data, 0);
286     Z1 = filter_tables_128[j](data, 1);
287     Z2 = filter_tables_128[j](data, 2);
288 #else
289     Z0 = filter_table(data, 0, Param);
290     Z1 = filter_table(data, 1, Param);
291     Z2 = filter_table(data, 2, Param);
292 #endif
293 
294     Z = Param->Coef[1] + Z2 - sub_const;
295     Param->Coef[1] = Param->Coef[0] + Z1;
296     Param->Coef[0] = Z0;
297 
298     OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
299     OldIn = Z;
300     OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
301 
302     Z = OldZ * volume;
303     Z = RoundDiv(Z, div_const);
304     Z = SaturaLH(Z, -32700, 32700);
305 
306     dataOut[data_out_index] = Z;
307     data += data_inc;
308   }
309 
310   Param->OldOut = OldOut;
311   Param->OldIn = OldIn;
312   Param->OldZ = OldZ;
313 }
314