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 }