14e074f72SMilanka Ringwald /* 24e074f72SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 34e074f72SMilanka Ringwald * 44e074f72SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 54e074f72SMilanka Ringwald * modification, are permitted provided that the following conditions 64e074f72SMilanka Ringwald * are met: 74e074f72SMilanka Ringwald * 84e074f72SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 94e074f72SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 104e074f72SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 114e074f72SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 124e074f72SMilanka Ringwald * documentation and/or other materials provided with the distribution. 134e074f72SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 144e074f72SMilanka Ringwald * contributors may be used to endorse or promote products derived 154e074f72SMilanka Ringwald * from this software without specific prior written permission. 164e074f72SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 174e074f72SMilanka Ringwald * personal benefit and not for any commercial purpose or for 184e074f72SMilanka Ringwald * monetary gain. 194e074f72SMilanka Ringwald * 204e074f72SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 214e074f72SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 224e074f72SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 234e074f72SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 244e074f72SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 254e074f72SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 264e074f72SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 274e074f72SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 284e074f72SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 294e074f72SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 304e074f72SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314e074f72SMilanka Ringwald * SUCH DAMAGE. 324e074f72SMilanka Ringwald * 334e074f72SMilanka Ringwald * Please inquire about commercial licensing options at 344e074f72SMilanka Ringwald * [email protected] 354e074f72SMilanka Ringwald * 364e074f72SMilanka Ringwald */ 374e074f72SMilanka Ringwald 38*ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "btstack_sbc_plc.c" 39*ab2c6ae4SMatthias Ringwald 404e074f72SMilanka Ringwald /* 41e7a41128SMilanka Ringwald * btstack_sbc_plc.c 424e074f72SMilanka Ringwald * 434e074f72SMilanka Ringwald */ 444e074f72SMilanka Ringwald 454e074f72SMilanka Ringwald #include <stdint.h> 464e074f72SMilanka Ringwald #include <stdio.h> 474e074f72SMilanka Ringwald #include <stdlib.h> 484e074f72SMilanka Ringwald #include <string.h> 494e074f72SMilanka Ringwald 504e074f72SMilanka Ringwald #include "btstack_sbc_plc.h" 514e074f72SMilanka Ringwald 524e4f6f26SMatthias Ringwald #define SAMPLE_FORMAT int16_t 534e4f6f26SMatthias Ringwald 544e074f72SMilanka Ringwald static uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 554e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 564e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 574e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 584e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c}; 594e074f72SMilanka Ringwald 604e074f72SMilanka Ringwald /* Raised COSine table for OLA */ 617e6b1e83SMilanka Ringwald static float rcos[SBC_OLAL] = { 624e074f72SMilanka Ringwald 0.99148655f,0.96623611f,0.92510857f,0.86950446f, 634e074f72SMilanka Ringwald 0.80131732f,0.72286918f,0.63683150f,0.54613418f, 644e074f72SMilanka Ringwald 0.45386582f,0.36316850f,0.27713082f,0.19868268f, 654e074f72SMilanka Ringwald 0.13049554f,0.07489143f,0.03376389f,0.00851345f}; 664e074f72SMilanka Ringwald 6740e1e61cSMilanka Ringwald // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi 6840e1e61cSMilanka Ringwald // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation 6940e1e61cSMilanka Ringwald static float sqrt3(const float x){ 7040e1e61cSMilanka Ringwald union { 7140e1e61cSMilanka Ringwald int i; 7240e1e61cSMilanka Ringwald float x; 7340e1e61cSMilanka Ringwald } u; 7440e1e61cSMilanka Ringwald u.x = x; 7540e1e61cSMilanka Ringwald u.i = (1<<29) + (u.i >> 1) - (1<<22); 7640e1e61cSMilanka Ringwald 7740e1e61cSMilanka Ringwald // Two Babylonian Steps (simplified from:) 7840e1e61cSMilanka Ringwald // u.x = 0.5f * (u.x + x/u.x); 7940e1e61cSMilanka Ringwald // u.x = 0.5f * (u.x + x/u.x); 8040e1e61cSMilanka Ringwald u.x = u.x + x/u.x; 8140e1e61cSMilanka Ringwald u.x = 0.25f*u.x + x/u.x; 8240e1e61cSMilanka Ringwald 8340e1e61cSMilanka Ringwald return u.x; 8440e1e61cSMilanka Ringwald } 8540e1e61cSMilanka Ringwald 8640e1e61cSMilanka Ringwald static float absolute(float x){ 8740e1e61cSMilanka Ringwald if (x < 0) x = -x; 8840e1e61cSMilanka Ringwald return x; 8940e1e61cSMilanka Ringwald } 9040e1e61cSMilanka Ringwald 914e4f6f26SMatthias Ringwald static float CrossCorrelation(SAMPLE_FORMAT *x, SAMPLE_FORMAT *y){ 92c5e169ecSMilanka Ringwald float num = 0; 93c5e169ecSMilanka Ringwald float den = 0; 94c5e169ecSMilanka Ringwald float x2 = 0; 95c5e169ecSMilanka Ringwald float y2 = 0; 96c5e169ecSMilanka Ringwald int m; 97c5e169ecSMilanka Ringwald for (m=0;m<SBC_M;m++){ 98c5e169ecSMilanka Ringwald num+=((float)x[m])*y[m]; 99c5e169ecSMilanka Ringwald x2+=((float)x[m])*x[m]; 100c5e169ecSMilanka Ringwald y2+=((float)y[m])*y[m]; 101c5e169ecSMilanka Ringwald } 10240e1e61cSMilanka Ringwald den = (float)sqrt3(x2*y2); 103c5e169ecSMilanka Ringwald return num/den; 104c5e169ecSMilanka Ringwald } 105c5e169ecSMilanka Ringwald 1064e4f6f26SMatthias Ringwald static int PatternMatch(SAMPLE_FORMAT *y){ 1074e4f6f26SMatthias Ringwald float maxCn = -999999.0; // large negative number 108c5e169ecSMilanka Ringwald int bestmatch = 0; 109c5e169ecSMilanka Ringwald float Cn; 110c5e169ecSMilanka Ringwald int n; 111c5e169ecSMilanka Ringwald for (n=0;n<SBC_N;n++){ 1124e4f6f26SMatthias Ringwald Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]); 113c5e169ecSMilanka Ringwald if (Cn>maxCn){ 114c5e169ecSMilanka Ringwald bestmatch=n; 115c5e169ecSMilanka Ringwald maxCn = Cn; 116c5e169ecSMilanka Ringwald } 117c5e169ecSMilanka Ringwald } 118c5e169ecSMilanka Ringwald return bestmatch; 119c5e169ecSMilanka Ringwald } 120c5e169ecSMilanka Ringwald 1214e4f6f26SMatthias Ringwald static float AmplitudeMatch(SAMPLE_FORMAT *y, SAMPLE_FORMAT bestmatch) { 122c5e169ecSMilanka Ringwald int i; 123c5e169ecSMilanka Ringwald float sumx = 0; 124c5e169ecSMilanka Ringwald float sumy = 0.000001f; 125c5e169ecSMilanka Ringwald float sf; 126c5e169ecSMilanka Ringwald 127c5e169ecSMilanka Ringwald for (i=0;i<SBC_FS;i++){ 12840e1e61cSMilanka Ringwald sumx += absolute(y[SBC_LHIST-SBC_FS+i]); 12940e1e61cSMilanka Ringwald sumy += absolute(y[bestmatch+i]); 130c5e169ecSMilanka Ringwald } 131c5e169ecSMilanka Ringwald sf = sumx/sumy; 1324e4f6f26SMatthias Ringwald // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts 133c5e169ecSMilanka Ringwald if (sf<0.75f) sf=0.75f; 134c5e169ecSMilanka Ringwald if (sf>1.2f) sf=1.2f; 135c5e169ecSMilanka Ringwald return sf; 136c5e169ecSMilanka Ringwald } 1374e074f72SMilanka Ringwald 1384e4f6f26SMatthias Ringwald static SAMPLE_FORMAT crop_sample(float val){ 139250a1e4aSMilanka Ringwald float croped_val = val; 140250a1e4aSMilanka Ringwald if (croped_val > 32767.0) croped_val= 32767.0; 141250a1e4aSMilanka Ringwald if (croped_val < -32768.0) croped_val=-32768.0; 1424e4f6f26SMatthias Ringwald return (SAMPLE_FORMAT) croped_val; 1437e6b1e83SMilanka Ringwald } 1447e6b1e83SMilanka Ringwald 145e7a41128SMilanka Ringwald uint8_t * btstack_sbc_plc_zero_signal_frame(void){ 1464e074f72SMilanka Ringwald return (uint8_t *)&indices0; 1474e074f72SMilanka Ringwald } 1484e074f72SMilanka Ringwald 149e7a41128SMilanka Ringwald void btstack_sbc_plc_init(btstack_sbc_plc_state_t *plc_state){ 1504e074f72SMilanka Ringwald plc_state->nbf=0; 1514e074f72SMilanka Ringwald plc_state->bestlag=0; 152b3f76298SMilanka Ringwald memset(plc_state->hist,0,sizeof(plc_state->hist)); 1534e074f72SMilanka Ringwald } 1544e074f72SMilanka Ringwald 1554e4f6f26SMatthias Ringwald void btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *ZIRbuf, SAMPLE_FORMAT *out){ 1564e074f72SMilanka Ringwald float val; 1577e6b1e83SMilanka Ringwald int i = 0; 1587e6b1e83SMilanka Ringwald float sf = 1; 1597e6b1e83SMilanka Ringwald plc_state->nbf++; 1607e6b1e83SMilanka Ringwald 1614e074f72SMilanka Ringwald if (plc_state->nbf==1){ 1624e4f6f26SMatthias Ringwald // Perform pattern matching to find where to replicate 1634e074f72SMilanka Ringwald plc_state->bestlag = PatternMatch(plc_state->hist); 1644e4f6f26SMatthias Ringwald // the replication begins after the template match 1657e6b1e83SMilanka Ringwald plc_state->bestlag += SBC_M; 1664e074f72SMilanka Ringwald 1674e4f6f26SMatthias Ringwald // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet 1684e074f72SMilanka Ringwald sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag); 1697e6b1e83SMilanka Ringwald for (i=0;i<SBC_OLAL;i++){ 1707e6b1e83SMilanka Ringwald float left = ZIRbuf[i]; 1717e6b1e83SMilanka Ringwald float right = sf*plc_state->hist[plc_state->bestlag+i]; 17262f77245SMilanka Ringwald val = left*rcos[i] + right*rcos[SBC_OLAL-1-i]; 1734e4f6f26SMatthias Ringwald plc_state->hist[SBC_LHIST+i] = crop_sample(val); 1744e074f72SMilanka Ringwald } 1754e074f72SMilanka Ringwald 1767e6b1e83SMilanka Ringwald for (;i<SBC_FS;i++){ 1777e6b1e83SMilanka Ringwald val = sf*plc_state->hist[plc_state->bestlag+i]; 1784e4f6f26SMatthias Ringwald plc_state->hist[SBC_LHIST+i] = crop_sample(val); 1794e074f72SMilanka Ringwald } 1804e074f72SMilanka Ringwald 1817e6b1e83SMilanka Ringwald for (;i<SBC_FS+SBC_OLAL;i++){ 1827e6b1e83SMilanka Ringwald float left = sf*plc_state->hist[plc_state->bestlag+i]; 1837e6b1e83SMilanka Ringwald float right = plc_state->hist[plc_state->bestlag+i]; 1844e4f6f26SMatthias Ringwald val = left*rcos[i-SBC_FS]+right*rcos[SBC_OLAL-1-i+SBC_FS]; 1854e4f6f26SMatthias Ringwald plc_state->hist[SBC_LHIST+i] = crop_sample(val); 1864e074f72SMilanka Ringwald } 1874e074f72SMilanka Ringwald 1887e6b1e83SMilanka Ringwald for (;i<SBC_FS+SBC_RT+SBC_OLAL;i++){ 1897e6b1e83SMilanka Ringwald plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i]; 1907e6b1e83SMilanka Ringwald } 1914e074f72SMilanka Ringwald } else { 1924e4f6f26SMatthias Ringwald for (;i<SBC_FS+SBC_RT+SBC_OLAL;i++){ 1937e6b1e83SMilanka Ringwald plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i]; 1944e074f72SMilanka Ringwald } 195c5e169ecSMilanka Ringwald } 1967e6b1e83SMilanka Ringwald for (i=0;i<SBC_FS;i++){ 1977e6b1e83SMilanka Ringwald out[i] = plc_state->hist[SBC_LHIST+i]; 1987e6b1e83SMilanka Ringwald } 1994e074f72SMilanka Ringwald 2004e4f6f26SMatthias Ringwald // shift the history buffer 2017e6b1e83SMilanka Ringwald for (i=0;i<SBC_LHIST+SBC_RT+SBC_OLAL;i++){ 2027e6b1e83SMilanka Ringwald plc_state->hist[i] = plc_state->hist[i+SBC_FS]; 2037e6b1e83SMilanka Ringwald } 2044e074f72SMilanka Ringwald } 2054e074f72SMilanka Ringwald 2064e4f6f26SMatthias Ringwald void btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *in, SAMPLE_FORMAT *out){ 2077e6b1e83SMilanka Ringwald float val; 2087e6b1e83SMilanka Ringwald int i = 0; 2094e074f72SMilanka Ringwald if (plc_state->nbf>0){ 2107e6b1e83SMilanka Ringwald for (i=0;i<SBC_RT;i++){ 2117e6b1e83SMilanka Ringwald out[i] = plc_state->hist[SBC_LHIST+i]; 2124e074f72SMilanka Ringwald } 2137e6b1e83SMilanka Ringwald 2144e4f6f26SMatthias Ringwald for (i = SBC_RT;i<SBC_RT+SBC_OLAL;i++){ 2157e6b1e83SMilanka Ringwald float left = plc_state->hist[SBC_LHIST+i]; 2167e6b1e83SMilanka Ringwald float right = in[i]; 2174e4f6f26SMatthias Ringwald val = left*rcos[i-SBC_RT] + right*rcos[SBC_OLAL+SBC_RT-1-i]; 2184e4f6f26SMatthias Ringwald out[i] = (SAMPLE_FORMAT)val; 2197e6b1e83SMilanka Ringwald } 2207e6b1e83SMilanka Ringwald } 2214e4f6f26SMatthias Ringwald 2227e6b1e83SMilanka Ringwald for (;i<SBC_FS;i++){ 2234e074f72SMilanka Ringwald out[i] = in[i]; 2247e6b1e83SMilanka Ringwald } 2254e4f6f26SMatthias Ringwald // Copy the output to the history buffer 2267e6b1e83SMilanka Ringwald for (i=0;i<SBC_FS;i++){ 2277e6b1e83SMilanka Ringwald plc_state->hist[SBC_LHIST+i] = out[i]; 2287e6b1e83SMilanka Ringwald } 2294e4f6f26SMatthias Ringwald // shift the history buffer 2307e6b1e83SMilanka Ringwald for (i=0;i<SBC_LHIST;i++){ 2317e6b1e83SMilanka Ringwald plc_state->hist[i] = plc_state->hist[i+SBC_FS]; 2327e6b1e83SMilanka Ringwald } 2337e6b1e83SMilanka Ringwald 2344e074f72SMilanka Ringwald plc_state->nbf=0; 2354e074f72SMilanka Ringwald } 236