1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "common/bt_target.h"
12 #include "sbc_plc.h"
13 
14 #if (PLC_INCLUDED == TRUE)
15 /* msbc */
16 static const uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
17 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
18 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
19 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
20 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
21 
22 
23 /* 8 kHZ */
24 static const int16_t indices0_pcm[] = {
25   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
26   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
27   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
28   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
29   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
30   0,   0,   0,   0,   0,   0,   0,   0,   0,   0};
31 
32 /* Raised COSine table for OLA */
33 /* 16 kHZ */
34 static float rcos[SBC_OLAL] = {
35     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
36     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
37     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
38     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
39 
40 // /* 8 kHZ */
41 // static float rcos[SBC_OLAL] = {
42 //     0.96984631f,0.88302222f,      0.75f,0.58682409f,
43 //     0.41317591f,      0.25f,0.11697778f,0.09015369f};
44 
45 
SqrtByCarmack(const float x)46 static float SqrtByCarmack(const float x){
47     union {
48         int i;
49         float y;
50     } float_int;
51 
52     float x2;
53     const float threehalfs = 1.5f;
54 
55     x2 = x * 0.5f;
56     float_int.y = x;
57 
58     float_int.i = 0x5f375a86 - (float_int.i >> 1);
59     float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
60     // float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
61     // float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
62 
63     return (x * float_int.y);
64 }
65 
absolute(float x)66 static float absolute(float x){
67     if (x < 0) {
68         x = -x;
69     }
70 
71     return x;
72 }
73 
74 /**
75  * Compute the cross correlation according to Eq. (4) of Goodman
76  * paper, except that the true correlation is used. His formula
77  * seems to be incorrect.
78  *
79  * @param  x pointer to x input vector
80  * @param  y pointer to y input vector
81  *
82  * @return   value containing the cross-correlation of x and y
83  */
CrossCorrelation(int16_t * x,int16_t * y)84 static float CrossCorrelation(int16_t *x, int16_t *y){
85     int   m;
86     float num = 0;
87     float den = 0;
88     float x2 = 0;
89     float y2 = 0;
90 
91     for (m = 0; m < SBC_M; m++) {
92         num += ((float)x[m]) * y[m];
93         x2 += ((float)x[m]) * x[m];
94         y2 += ((float)y[m]) * y[m];
95     }
96     den = (float)SqrtByCarmack(x2 * y2);
97     return num / den;
98 }
99 
100 /**
101  * Perform pattern matching to find the match of template with the
102  * history buffer according to Section B of Goodman paper.
103  *
104  * @param  y pointer to history buffer
105  *
106  * @return   the lag corresponding to the best match. The lag is
107  *           with respect to the beginning of the history buffer.
108  *
109  */
PatternMatch(int16_t * y)110 static int PatternMatch(int16_t *y){
111     int   n;
112     float maxCn = -999999.0;  // large negative number
113     float Cn;
114     int   bestmatch = 0;
115 
116     for (n = 0; n < SBC_N; n++){
117         Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]);
118         if (Cn > maxCn){
119             bestmatch = n;
120             maxCn = Cn;
121         }
122     }
123     return bestmatch;
124 }
125 
126 /**
127  * Perform amplitude matching using mean-absolute-value according
128  * to Goodman paper.
129  *
130  * @param  y         pointer to history buffer
131  * @param  bestmatch value of the lag to the best match
132  *
133  * @return           scale factor
134  */
AmplitudeMatch(int16_t * y,int16_t bestmatch)135 static float AmplitudeMatch(int16_t *y, int16_t bestmatch) {
136     int   i;
137     float sumx = 0;
138     float sumy = 0.000001f;
139     float sf;
140 
141     for (i = 0; i < SBC_FS; i++){
142         sumx += absolute(y[SBC_LHIST - SBC_FS + i]);
143         sumy += absolute(y[bestmatch + i]);
144     }
145     sf = sumx / sumy;
146     // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
147     if (sf < 0.75f) {
148         sf = 0.75f;
149     }
150     if (sf > 1.2f) {
151         sf = 1.2f;
152     }
153     return sf;
154 }
155 
crop_sample(float val)156 static int16_t crop_sample(float val){
157     float croped_val = val;
158     if (croped_val > 32767.0)  croped_val= 32767.0;
159     if (croped_val < -32768.0) croped_val=-32768.0;
160     return (int16_t) croped_val;
161 }
162 
163 /**
164  * Get a zero signal eSCO frame
165  * @return  pointer to data buffer
166  */
sbc_plc_zero_signal_frame(void)167 uint8_t * sbc_plc_zero_signal_frame(void){
168     return (uint8_t *)&indices0;
169 }
170 
171 /**
172  * Get a zero signal eSCO pcm frame
173  * @return  pointer to data buffer
174  */
sbc_plc_zero_signal_frame_pcm(void)175 int16_t * sbc_plc_zero_signal_frame_pcm(void){
176     return (int16_t *)&indices0_pcm;
177 }
178 
179 /**
180  * Perform PLC initialization of memory vectors.
181  *
182  * @param plc_state pointer to PLC state memory
183  */
sbc_plc_init(sbc_plc_state_t * plc_state)184 void sbc_plc_init(sbc_plc_state_t *plc_state){
185     plc_state->nbf=0;
186     plc_state->bestlag=0;
187     memset(plc_state->hist, 0, sizeof(plc_state->hist));
188 }
189 
190 /**
191  * Perform PLC deinitialization of memory vectors.
192  *
193  * @param plc_state pointer to PLC state memory
194  */
sbc_plc_deinit(sbc_plc_state_t * plc_state)195 void sbc_plc_deinit(sbc_plc_state_t *plc_state){
196     plc_state->nbf=0;
197     plc_state->bestlag=0;
198     memset(plc_state->hist, 0, sizeof(plc_state->hist));
199 }
200 
201 /**
202  * Perform bad frame processing.
203  *
204  * @param plc_state pointer to PLC state memory
205  * @param ZIRbuf    pointer to the ZIR response of the SBC decoder
206  * @param out       pointer to the output samples
207  */
sbc_plc_bad_frame(sbc_plc_state_t * plc_state,int16_t * ZIRbuf,int16_t * out)208 void sbc_plc_bad_frame(sbc_plc_state_t *plc_state, int16_t *ZIRbuf, int16_t *out){
209     int   i = 0;
210     float val;
211     float sf = 1;
212 
213     plc_state->nbf++;
214 
215     if (plc_state->nbf == 1){
216         // Perform pattern matching to find where to replicate
217         plc_state->bestlag = PatternMatch(plc_state->hist);
218         // the replication begins after the template match
219         plc_state->bestlag += SBC_M;
220 
221         // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
222         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
223 
224         for (i = 0; i < SBC_OLAL; i++){
225             val = ZIRbuf[i] * rcos[i]
226                 + sf * plc_state->hist[plc_state->bestlag + i] * rcos[SBC_OLAL - i - 1];
227             plc_state->hist[SBC_LHIST + i] = crop_sample(val);
228         }
229 
230         for (; i < SBC_FS; i++){
231             val = sf*plc_state->hist[plc_state->bestlag + i];
232             plc_state->hist[SBC_LHIST + i] = crop_sample(val);
233         }
234 
235         for (; i < SBC_FS + SBC_OLAL; i++){
236             val = sf * plc_state->hist[plc_state->bestlag + i] * rcos[i-SBC_FS]
237                 + plc_state->hist[plc_state->bestlag + i] * rcos[SBC_OLAL - 1 - i + SBC_FS];
238             plc_state->hist[SBC_LHIST + i] = crop_sample(val);
239         }
240 
241         for (; i < SBC_FS + SBC_RT + SBC_OLAL; i++){
242             plc_state->hist[SBC_LHIST + i] = plc_state->hist[plc_state->bestlag + i];
243         }
244     } else {
245         for ( ;i < SBC_FS + SBC_RT + SBC_OLAL; i++){
246             plc_state->hist[SBC_LHIST + i] = plc_state->hist[plc_state->bestlag + i];
247         }
248     }
249 
250     for (i = 0; i < SBC_FS; i++){
251         out[i] = plc_state->hist[SBC_LHIST + i];
252     }
253 
254    // shift the history buffer
255     for (i = 0; i < SBC_LHIST + SBC_RT + SBC_OLAL; i++){
256         plc_state->hist[i] = plc_state->hist[i + SBC_FS];
257     }
258 }
259 
260 /**
261  * Perform good frame processing. Most of the time, this function
262  * just updates history buffers and passes the input to the output,
263  * but in the first good frame after frame loss, it must conceal the
264  * received signal as it reconverges with the true output.
265  *
266  * @param plc_state pointer to PLC state memory
267  * @param in        pointer to the input vector
268  * @param out       pointer to the output samples
269  */
sbc_plc_good_frame(sbc_plc_state_t * plc_state,int16_t * in,int16_t * out)270 void sbc_plc_good_frame(sbc_plc_state_t *plc_state, int16_t *in, int16_t *out){
271     int i = 0;
272 
273     if (plc_state->nbf > 0){
274         for (i = 0; i < SBC_RT; i++){
275             out[i] = plc_state->hist[SBC_LHIST + i];
276         }
277 
278         for (i = SBC_RT; i < SBC_RT + SBC_OLAL; i++){
279             out[i] = (int16_t)(plc_state->hist[SBC_LHIST + i] * rcos[i - SBC_RT] + in[i] * rcos[SBC_OLAL - 1 - i + SBC_RT]);
280         }
281     }
282 
283     for (; i < SBC_FS; i++){
284         out[i] = in[i];
285     }
286     // Copy the output to the history buffer
287     for (i = 0; i < SBC_FS; i++){
288         plc_state->hist[SBC_LHIST + i] = out[i];
289     }
290     // shift the history buffer
291     for (i = 0; i < SBC_LHIST; i++){
292         plc_state->hist[i] = plc_state->hist[i + SBC_FS];
293     }
294 
295     plc_state->nbf = 0;
296 }
297 
298 #endif  ///(PLC_INCLUDED == TRUE)
299