xref: /btstack/src/classic/btstack_sbc_plc.c (revision 4e074f72dfc9d6dbd14a53f67cd879195210e6b8)
1*4e074f72SMilanka Ringwald /*
2*4e074f72SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3*4e074f72SMilanka Ringwald  *
4*4e074f72SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*4e074f72SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*4e074f72SMilanka Ringwald  * are met:
7*4e074f72SMilanka Ringwald  *
8*4e074f72SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*4e074f72SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*4e074f72SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*4e074f72SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*4e074f72SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*4e074f72SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*4e074f72SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*4e074f72SMilanka Ringwald  *    from this software without specific prior written permission.
16*4e074f72SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*4e074f72SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*4e074f72SMilanka Ringwald  *    monetary gain.
19*4e074f72SMilanka Ringwald  *
20*4e074f72SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*4e074f72SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*4e074f72SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*4e074f72SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*4e074f72SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*4e074f72SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*4e074f72SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*4e074f72SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*4e074f72SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*4e074f72SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*4e074f72SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*4e074f72SMilanka Ringwald  * SUCH DAMAGE.
32*4e074f72SMilanka Ringwald  *
33*4e074f72SMilanka Ringwald  * Please inquire about commercial licensing options at
34*4e074f72SMilanka Ringwald  * [email protected]
35*4e074f72SMilanka Ringwald  *
36*4e074f72SMilanka Ringwald  */
37*4e074f72SMilanka Ringwald 
38*4e074f72SMilanka Ringwald /*
39*4e074f72SMilanka Ringwald  * sbc_plc.c
40*4e074f72SMilanka Ringwald  *
41*4e074f72SMilanka Ringwald  */
42*4e074f72SMilanka Ringwald 
43*4e074f72SMilanka Ringwald #include <stdint.h>
44*4e074f72SMilanka Ringwald #include <stdio.h>
45*4e074f72SMilanka Ringwald #include <stdlib.h>
46*4e074f72SMilanka Ringwald #include <string.h>
47*4e074f72SMilanka Ringwald #include <fcntl.h>
48*4e074f72SMilanka Ringwald #include <unistd.h>
49*4e074f72SMilanka Ringwald #include <math.h>
50*4e074f72SMilanka Ringwald 
51*4e074f72SMilanka Ringwald #include "btstack_sbc_plc.h"
52*4e074f72SMilanka Ringwald 
53*4e074f72SMilanka Ringwald static uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
54*4e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
55*4e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
56*4e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
57*4e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
58*4e074f72SMilanka Ringwald 
59*4e074f72SMilanka Ringwald /* Raised COSine table for OLA */
60*4e074f72SMilanka Ringwald static float rcos[OLAL] = {
61*4e074f72SMilanka Ringwald     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
62*4e074f72SMilanka Ringwald     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
63*4e074f72SMilanka Ringwald     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
64*4e074f72SMilanka Ringwald     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
65*4e074f72SMilanka Ringwald 
66*4e074f72SMilanka Ringwald static float CrossCorrelation(int16_t *x, int16_t *y);
67*4e074f72SMilanka Ringwald static int PatternMatch(int16_t *y);
68*4e074f72SMilanka Ringwald static float AmplitudeMatch(int16_t *y, int16_t bestmatch);
69*4e074f72SMilanka Ringwald 
70*4e074f72SMilanka Ringwald uint8_t * sbc_plc_zero_signal_frame(void){
71*4e074f72SMilanka Ringwald     return (uint8_t *)&indices0;
72*4e074f72SMilanka Ringwald }
73*4e074f72SMilanka Ringwald 
74*4e074f72SMilanka Ringwald void sbc_plc_init(sbc_plc_state_t *plc_state){
75*4e074f72SMilanka Ringwald     int i;
76*4e074f72SMilanka Ringwald     plc_state->nbf=0;
77*4e074f72SMilanka Ringwald     plc_state->bestlag=0;
78*4e074f72SMilanka Ringwald     for (i=0;i<LHIST+SBCRT;i++){
79*4e074f72SMilanka Ringwald         plc_state->hist[i] = 0;
80*4e074f72SMilanka Ringwald     }
81*4e074f72SMilanka Ringwald 
82*4e074f72SMilanka Ringwald }
83*4e074f72SMilanka Ringwald 
84*4e074f72SMilanka Ringwald void sbc_plc_bad_frame(sbc_plc_state_t *plc_state, int16_t *ZIRbuf, int16_t *out){
85*4e074f72SMilanka Ringwald     int   i;
86*4e074f72SMilanka Ringwald     float val;
87*4e074f72SMilanka Ringwald     float sf;
88*4e074f72SMilanka Ringwald     plc_state->nbf++;
89*4e074f72SMilanka Ringwald     sf=1.0f;
90*4e074f72SMilanka Ringwald 
91*4e074f72SMilanka Ringwald     i=0;
92*4e074f72SMilanka Ringwald     if (plc_state->nbf==1){
93*4e074f72SMilanka Ringwald         /* Perform pattern matching to find where to replicate */
94*4e074f72SMilanka Ringwald         plc_state->bestlag = PatternMatch(plc_state->hist);
95*4e074f72SMilanka Ringwald         /* the replication begins after the template match */
96*4e074f72SMilanka Ringwald         plc_state->bestlag += M;
97*4e074f72SMilanka Ringwald 
98*4e074f72SMilanka Ringwald         /* Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet */
99*4e074f72SMilanka Ringwald         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
100*4e074f72SMilanka Ringwald         for (i=0;i<OLAL;i++){
101*4e074f72SMilanka Ringwald             val = ZIRbuf[i]*rcos[i] + sf*plc_state->hist[plc_state->bestlag+i]*rcos[OLAL-i-1];
102*4e074f72SMilanka Ringwald             if (val >  32767.0) val= 32767.0;
103*4e074f72SMilanka Ringwald             if (val < -32768.0) val=-32768.0;
104*4e074f72SMilanka Ringwald              plc_state->hist[LHIST+i] = (int16_t)val;
105*4e074f72SMilanka Ringwald         }
106*4e074f72SMilanka Ringwald 
107*4e074f72SMilanka Ringwald         for (;i<FS;i++){
108*4e074f72SMilanka Ringwald             val = sf*plc_state->hist[plc_state->bestlag+i]; if (val > 32767.0) val= 32767.0;
109*4e074f72SMilanka Ringwald             if (val < -32768.0) val=-32768.0; plc_state->hist[LHIST+i] = (int16_t)val;
110*4e074f72SMilanka Ringwald         }
111*4e074f72SMilanka Ringwald 
112*4e074f72SMilanka Ringwald         for (;i<FS+OLAL;i++){
113*4e074f72SMilanka Ringwald             val = sf*plc_state->hist[plc_state->bestlag+i]*rcos[i-FS]+plc_state->hist[plc_state->bestlag+i]*rcos[OLAL-1-i+FS];
114*4e074f72SMilanka Ringwald             if (val >  32767.0) val= 32767.0;
115*4e074f72SMilanka Ringwald             if (val < -32768.0) val=-32768.0;
116*4e074f72SMilanka Ringwald             plc_state->hist[LHIST+i] = (int16_t)val;
117*4e074f72SMilanka Ringwald         }
118*4e074f72SMilanka Ringwald 
119*4e074f72SMilanka Ringwald         for (;i<FS+SBCRT+OLAL;i++)
120*4e074f72SMilanka Ringwald             plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
121*4e074f72SMilanka Ringwald     } else {
122*4e074f72SMilanka Ringwald         for (;i<FS;i++)
123*4e074f72SMilanka Ringwald             plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
124*4e074f72SMilanka Ringwald         for (;i<FS+SBCRT+OLAL;i++)
125*4e074f72SMilanka Ringwald             plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
126*4e074f72SMilanka Ringwald     }
127*4e074f72SMilanka Ringwald     for (i=0;i<FS;i++)
128*4e074f72SMilanka Ringwald         out[i] = plc_state->hist[LHIST+i];
129*4e074f72SMilanka Ringwald 
130*4e074f72SMilanka Ringwald    /* shift the history buffer */
131*4e074f72SMilanka Ringwald    for (i=0;i<LHIST+SBCRT+OLAL;i++)
132*4e074f72SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+FS];
133*4e074f72SMilanka Ringwald 
134*4e074f72SMilanka Ringwald }
135*4e074f72SMilanka Ringwald 
136*4e074f72SMilanka Ringwald void sbc_plc_good_frame(sbc_plc_state_t *plc_state, int16_t *in, int16_t *out){
137*4e074f72SMilanka Ringwald     int i;
138*4e074f72SMilanka Ringwald     i=0;
139*4e074f72SMilanka Ringwald     if (plc_state->nbf>0){
140*4e074f72SMilanka Ringwald         for (i=0;i<SBCRT;i++)
141*4e074f72SMilanka Ringwald             out[i] = plc_state->hist[LHIST+i];
142*4e074f72SMilanka Ringwald         for (;i<SBCRT+OLAL;i++)
143*4e074f72SMilanka Ringwald             out[i] = (int16_t)(plc_state->hist[LHIST+i]*rcos[i-SBCRT] + in[i]*rcos[OLAL-1-i+SBCRT]);
144*4e074f72SMilanka Ringwald     }
145*4e074f72SMilanka Ringwald     for (;i<FS;i++)
146*4e074f72SMilanka Ringwald         out[i] = in[i];
147*4e074f72SMilanka Ringwald     /*Copy the output to the history buffer */
148*4e074f72SMilanka Ringwald     for (i=0;i<FS;i++)
149*4e074f72SMilanka Ringwald         plc_state->hist[LHIST+i] = out[i];
150*4e074f72SMilanka Ringwald     /* shift the history buffer */
151*4e074f72SMilanka Ringwald     for (i=0;i<LHIST;i++)
152*4e074f72SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+FS];
153*4e074f72SMilanka Ringwald     plc_state->nbf=0;
154*4e074f72SMilanka Ringwald }
155*4e074f72SMilanka Ringwald 
156*4e074f72SMilanka Ringwald 
157*4e074f72SMilanka Ringwald float CrossCorrelation(int16_t *x, int16_t *y){
158*4e074f72SMilanka Ringwald     int   m;
159*4e074f72SMilanka Ringwald     float num;
160*4e074f72SMilanka Ringwald     float den;
161*4e074f72SMilanka Ringwald     float Cn;
162*4e074f72SMilanka Ringwald     float x2, y2;
163*4e074f72SMilanka Ringwald     num=0;
164*4e074f72SMilanka Ringwald     den=0;
165*4e074f72SMilanka Ringwald     x2=0.0;
166*4e074f72SMilanka Ringwald     y2=0.0;
167*4e074f72SMilanka Ringwald     for (m=0;m<M;m++){
168*4e074f72SMilanka Ringwald         num+=((float)x[m])*y[m];
169*4e074f72SMilanka Ringwald         x2+=((float)x[m])*x[m];
170*4e074f72SMilanka Ringwald         y2+=((float)y[m])*y[m];
171*4e074f72SMilanka Ringwald     }
172*4e074f72SMilanka Ringwald     den = (float)sqrt(x2*y2);
173*4e074f72SMilanka Ringwald     Cn = num/den;
174*4e074f72SMilanka Ringwald     return(Cn);
175*4e074f72SMilanka Ringwald }
176*4e074f72SMilanka Ringwald 
177*4e074f72SMilanka Ringwald int PatternMatch(int16_t *y){
178*4e074f72SMilanka Ringwald     int   n;
179*4e074f72SMilanka Ringwald     float maxCn;
180*4e074f72SMilanka Ringwald     float Cn;
181*4e074f72SMilanka Ringwald     int   bestmatch;
182*4e074f72SMilanka Ringwald     maxCn=-999999.0;  /* large negative number */
183*4e074f72SMilanka Ringwald     bestmatch=0;
184*4e074f72SMilanka Ringwald     for (n=0;n<N;n++){
185*4e074f72SMilanka Ringwald         Cn = CrossCorrelation(&y[LHIST-M] /* x */, &y[n]);
186*4e074f72SMilanka Ringwald         if (Cn>maxCn){
187*4e074f72SMilanka Ringwald             bestmatch=n;
188*4e074f72SMilanka Ringwald             maxCn = Cn;
189*4e074f72SMilanka Ringwald         }
190*4e074f72SMilanka Ringwald     }
191*4e074f72SMilanka Ringwald     return(bestmatch);
192*4e074f72SMilanka Ringwald }
193*4e074f72SMilanka Ringwald 
194*4e074f72SMilanka Ringwald 
195*4e074f72SMilanka Ringwald float AmplitudeMatch(int16_t *y, int16_t bestmatch) {
196*4e074f72SMilanka Ringwald     int   i;
197*4e074f72SMilanka Ringwald     float sumx;
198*4e074f72SMilanka Ringwald     float sumy;
199*4e074f72SMilanka Ringwald     float sf;
200*4e074f72SMilanka Ringwald     sumx = 0.0;
201*4e074f72SMilanka Ringwald     sumy = 0.000001f;
202*4e074f72SMilanka Ringwald     for (i=0;i<FS;i++){
203*4e074f72SMilanka Ringwald         sumx += abs(y[LHIST-FS+i]);
204*4e074f72SMilanka Ringwald         sumy += abs(y[bestmatch+i]);
205*4e074f72SMilanka Ringwald     }
206*4e074f72SMilanka Ringwald     sf = sumx/sumy;
207*4e074f72SMilanka Ringwald     /* This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts */
208*4e074f72SMilanka Ringwald     if (sf<0.75f) sf=0.75f;
209*4e074f72SMilanka Ringwald     if (sf>1.2f) sf=1.2f;
210*4e074f72SMilanka Ringwald     return(sf);
211*4e074f72SMilanka Ringwald }