xref: /btstack/src/classic/btstack_sbc_plc.c (revision ddaf35c7579ab4463891f4e60cea40b4398b142c)
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 /*
39  * btstack_sbc_plc.c
40  *
41  */
42 
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <math.h>
50 
51 #include "btstack_sbc_plc.h"
52 
53 static uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
54 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
55 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
56 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
57 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
58 
59 /* Raised COSine table for OLA */
60 static float rcos[SBC_OLAL] = {
61     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
62     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
63     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
64     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
65 
66 static float CrossCorrelation(int16_t *x, int16_t *y){
67     float num = 0;
68     float den = 0;
69     float x2 = 0;
70     float y2 = 0;
71     int   m;
72     for (m=0;m<SBC_M;m++){
73         num+=((float)x[m])*y[m];
74         x2+=((float)x[m])*x[m];
75         y2+=((float)y[m])*y[m];
76     }
77     den = (float)sqrt(x2*y2);
78     return num/den;
79 }
80 
81 static int PatternMatch(int16_t *y){
82     float maxCn = -999999.0;  /* large negative number */
83     int   bestmatch = 0;
84     float Cn;
85     int   n;
86     for (n=0;n<SBC_N;n++){
87         Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M] /* x */, &y[n]);
88         if (Cn>maxCn){
89             bestmatch=n;
90             maxCn = Cn;
91         }
92     }
93     return bestmatch;
94 }
95 
96 
97 static float AmplitudeMatch(int16_t *y, int16_t bestmatch) {
98     int   i;
99     float sumx = 0;
100     float sumy = 0.000001f;
101     float sf;
102 
103     for (i=0;i<SBC_FS;i++){
104         sumx += abs(y[SBC_LHIST-SBC_FS+i]);
105         sumy += abs(y[bestmatch+i]);
106     }
107     sf = sumx/sumy;
108     /* This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts */
109     if (sf<0.75f) sf=0.75f;
110     if (sf>1.2f) sf=1.2f;
111     return sf;
112 }
113 
114 static int16_t crop_to_int16(float val){
115     float croped_val = val;
116     if (croped_val > 32767.0)  croped_val= 32767.0;
117     if (croped_val < -32768.0) croped_val=-32768.0;
118     return (int16_t) croped_val;
119 }
120 
121 uint8_t * btstack_sbc_plc_zero_signal_frame(void){
122     return (uint8_t *)&indices0;
123 }
124 
125 void btstack_sbc_plc_init(btstack_sbc_plc_state_t *plc_state){
126     plc_state->nbf=0;
127     plc_state->bestlag=0;
128     memset(plc_state->hist,0,sizeof(plc_state->hist));
129 }
130 
131 void btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t *plc_state, int16_t *ZIRbuf, int16_t *out){
132     float val;
133     int   i = 0;
134     float sf = 1;
135 
136     plc_state->nbf++;
137 
138     if (plc_state->nbf==1){
139         /* Perform pattern matching to find where to replicate */
140         plc_state->bestlag = PatternMatch(plc_state->hist);
141         /* the replication begins after the template match */
142         plc_state->bestlag += SBC_M;
143 
144         /* Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet */
145         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
146         for (i=0;i<SBC_OLAL;i++){
147             float left  = ZIRbuf[i];
148             float right = sf*plc_state->hist[plc_state->bestlag+i];
149             val = left*rcos[i] + right*rcos[SBC_OLAL-1-i];
150             plc_state->hist[SBC_LHIST+i] = crop_to_int16(val);
151         }
152 
153         for (;i<SBC_FS;i++){
154             val = sf*plc_state->hist[plc_state->bestlag+i];
155             plc_state->hist[SBC_LHIST+i] = crop_to_int16(val);
156         }
157 
158         for (;i<SBC_FS+SBC_OLAL;i++){
159             float left  = sf*plc_state->hist[plc_state->bestlag+i];
160             float right = plc_state->hist[plc_state->bestlag+i];
161             val = left*rcos[i-SBC_FS]+right*rcos[SBC_FS+SBC_OLAL-1-i];
162             plc_state->hist[SBC_LHIST+i] = crop_to_int16(val);
163         }
164 
165         for (;i<SBC_FS+SBC_RT+SBC_OLAL;i++){
166             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
167         }
168 
169     } else {
170         for (i=0;i<SBC_FS+SBC_RT+SBC_OLAL;i++){
171             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
172         }
173     }
174     for (i=0;i<SBC_FS;i++){
175         out[i] = plc_state->hist[SBC_LHIST+i];
176     }
177 
178     /* shift the history buffer */
179     for (i=0;i<SBC_LHIST+SBC_RT+SBC_OLAL;i++){
180         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
181     }
182 
183 }
184 
185 void btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t *plc_state, int16_t *in, int16_t *out){
186     float val;
187     int i = 0;
188     if (plc_state->nbf>0){
189         for (i=0;i<SBC_RT;i++){
190             out[i] = plc_state->hist[SBC_LHIST+i];
191         }
192 
193         for (;i<SBC_RT+SBC_OLAL;i++){
194             float left  = plc_state->hist[SBC_LHIST+i];
195             float right = in[i];
196             val = left*rcos[i-SBC_RT] + right*rcos[SBC_OLAL-1-i+SBC_RT];
197             out[i] = (int16_t)val;
198         }
199     }
200     for (;i<SBC_FS;i++){
201         out[i] = in[i];
202     }
203 
204     /*Copy the output to the history buffer */
205     for (i=0;i<SBC_FS;i++){
206         plc_state->hist[SBC_LHIST+i] = out[i];
207     }
208     /* shift the history buffer */
209     for (i=0;i<SBC_LHIST;i++){
210         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
211     }
212 
213     plc_state->nbf=0;
214 }
215