xref: /btstack/src/classic/btstack_sbc_plc.c (revision 95a50da88b4181db3c2f4fb459bb9de4f1130fd6)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_sbc_plc.c"
39ab2c6ae4SMatthias Ringwald 
404e074f72SMilanka Ringwald /*
41e7a41128SMilanka Ringwald  * btstack_sbc_plc.c
424e074f72SMilanka Ringwald  *
434e074f72SMilanka Ringwald  */
444e074f72SMilanka Ringwald 
454e074f72SMilanka Ringwald #include <stdint.h>
464e074f72SMilanka Ringwald #include <stdlib.h>
474e074f72SMilanka Ringwald #include <string.h>
484e074f72SMilanka Ringwald 
49650b64aaSMilanka Ringwald #ifdef OCTAVE_OUTPUT
50650b64aaSMilanka Ringwald #include <stdio.h>
51650b64aaSMilanka Ringwald #endif
52650b64aaSMilanka Ringwald 
534e074f72SMilanka Ringwald #include "btstack_sbc_plc.h"
54de854f9aSMilanka Ringwald #include "btstack_debug.h"
554e074f72SMilanka Ringwald 
564e4f6f26SMatthias Ringwald #define SAMPLE_FORMAT int16_t
574e4f6f26SMatthias Ringwald 
58a2c7346fSMatthias Ringwald // Zero Frame (57 bytes) with padding zeros to avoid out of bound reads
59a2c7346fSMatthias Ringwald static uint8_t indices0[] = {
60a2c7346fSMatthias Ringwald     0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
61a2c7346fSMatthias Ringwald     0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6,
62a2c7346fSMatthias Ringwald     0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb,
63a2c7346fSMatthias Ringwald     0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d,
64a2c7346fSMatthias Ringwald     0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6,
65a2c7346fSMatthias Ringwald     0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c,
66a2c7346fSMatthias Ringwald     /*                padding            */   0x00, 0x00, 0x00
67a2c7346fSMatthias Ringwald };
684e074f72SMilanka Ringwald 
694e074f72SMilanka Ringwald /* Raised COSine table for OLA */
707e6b1e83SMilanka Ringwald static float rcos[SBC_OLAL] = {
714e074f72SMilanka Ringwald     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
724e074f72SMilanka Ringwald     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
734e074f72SMilanka Ringwald     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
74a2c7346fSMatthias Ringwald     0.13049554f,0.07489143f,0.03376389f,0.00851345f
75a2c7346fSMatthias Ringwald };
764e074f72SMilanka Ringwald 
7740e1e61cSMilanka Ringwald // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
7840e1e61cSMilanka Ringwald // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation
sqrt3(const float x)7940e1e61cSMilanka Ringwald static float sqrt3(const float x){
8040e1e61cSMilanka Ringwald     union {
8140e1e61cSMilanka Ringwald         int i;
8240e1e61cSMilanka Ringwald         float x;
8340e1e61cSMilanka Ringwald     } u;
8440e1e61cSMilanka Ringwald     u.x = x;
8540e1e61cSMilanka Ringwald     u.i = (1<<29) + (u.i >> 1) - (1<<22);
8640e1e61cSMilanka Ringwald 
8740e1e61cSMilanka Ringwald     // Two Babylonian Steps (simplified from:)
8840e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
8940e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
90c1ab6cc1SMatthias Ringwald     u.x =       u.x + (x/u.x);
91c1ab6cc1SMatthias Ringwald     u.x = (0.25f*u.x) + (x/u.x);
9240e1e61cSMilanka Ringwald 
9340e1e61cSMilanka Ringwald     return u.x;
9440e1e61cSMilanka Ringwald }
9540e1e61cSMilanka Ringwald 
absolute(float x)9640e1e61cSMilanka Ringwald static float absolute(float x){
9740e1e61cSMilanka Ringwald      if (x < 0) x = -x;
9840e1e61cSMilanka Ringwald      return x;
9940e1e61cSMilanka Ringwald }
10040e1e61cSMilanka Ringwald 
CrossCorrelation(SAMPLE_FORMAT * x,SAMPLE_FORMAT * y)1014e4f6f26SMatthias Ringwald static float CrossCorrelation(SAMPLE_FORMAT *x, SAMPLE_FORMAT *y){
102c5e169ecSMilanka Ringwald     float num = 0;
103c5e169ecSMilanka Ringwald     float den = 0;
104c5e169ecSMilanka Ringwald     float x2 = 0;
105c5e169ecSMilanka Ringwald     float y2 = 0;
106c5e169ecSMilanka Ringwald     int   m;
107c5e169ecSMilanka Ringwald     for (m=0;m<SBC_M;m++){
108c5e169ecSMilanka Ringwald         num+=((float)x[m])*y[m];
109c5e169ecSMilanka Ringwald         x2+=((float)x[m])*x[m];
110c5e169ecSMilanka Ringwald         y2+=((float)y[m])*y[m];
111c5e169ecSMilanka Ringwald     }
11240e1e61cSMilanka Ringwald     den = (float)sqrt3(x2*y2);
113c5e169ecSMilanka Ringwald     return num/den;
114c5e169ecSMilanka Ringwald }
115c5e169ecSMilanka Ringwald 
PatternMatch(SAMPLE_FORMAT * y)1164e4f6f26SMatthias Ringwald static int PatternMatch(SAMPLE_FORMAT *y){
1173548b7cbSDirk Helbig     float maxCn = -999999.f;  // large negative number
118c5e169ecSMilanka Ringwald     int   bestmatch = 0;
119c5e169ecSMilanka Ringwald     float Cn;
120c5e169ecSMilanka Ringwald     int   n;
121c5e169ecSMilanka Ringwald     for (n=0;n<SBC_N;n++){
1224e4f6f26SMatthias Ringwald         Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]);
123c5e169ecSMilanka Ringwald         if (Cn>maxCn){
124c5e169ecSMilanka Ringwald             bestmatch=n;
125c5e169ecSMilanka Ringwald             maxCn = Cn;
126c5e169ecSMilanka Ringwald         }
127c5e169ecSMilanka Ringwald     }
128c5e169ecSMilanka Ringwald     return bestmatch;
129c5e169ecSMilanka Ringwald }
130c5e169ecSMilanka Ringwald 
AmplitudeMatch(SAMPLE_FORMAT * y,SAMPLE_FORMAT bestmatch)1314e4f6f26SMatthias Ringwald static float AmplitudeMatch(SAMPLE_FORMAT *y, SAMPLE_FORMAT bestmatch) {
132c5e169ecSMilanka Ringwald     int   i;
133c5e169ecSMilanka Ringwald     float sumx = 0;
134c5e169ecSMilanka Ringwald     float sumy = 0.000001f;
135c5e169ecSMilanka Ringwald     float sf;
136c5e169ecSMilanka Ringwald 
137c5e169ecSMilanka Ringwald     for (i=0;i<SBC_FS;i++){
13840e1e61cSMilanka Ringwald         sumx += absolute(y[SBC_LHIST-SBC_FS+i]);
13940e1e61cSMilanka Ringwald         sumy += absolute(y[bestmatch+i]);
140c5e169ecSMilanka Ringwald     }
141c5e169ecSMilanka Ringwald     sf = sumx/sumy;
1424e4f6f26SMatthias Ringwald     // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
143c5e169ecSMilanka Ringwald     if (sf<0.75f) sf=0.75f;
144ee5b2fc6SMilanka Ringwald     if (sf>1.0f) sf=1.0f;
145c5e169ecSMilanka Ringwald     return sf;
146c5e169ecSMilanka Ringwald }
1474e074f72SMilanka Ringwald 
crop_sample(float val)1484e4f6f26SMatthias Ringwald static SAMPLE_FORMAT crop_sample(float val){
149250a1e4aSMilanka Ringwald     float croped_val = val;
1503548b7cbSDirk Helbig     if (croped_val > 32767.f)  croped_val= 32767.f;
1513548b7cbSDirk Helbig     if (croped_val < -32768.f) croped_val=-32768.f;
1524e4f6f26SMatthias Ringwald     return (SAMPLE_FORMAT) croped_val;
1537e6b1e83SMilanka Ringwald }
1547e6b1e83SMilanka Ringwald 
btstack_sbc_plc_zero_signal_frame(void)155e7a41128SMilanka Ringwald uint8_t * btstack_sbc_plc_zero_signal_frame(void){
1564e074f72SMilanka Ringwald     return (uint8_t *)&indices0;
1574e074f72SMilanka Ringwald }
1584e074f72SMilanka Ringwald 
btstack_sbc_plc_init(btstack_sbc_plc_state_t * plc_state)159e7a41128SMilanka Ringwald void btstack_sbc_plc_init(btstack_sbc_plc_state_t *plc_state){
1604e074f72SMilanka Ringwald     plc_state->nbf=0;
1614e074f72SMilanka Ringwald     plc_state->bestlag=0;
162b3f76298SMilanka Ringwald     memset(plc_state->hist,0,sizeof(plc_state->hist));
1634e074f72SMilanka Ringwald }
1644e074f72SMilanka Ringwald 
165ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
166ee5b2fc6SMilanka Ringwald typedef enum {
167ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_UNKNOWN = 0,
168ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_GOOD,
169ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_BAD
170ee5b2fc6SMilanka Ringwald } octave_frame_type_t;
171ee5b2fc6SMilanka Ringwald 
172ee5b2fc6SMilanka Ringwald static const char * octave_frame_type_name[] = {
173ee5b2fc6SMilanka Ringwald     "unknown",
174ee5b2fc6SMilanka Ringwald     "good",
175ee5b2fc6SMilanka Ringwald     "bad"
176ee5b2fc6SMilanka Ringwald };
177ee5b2fc6SMilanka Ringwald 
178ee5b2fc6SMilanka Ringwald static octave_frame_type_t octave_frame_type;
179ee5b2fc6SMilanka Ringwald static char octave_base_name[1000];
180ee5b2fc6SMilanka Ringwald 
octave_frame_type2str(int index)181ee5b2fc6SMilanka Ringwald const char * octave_frame_type2str(int index){
182ee5b2fc6SMilanka Ringwald     if (index <= 0 || index >= sizeof(octave_frame_type_t)) return octave_frame_type_name[0];
183ee5b2fc6SMilanka Ringwald     return octave_frame_type_name[index];
184ee5b2fc6SMilanka Ringwald }
185ee5b2fc6SMilanka Ringwald 
btstack_sbc_plc_octave_set_base_name(const char * base_name)186d1550f90SMilanka Ringwald void btstack_sbc_plc_octave_set_base_name(const char * base_name){
187ee5b2fc6SMilanka Ringwald     strcpy(octave_base_name, base_name);
188ee5b2fc6SMilanka Ringwald     printf("OCTAVE: base name set to %s\n", octave_base_name);
189ee5b2fc6SMilanka Ringwald }
190ee5b2fc6SMilanka Ringwald 
octave_fprintf_array_int16(FILE * oct_file,char * name,int data_len,int16_t * data)191ee5b2fc6SMilanka Ringwald static void octave_fprintf_array_int16(FILE * oct_file, char * name, int data_len, int16_t * data){
192ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s = [", name);
193ee5b2fc6SMilanka Ringwald     int i;
194ee5b2fc6SMilanka Ringwald     for (i = 0; i < data_len - 1; i++){
195ee5b2fc6SMilanka Ringwald         fprintf(oct_file, "%d, ", data[i]);
196ee5b2fc6SMilanka Ringwald     }
197ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%d", data[i]);
198ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s", "];\n");
199ee5b2fc6SMilanka Ringwald }
200ee5b2fc6SMilanka Ringwald 
open_octave_file(btstack_sbc_plc_state_t * plc_state,octave_frame_type_t frame_type)201ee5b2fc6SMilanka Ringwald static FILE * open_octave_file(btstack_sbc_plc_state_t *plc_state, octave_frame_type_t frame_type){
202ee5b2fc6SMilanka Ringwald     char oct_file_name[1200];
203ee5b2fc6SMilanka Ringwald     octave_frame_type = frame_type;
204ff7d6aeaSMatthias Ringwald     snprintf(oct_file_name, sizeof(oct_file_name), "%s_octave_plc_%d_%s.m",
205ff7d6aeaSMatthias Ringwald              octave_base_name, plc_state->frame_count,
206ff7d6aeaSMatthias Ringwald              octave_frame_type2str(octave_frame_type));
207ff7d6aeaSMatthias Ringwald     oct_file_name[sizeof(oct_file_name) - 1] = 0;
208ee5b2fc6SMilanka Ringwald 
209ee5b2fc6SMilanka Ringwald     FILE * oct_file = fopen(oct_file_name, "wb");
210ee5b2fc6SMilanka Ringwald     if (oct_file == NULL){
211ee5b2fc6SMilanka Ringwald         printf("OCTAVE: could not open file %s\n", oct_file_name);
212ee5b2fc6SMilanka Ringwald         return NULL;
213ee5b2fc6SMilanka Ringwald     }
214ee5b2fc6SMilanka Ringwald     printf("OCTAVE: opened file %s\n", oct_file_name);
215ee5b2fc6SMilanka Ringwald     return oct_file;
216ee5b2fc6SMilanka Ringwald }
217ee5b2fc6SMilanka Ringwald 
octave_fprintf_plot_history_frame(btstack_sbc_plc_state_t * plc_state,FILE * oct_file,int frame_nr)218ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_history_frame(btstack_sbc_plc_state_t *plc_state, FILE * oct_file, int frame_nr){
219ee5b2fc6SMilanka Ringwald     char title[100];
220ee5b2fc6SMilanka Ringwald     char hist_name[10];
221ff7d6aeaSMatthias Ringwald     snprintf(hist_name, sizeof(hist_name), "hist%d", plc_state->nbf);
222ff7d6aeaSMatthias Ringwald     hist_name[sizeof(hist_name) - 1] = 0;
223ee5b2fc6SMilanka Ringwald 
224ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, hist_name, SBC_LHIST, plc_state->hist);
225ee5b2fc6SMilanka Ringwald 
226ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "y = [min(%s):1000:max(%s)];\n", hist_name, hist_name);
227ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "x = zeros(1, size(y,2));\n");
228ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "b = [0: %d];\n", SBC_LHIST+SBC_FS+SBC_RT+SBC_OLAL);
229ee5b2fc6SMilanka Ringwald 
230ee5b2fc6SMilanka Ringwald     int pos = SBC_FS;
231ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "shift_x = x + %d;\n", pos);
232ee5b2fc6SMilanka Ringwald 
233ee5b2fc6SMilanka Ringwald     pos = SBC_LHIST - 1;
234ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_x = x + %d;\n", pos);
235ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
236ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal1_x = x + %d;\n", pos);
237ee5b2fc6SMilanka Ringwald     pos += SBC_FS - SBC_OLAL;
238ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_fs_x = x + %d;\n", pos);
239ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
240ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal2_x = x + %d;\n", pos);
241ee5b2fc6SMilanka Ringwald     pos += SBC_RT;
242ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_rt_x = x + %d;\n", pos);
243ee5b2fc6SMilanka Ringwald 
244ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "pattern_window_x = x + %d;\n", SBC_LHIST - SBC_M);
245ee5b2fc6SMilanka Ringwald 
246ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hf = figure();\n");
247ff7d6aeaSMatthias Ringwald     snprintf(title, sizeof(title), "PLC %s frame %d",
248ff7d6aeaSMatthias Ringwald              octave_frame_type2str(octave_frame_type), frame_nr);
249ff7d6aeaSMatthias Ringwald     title[sizeof(title) - 1] = 0;
250ee5b2fc6SMilanka Ringwald 
251ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hold on;\n");
252ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h1 = plot(%s); \n", hist_name);
253ee5b2fc6SMilanka Ringwald 
254ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "title(\"%s\");\n", title);
255ee5b2fc6SMilanka Ringwald 
256ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_x, y, 'k'); \n");
257ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_x) - 10, max(y)+1000, 'lhist'); \n");
258ee5b2fc6SMilanka Ringwald 
259ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal1_x, y, 'k'); \n");
260ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal1_x) - 10, max(y)+1000, 'OLAL'); \n");
261ee5b2fc6SMilanka Ringwald 
262ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_fs_x, y, 'k'); \n");
263ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_fs_x) - 10, max(y)+1000, 'FS'); \n");
264ee5b2fc6SMilanka Ringwald 
265ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal2_x, y, 'k'); \n");
266ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal2_x) - 10, max(y)+1000, 'OLAL'); \n");
267ee5b2fc6SMilanka Ringwald 
268ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_rt_x, y, 'k');\n");
269ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_rt_x) - 10, max(y)+1000, 'RT'); \n");
270ee5b2fc6SMilanka Ringwald 
271ee5b2fc6SMilanka Ringwald     if (octave_frame_type == OCTAVE_FRAME_TYPE_GOOD) return;
272ee5b2fc6SMilanka Ringwald 
273ee5b2fc6SMilanka Ringwald     int x0 = plc_state->bestlag;
274ee5b2fc6SMilanka Ringwald     int x1 = plc_state->bestlag + SBC_M - 1;
275ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
276ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(%d - 10, -10, 'bestlag'); \n", x0);
277ee5b2fc6SMilanka Ringwald 
278ee5b2fc6SMilanka Ringwald     x0 = plc_state->bestlag + SBC_M ;
279ee5b2fc6SMilanka Ringwald     x1 = plc_state->bestlag + SBC_M + SBC_FS - 1;
280ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'kd'); \n", x0, x1, hist_name, x0, x1);
281ee5b2fc6SMilanka Ringwald 
282ee5b2fc6SMilanka Ringwald     x0 = SBC_LHIST - SBC_M;
283ee5b2fc6SMilanka Ringwald     x1 = SBC_LHIST - 1;
284ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
285ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(pattern_window_x, y, 'g'); \n");
286ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(pattern_window_x) - 10, max(y)+1000, 'M'); \n");
287ee5b2fc6SMilanka Ringwald }
288ee5b2fc6SMilanka Ringwald 
octave_fprintf_plot_output(btstack_sbc_plc_state_t * plc_state,FILE * oct_file)289ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_output(btstack_sbc_plc_state_t *plc_state, FILE * oct_file){
290ee5b2fc6SMilanka Ringwald     if (!oct_file) return;
291ee5b2fc6SMilanka Ringwald     char out_name[10];
292ff7d6aeaSMatthias Ringwald     snprintf(out_name, sizeof(out_name), "out%d", plc_state->nbf);
293ff7d6aeaSMatthias Ringwald     out_name[sizeof(out_name) - 1] = 0;
294ee5b2fc6SMilanka Ringwald     int x0  = SBC_LHIST;
295ee5b2fc6SMilanka Ringwald     int x1  = x0 + SBC_FS - 1;
296ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, out_name, SBC_FS, plc_state->hist+x0);
297ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h2 = plot(b(%d:%d), %s, 'cd'); \n", x0, x1, out_name);
298ee5b2fc6SMilanka Ringwald 
299ee5b2fc6SMilanka Ringwald     char rest_hist_name[10];
300ff7d6aeaSMatthias Ringwald     snprintf(rest_hist_name, sizeof(rest_hist_name), "rest%d", plc_state->nbf);
301ff7d6aeaSMatthias Ringwald     rest_hist_name[sizeof(rest_hist_name) - 1] = 0;
302ee5b2fc6SMilanka Ringwald     x0  = SBC_LHIST + SBC_FS;
303ee5b2fc6SMilanka Ringwald     x1  = x0 + SBC_OLAL + SBC_RT - 1;
304ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, rest_hist_name, SBC_OLAL + SBC_RT, plc_state->hist+x0);
305ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h3 = plot(b(%d:%d), %s, 'kd'); \n", x0, x1, rest_hist_name);
306ee5b2fc6SMilanka Ringwald 
307ee5b2fc6SMilanka Ringwald     char new_hist_name[10];
308ff7d6aeaSMatthias Ringwald     snprintf(new_hist_name, sizeof(new_hist_name), "hist%d", plc_state->nbf);
309ff7d6aeaSMatthias Ringwald     new_hist_name[sizeof(new_hist_name) - 1] = 0;
310ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, new_hist_name, SBC_LHIST, plc_state->hist);
311ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h4 = plot(%s, 'r--'); \n", new_hist_name);
312ee5b2fc6SMilanka Ringwald 
313ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "legend ([h1, h2, h3, h4], {\"hist\", \"out\", \"rest\", \"new hist\"}, \"location\", \"northeast\");\n ");
314ee5b2fc6SMilanka Ringwald 
315ee5b2fc6SMilanka Ringwald     char fig_name[1200];
316ff7d6aeaSMatthias Ringwald     snprintf(fig_name, sizeof(fig_name), "../%s_octave_plc_%d_%s",
317ff7d6aeaSMatthias Ringwald              octave_base_name, plc_state->frame_count,
318ff7d6aeaSMatthias Ringwald              octave_frame_type2str(octave_frame_type));
319ff7d6aeaSMatthias Ringwald     fig_name[sizeof(fig_name) - 1] = 0;
320ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "print(hf, \"%s.jpg\", \"-djpg\");", fig_name);
321ee5b2fc6SMilanka Ringwald }
322ee5b2fc6SMilanka Ringwald #endif
323ee5b2fc6SMilanka Ringwald 
324ee5b2fc6SMilanka Ringwald 
btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t * plc_state,SAMPLE_FORMAT * ZIRbuf,SAMPLE_FORMAT * out)3254e4f6f26SMatthias Ringwald void btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *ZIRbuf, SAMPLE_FORMAT *out){
3264e074f72SMilanka Ringwald     float val;
3279b037397SMilanka Ringwald     int   i;
3287e6b1e83SMilanka Ringwald     float sf = 1;
3297e6b1e83SMilanka Ringwald 
3309b037397SMilanka Ringwald     plc_state->nbf++;
331de854f9aSMilanka Ringwald     plc_state->bad_frames_nr++;
332de854f9aSMilanka Ringwald     plc_state->frame_count++;
3339b037397SMilanka Ringwald 
334de854f9aSMilanka Ringwald     if (plc_state->max_consecutive_bad_frames_nr < plc_state->nbf){
335de854f9aSMilanka Ringwald         plc_state->max_consecutive_bad_frames_nr = plc_state->nbf;
336de854f9aSMilanka Ringwald     }
337de854f9aSMilanka Ringwald 
3384e074f72SMilanka Ringwald     if (plc_state->nbf==1){
33922183937SMilanka Ringwald         // printf("first bad frame\n");
3404e4f6f26SMatthias Ringwald         // Perform pattern matching to find where to replicate
3414e074f72SMilanka Ringwald         plc_state->bestlag = PatternMatch(plc_state->hist);
342ee5b2fc6SMilanka Ringwald     }
343ee5b2fc6SMilanka Ringwald 
344ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
345ee5b2fc6SMilanka Ringwald     FILE * oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_BAD);
346ee5b2fc6SMilanka Ringwald     if (oct_file){
347ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
348ee5b2fc6SMilanka Ringwald     }
349ee5b2fc6SMilanka Ringwald #endif
350ee5b2fc6SMilanka Ringwald 
351ee5b2fc6SMilanka Ringwald     if (plc_state->nbf==1){
3524e4f6f26SMatthias Ringwald         // the replication begins after the template match
3537e6b1e83SMilanka Ringwald         plc_state->bestlag += SBC_M;
3544e074f72SMilanka Ringwald 
3554e4f6f26SMatthias Ringwald         // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
3564e074f72SMilanka Ringwald         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
35722183937SMilanka Ringwald         // printf("sf Apmlitude Match %f, new data %d, bestlag+M %d\n", sf, ZIRbuf[0], plc_state->hist[plc_state->bestlag]);
3587e6b1e83SMilanka Ringwald         for (i=0; i<SBC_OLAL; i++){
3597e6b1e83SMilanka Ringwald             float left  = ZIRbuf[i];
3607e6b1e83SMilanka Ringwald             float right = sf*plc_state->hist[plc_state->bestlag+i];
361c1ab6cc1SMatthias Ringwald             val = (left*rcos[i]) + (right*rcos[SBC_OLAL-1-i]);
362ee5b2fc6SMilanka Ringwald             // val = sf*plc_state->hist[plc_state->bestlag+i];
3634e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3644e074f72SMilanka Ringwald         }
3654e074f72SMilanka Ringwald 
3669b037397SMilanka Ringwald         for (i=SBC_OLAL; i<SBC_FS; i++){
3677e6b1e83SMilanka Ringwald             val = sf*plc_state->hist[plc_state->bestlag+i];
3684e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3694e074f72SMilanka Ringwald         }
3704e074f72SMilanka Ringwald 
3719b037397SMilanka Ringwald         for (i=SBC_FS; i<(SBC_FS+SBC_OLAL); i++){
3727e6b1e83SMilanka Ringwald             float left  = sf*plc_state->hist[plc_state->bestlag+i];
3737e6b1e83SMilanka Ringwald             float right = plc_state->hist[plc_state->bestlag+i];
374c1ab6cc1SMatthias Ringwald             val = (left*rcos[i-SBC_FS])+(right*rcos[SBC_OLAL-1-i+SBC_FS]);
3754e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3764e074f72SMilanka Ringwald         }
3774e074f72SMilanka Ringwald 
3789b037397SMilanka Ringwald         for (i=(SBC_FS+SBC_OLAL); i<(SBC_FS+SBC_RT+SBC_OLAL); i++){
3797e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3807e6b1e83SMilanka Ringwald         }
3814e074f72SMilanka Ringwald     } else {
38222183937SMilanka Ringwald         // printf("succesive bad frame nr %d\n", plc_state->nbf);
3839b037397SMilanka Ringwald         for (i=0; i<(SBC_FS+SBC_RT+SBC_OLAL); i++){
3847e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3854e074f72SMilanka Ringwald         }
386c5e169ecSMilanka Ringwald     }
3877e6b1e83SMilanka Ringwald     for (i=0; i<SBC_FS; i++){
3887e6b1e83SMilanka Ringwald         out[i] = plc_state->hist[SBC_LHIST+i];
3897e6b1e83SMilanka Ringwald     }
3904e074f72SMilanka Ringwald 
3914e4f6f26SMatthias Ringwald    // shift the history buffer
3920e588213SMatthias Ringwald     for (i=0; i<(SBC_LHIST+SBC_RT+SBC_OLAL); i++){
3937e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
3947e6b1e83SMilanka Ringwald     }
395ee5b2fc6SMilanka Ringwald 
396ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
397ee5b2fc6SMilanka Ringwald     if (oct_file){
398ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
399ee5b2fc6SMilanka Ringwald         fclose(oct_file);
400ee5b2fc6SMilanka Ringwald     }
401ee5b2fc6SMilanka Ringwald #endif
4024e074f72SMilanka Ringwald }
4034e074f72SMilanka Ringwald 
btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t * plc_state,SAMPLE_FORMAT * in,SAMPLE_FORMAT * out)4044e4f6f26SMatthias Ringwald void btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *in, SAMPLE_FORMAT *out){
4057e6b1e83SMilanka Ringwald     float val;
4067e6b1e83SMilanka Ringwald     int i = 0;
407de854f9aSMilanka Ringwald     plc_state->good_frames_nr++;
408de854f9aSMilanka Ringwald     plc_state->frame_count++;
409de854f9aSMilanka Ringwald 
410ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
411ee5b2fc6SMilanka Ringwald     FILE * oct_file = NULL;
412ee5b2fc6SMilanka Ringwald     if (plc_state->nbf>0){
413ee5b2fc6SMilanka Ringwald         oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_GOOD);
414ee5b2fc6SMilanka Ringwald         if (oct_file){
415ee5b2fc6SMilanka Ringwald             octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
416ee5b2fc6SMilanka Ringwald         }
417ee5b2fc6SMilanka Ringwald     }
418ee5b2fc6SMilanka Ringwald #endif
419ee5b2fc6SMilanka Ringwald 
4204e074f72SMilanka Ringwald     if (plc_state->nbf>0){
4217e6b1e83SMilanka Ringwald         for (i=0;i<SBC_RT;i++){
4227e6b1e83SMilanka Ringwald             out[i] = plc_state->hist[SBC_LHIST+i];
4234e074f72SMilanka Ringwald         }
4247e6b1e83SMilanka Ringwald 
425c1ab6cc1SMatthias Ringwald         for (i = SBC_RT;i<(SBC_RT+SBC_OLAL);i++){
4267e6b1e83SMilanka Ringwald             float left  = plc_state->hist[SBC_LHIST+i];
4277e6b1e83SMilanka Ringwald             float right = in[i];
428c1ab6cc1SMatthias Ringwald             val = (left*rcos[i-SBC_RT]) + (right*rcos[SBC_OLAL+SBC_RT-1-i]);
429ee5b2fc6SMilanka Ringwald             out[i] = crop_sample(val);
4307e6b1e83SMilanka Ringwald         }
4317e6b1e83SMilanka Ringwald     }
4324e4f6f26SMatthias Ringwald 
4337e6b1e83SMilanka Ringwald     for (;i<SBC_FS;i++){
4344e074f72SMilanka Ringwald         out[i] = in[i];
4357e6b1e83SMilanka Ringwald     }
4364e4f6f26SMatthias Ringwald     // Copy the output to the history buffer
4377e6b1e83SMilanka Ringwald     for (i=0;i<SBC_FS;i++){
4387e6b1e83SMilanka Ringwald         plc_state->hist[SBC_LHIST+i] = out[i];
4397e6b1e83SMilanka Ringwald     }
440ee5b2fc6SMilanka Ringwald 
4414e4f6f26SMatthias Ringwald     // shift the history buffer
4427e6b1e83SMilanka Ringwald     for (i=0;i<SBC_LHIST;i++){
4437e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
4447e6b1e83SMilanka Ringwald     }
4457e6b1e83SMilanka Ringwald 
446ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
447ee5b2fc6SMilanka Ringwald     if (oct_file){
448ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
449ee5b2fc6SMilanka Ringwald         fclose(oct_file);
450ee5b2fc6SMilanka Ringwald     }
451ee5b2fc6SMilanka Ringwald #endif
4524e074f72SMilanka Ringwald     plc_state->nbf=0;
4534e074f72SMilanka Ringwald }
454de854f9aSMilanka Ringwald 
btstack_sbc_dump_statistics(btstack_sbc_plc_state_t * state)455de854f9aSMilanka Ringwald void btstack_sbc_dump_statistics(btstack_sbc_plc_state_t * state){
456*95a50da8SDirk Helbig     UNUSED(state);
457de854f9aSMilanka Ringwald     log_info("Good frames: %d\n", state->good_frames_nr);
458de854f9aSMilanka Ringwald     log_info("Bad frames: %d\n", state->bad_frames_nr);
459de854f9aSMilanka Ringwald     log_info("Max Consecutive bad frames: %d\n", state->max_consecutive_bad_frames_nr);
460de854f9aSMilanka Ringwald }
461