xref: /btstack/src/classic/btstack_cvsd_plc.c (revision de95d3c92868e277b02b54059719ec1e7925ec82)
1 /*
2  * Copyright (C) 2016 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define __BTSTACK_FILE__ "btstack_cvsd_plc.c"
39 
40 /*
41  * btstack_sbc_plc.c
42  *
43  */
44 
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 
50 #include "btstack_cvsd_plc.h"
51 #include "btstack_debug.h"
52 
53 // static float rcos[CVSD_OLAL] = {
54 //     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
55 //     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
56 //     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
57 //     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
58 
59 static float rcos[CVSD_OLAL] = {
60     0.99148655f,0.92510857f,
61     0.80131732f,0.63683150f,
62     0.45386582f,0.27713082f,
63     0.13049554f,0.03376389f};
64 
65 float btstack_cvsd_plc_rcos(int index){
66     if (index > CVSD_OLAL) return 0;
67     return rcos[index];
68 }
69 // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
70 // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation
71 static float sqrt3(const float x){
72     union {
73         int i;
74         float x;
75     } u;
76     u.x = x;
77     u.i = (1<<29) + (u.i >> 1) - (1<<22);
78 
79     // Two Babylonian Steps (simplified from:)
80     // u.x = 0.5f * (u.x + x/u.x);
81     // u.x = 0.5f * (u.x + x/u.x);
82     u.x =       u.x + x/u.x;
83     u.x = 0.25f*u.x + x/u.x;
84 
85     return u.x;
86 }
87 
88 static float btstack_cvsd_plc_absolute(float x){
89      if (x < 0) x = -x;
90      return x;
91 }
92 
93 static float btstack_cvsd_plc_cross_correlation(BTSTACK_CVSD_PLC_SAMPLE_FORMAT *x, BTSTACK_CVSD_PLC_SAMPLE_FORMAT *y){
94     float num = 0;
95     float den = 0;
96     float x2 = 0;
97     float y2 = 0;
98     int   m;
99     for (m=0;m<CVSD_M;m++){
100         num+=((float)x[m])*y[m];
101         x2+=((float)x[m])*x[m];
102         y2+=((float)y[m])*y[m];
103     }
104     den = (float)sqrt3(x2*y2);
105     return num/den;
106 }
107 
108 int btstack_cvsd_plc_pattern_match(BTSTACK_CVSD_PLC_SAMPLE_FORMAT *y){
109     float maxCn = -999999.0;  // large negative number
110     int   bestmatch = 0;
111     float Cn;
112     int   n;
113     for (n=0;n<CVSD_N;n++){
114         Cn = btstack_cvsd_plc_cross_correlation(&y[CVSD_LHIST-CVSD_M], &y[n]);
115         if (Cn>maxCn){
116             bestmatch=n;
117             maxCn = Cn;
118         }
119     }
120     return bestmatch;
121 }
122 
123 float btstack_cvsd_plc_amplitude_match(btstack_cvsd_plc_state_t *plc_state, uint16_t num_samples, BTSTACK_CVSD_PLC_SAMPLE_FORMAT *y, BTSTACK_CVSD_PLC_SAMPLE_FORMAT bestmatch){
124     int   i;
125     float sumx = 0;
126     float sumy = 0.000001f;
127     float sf;
128 
129     for (i=0;i<num_samples;i++){
130         sumx += btstack_cvsd_plc_absolute(y[CVSD_LHIST-num_samples+i]);
131         sumy += btstack_cvsd_plc_absolute(y[bestmatch+i]);
132     }
133     sf = sumx/sumy;
134     // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
135     if (sf<0.75f) sf=0.75f;
136     if (sf>1.0) sf=1.0f;
137     return sf;
138 }
139 
140 BTSTACK_CVSD_PLC_SAMPLE_FORMAT btstack_cvsd_plc_crop_sample(float val){
141     float croped_val = val;
142     if (croped_val > 32767.0)  croped_val= 32767.0;
143     if (croped_val < -32768.0) croped_val=-32768.0;
144     return (BTSTACK_CVSD_PLC_SAMPLE_FORMAT) croped_val;
145 }
146 
147 void btstack_cvsd_plc_init(btstack_cvsd_plc_state_t *plc_state){
148     memset(plc_state, 0, sizeof(btstack_cvsd_plc_state_t));
149 }
150 
151 void btstack_cvsd_plc_bad_frame(btstack_cvsd_plc_state_t *plc_state, uint16_t num_samples, BTSTACK_CVSD_PLC_SAMPLE_FORMAT *out){
152     float val;
153     int   i = 0;
154     float sf = 1;
155     plc_state->nbf++;
156 
157     if (plc_state->max_consecutive_bad_frames_nr < plc_state->nbf){
158         plc_state->max_consecutive_bad_frames_nr = plc_state->nbf;
159     }
160 
161     // plc_state->cvsd_fs = CVSD_FS_MAX;
162     if (plc_state->nbf==1){
163         // Perform pattern matching to find where to replicate
164         plc_state->bestlag = btstack_cvsd_plc_pattern_match(plc_state->hist);
165         // the replication begins after the template match
166         plc_state->bestlag += CVSD_M;
167 
168         // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
169         sf = btstack_cvsd_plc_amplitude_match(plc_state, num_samples, plc_state->hist, plc_state->bestlag);
170         for (i=0;i<CVSD_OLAL;i++){
171             val = sf*plc_state->hist[plc_state->bestlag+i];
172             plc_state->hist[CVSD_LHIST+i] = btstack_cvsd_plc_crop_sample(val);
173         }
174 
175         for (;i<num_samples;i++){
176             val = sf*plc_state->hist[plc_state->bestlag+i];
177             plc_state->hist[CVSD_LHIST+i] = btstack_cvsd_plc_crop_sample(val);
178         }
179 
180         for (;i<num_samples+CVSD_OLAL;i++){
181             float left  = sf*plc_state->hist[plc_state->bestlag+i];
182             float right = plc_state->hist[plc_state->bestlag+i];
183             val = left*rcos[i-num_samples] + right*rcos[CVSD_OLAL-1-i+num_samples];
184             plc_state->hist[CVSD_LHIST+i] = btstack_cvsd_plc_crop_sample(val);
185         }
186 
187         for (;i<num_samples+CVSD_RT+CVSD_OLAL;i++){
188             plc_state->hist[CVSD_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
189         }
190     } else {
191         for (;i<num_samples+CVSD_RT+CVSD_OLAL;i++){
192             plc_state->hist[CVSD_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
193         }
194     }
195 
196     for (i=0;i<num_samples;i++){
197         out[i] = plc_state->hist[CVSD_LHIST+i];
198     }
199 
200     // shift the history buffer
201     for (i=0;i<CVSD_LHIST+CVSD_RT+CVSD_OLAL;i++){
202         plc_state->hist[i] = plc_state->hist[i+num_samples];
203     }
204 }
205 
206 void btstack_cvsd_plc_good_frame(btstack_cvsd_plc_state_t *plc_state, uint16_t num_samples, BTSTACK_CVSD_PLC_SAMPLE_FORMAT *in, BTSTACK_CVSD_PLC_SAMPLE_FORMAT *out){
207     float val;
208     int i = 0;
209     if (plc_state->nbf>0){
210         for (i=0;i<CVSD_RT;i++){
211             out[i] = plc_state->hist[CVSD_LHIST+i];
212         }
213 
214         for (i=CVSD_RT;i<CVSD_RT+CVSD_OLAL;i++){
215             float left  = plc_state->hist[CVSD_LHIST+i];
216             float right = in[i];
217             val = left * rcos[i-CVSD_RT] + right *rcos[CVSD_OLAL+CVSD_RT-1-i];
218             out[i] = (BTSTACK_CVSD_PLC_SAMPLE_FORMAT)val;
219         }
220     }
221 
222     for (;i<num_samples;i++){
223         out[i] = in[i];
224     }
225     // Copy the output to the history buffer
226     for (i=0;i<num_samples;i++){
227         plc_state->hist[CVSD_LHIST+i] = out[i];
228     }
229     // shift the history buffer
230     for (i=0;i<CVSD_LHIST;i++){
231         plc_state->hist[i] = plc_state->hist[i+num_samples];
232     }
233     plc_state->nbf=0;
234 }
235 
236 static int count_equal_samples(BTSTACK_CVSD_PLC_SAMPLE_FORMAT * packet, uint16_t size){
237     int count = 0;
238     int temp_count = 1;
239     int i;
240     for (i = 0; i < size-1; i++){
241         if (packet[i] == packet[i+1]){
242             temp_count++;
243             continue;
244         }
245         if (count < temp_count){
246             count = temp_count;
247         }
248         temp_count = 1;
249     }
250     if (temp_count > count + 1){
251         count = temp_count;
252     }
253     return count;
254 }
255 
256 static int count_zeros(BTSTACK_CVSD_PLC_SAMPLE_FORMAT * frame, uint16_t size){
257     int nr_zeros = 0;
258     int i;
259     for (i = 0; i < size-1; i++){
260         if (frame[i] == 0){
261             nr_zeros++;
262         }
263     }
264     return nr_zeros;
265 }
266 
267 // note: a zero_frame is currently also a 'bad_frame'
268 static int zero_frame(BTSTACK_CVSD_PLC_SAMPLE_FORMAT * frame, uint16_t size){
269     return count_zeros(frame, size) > (size/2);
270 }
271 
272 // more than half the samples are the same -> bad frame
273 static int bad_frame(btstack_cvsd_plc_state_t *plc_state, BTSTACK_CVSD_PLC_SAMPLE_FORMAT * frame, uint16_t size){
274     return count_equal_samples(frame, size) > size / 2;
275 }
276 
277 
278 void btstack_cvsd_plc_process_data(btstack_cvsd_plc_state_t * plc_state, BTSTACK_CVSD_PLC_SAMPLE_FORMAT * in, uint16_t num_samples, BTSTACK_CVSD_PLC_SAMPLE_FORMAT * out){
279     if (num_samples == 0) return;
280 
281     plc_state->frame_count++;
282 
283     int is_zero_frame = zero_frame(in, num_samples);
284     int is_bad_frame  = bad_frame(plc_state, in, num_samples);
285 
286     if (is_bad_frame){
287         memcpy(out, in, num_samples * 2);
288         if (plc_state->good_samples > CVSD_LHIST){
289             btstack_cvsd_plc_bad_frame(plc_state, num_samples, out);
290             if (is_zero_frame){
291                 plc_state->zero_frames_nr++;
292             } else {
293                 plc_state->bad_frames_nr++;
294             }
295         } else {
296             memset(out, 0, num_samples * 2);
297         }
298     } else {
299         btstack_cvsd_plc_good_frame(plc_state, num_samples, in, out);
300         plc_state->good_frames_nr++;
301         if (plc_state->good_frames_nr == 1){
302             log_info("First good frame at index %d\n", plc_state->frame_count-1);
303         }
304         plc_state->good_samples += num_samples;
305     }
306 }
307 
308 void btstack_cvsd_dump_statistics(btstack_cvsd_plc_state_t * state){
309     log_info("Good frames: %d\n", state->good_frames_nr);
310     log_info("Bad frames: %d\n", state->bad_frames_nr);
311     log_info("Zero frames: %d\n", state->zero_frames_nr);
312     log_info("Max Consecutive bad frames: %d\n", state->max_consecutive_bad_frames_nr);
313 }
314