xref: /btstack/src/classic/btstack_sbc_plc.c (revision d1550f906a6f7312c10521c9150f12effd00dedc)
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 
38ab2c6ae4SMatthias 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 <stdio.h>
474e074f72SMilanka Ringwald #include <stdlib.h>
484e074f72SMilanka Ringwald #include <string.h>
494e074f72SMilanka Ringwald 
504e074f72SMilanka Ringwald #include "btstack_sbc_plc.h"
51de854f9aSMilanka Ringwald #include "btstack_debug.h"
524e074f72SMilanka Ringwald 
534e4f6f26SMatthias Ringwald #define SAMPLE_FORMAT int16_t
544e4f6f26SMatthias Ringwald 
554e074f72SMilanka Ringwald static uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 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, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
594e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
604e074f72SMilanka Ringwald 
614e074f72SMilanka Ringwald /* Raised COSine table for OLA */
627e6b1e83SMilanka Ringwald static float rcos[SBC_OLAL] = {
634e074f72SMilanka Ringwald     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
644e074f72SMilanka Ringwald     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
654e074f72SMilanka Ringwald     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
664e074f72SMilanka Ringwald     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
674e074f72SMilanka Ringwald 
6840e1e61cSMilanka Ringwald // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
6940e1e61cSMilanka Ringwald // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation
7040e1e61cSMilanka Ringwald static float sqrt3(const float x){
7140e1e61cSMilanka Ringwald     union {
7240e1e61cSMilanka Ringwald         int i;
7340e1e61cSMilanka Ringwald         float x;
7440e1e61cSMilanka Ringwald     } u;
7540e1e61cSMilanka Ringwald     u.x = x;
7640e1e61cSMilanka Ringwald     u.i = (1<<29) + (u.i >> 1) - (1<<22);
7740e1e61cSMilanka Ringwald 
7840e1e61cSMilanka Ringwald     // Two Babylonian Steps (simplified from:)
7940e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
8040e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
8140e1e61cSMilanka Ringwald     u.x =       u.x + x/u.x;
8240e1e61cSMilanka Ringwald     u.x = 0.25f*u.x + x/u.x;
8340e1e61cSMilanka Ringwald 
8440e1e61cSMilanka Ringwald     return u.x;
8540e1e61cSMilanka Ringwald }
8640e1e61cSMilanka Ringwald 
8740e1e61cSMilanka Ringwald static float absolute(float x){
8840e1e61cSMilanka Ringwald      if (x < 0) x = -x;
8940e1e61cSMilanka Ringwald      return x;
9040e1e61cSMilanka Ringwald }
9140e1e61cSMilanka Ringwald 
924e4f6f26SMatthias Ringwald static float CrossCorrelation(SAMPLE_FORMAT *x, SAMPLE_FORMAT *y){
93c5e169ecSMilanka Ringwald     float num = 0;
94c5e169ecSMilanka Ringwald     float den = 0;
95c5e169ecSMilanka Ringwald     float x2 = 0;
96c5e169ecSMilanka Ringwald     float y2 = 0;
97c5e169ecSMilanka Ringwald     int   m;
98c5e169ecSMilanka Ringwald     for (m=0;m<SBC_M;m++){
99c5e169ecSMilanka Ringwald         num+=((float)x[m])*y[m];
100c5e169ecSMilanka Ringwald         x2+=((float)x[m])*x[m];
101c5e169ecSMilanka Ringwald         y2+=((float)y[m])*y[m];
102c5e169ecSMilanka Ringwald     }
10340e1e61cSMilanka Ringwald     den = (float)sqrt3(x2*y2);
104c5e169ecSMilanka Ringwald     return num/den;
105c5e169ecSMilanka Ringwald }
106c5e169ecSMilanka Ringwald 
1074e4f6f26SMatthias Ringwald static int PatternMatch(SAMPLE_FORMAT *y){
1084e4f6f26SMatthias Ringwald     float maxCn = -999999.0;  // large negative number
109c5e169ecSMilanka Ringwald     int   bestmatch = 0;
110c5e169ecSMilanka Ringwald     float Cn;
111c5e169ecSMilanka Ringwald     int   n;
112c5e169ecSMilanka Ringwald     for (n=0;n<SBC_N;n++){
1134e4f6f26SMatthias Ringwald         Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]);
114c5e169ecSMilanka Ringwald         if (Cn>maxCn){
115c5e169ecSMilanka Ringwald             bestmatch=n;
116c5e169ecSMilanka Ringwald             maxCn = Cn;
117c5e169ecSMilanka Ringwald         }
118c5e169ecSMilanka Ringwald     }
119c5e169ecSMilanka Ringwald     return bestmatch;
120c5e169ecSMilanka Ringwald }
121c5e169ecSMilanka Ringwald 
1224e4f6f26SMatthias Ringwald static float AmplitudeMatch(SAMPLE_FORMAT *y, SAMPLE_FORMAT bestmatch) {
123c5e169ecSMilanka Ringwald     int   i;
124c5e169ecSMilanka Ringwald     float sumx = 0;
125c5e169ecSMilanka Ringwald     float sumy = 0.000001f;
126c5e169ecSMilanka Ringwald     float sf;
127c5e169ecSMilanka Ringwald 
128c5e169ecSMilanka Ringwald     for (i=0;i<SBC_FS;i++){
12940e1e61cSMilanka Ringwald         sumx += absolute(y[SBC_LHIST-SBC_FS+i]);
13040e1e61cSMilanka Ringwald         sumy += absolute(y[bestmatch+i]);
131c5e169ecSMilanka Ringwald     }
132c5e169ecSMilanka Ringwald     sf = sumx/sumy;
1334e4f6f26SMatthias Ringwald     // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
134c5e169ecSMilanka Ringwald     if (sf<0.75f) sf=0.75f;
135ee5b2fc6SMilanka Ringwald     if (sf>1.0f) sf=1.0f;
136c5e169ecSMilanka Ringwald     return sf;
137c5e169ecSMilanka Ringwald }
1384e074f72SMilanka Ringwald 
1394e4f6f26SMatthias Ringwald static SAMPLE_FORMAT crop_sample(float val){
140250a1e4aSMilanka Ringwald     float croped_val = val;
141250a1e4aSMilanka Ringwald     if (croped_val > 32767.0)  croped_val= 32767.0;
142250a1e4aSMilanka Ringwald     if (croped_val < -32768.0) croped_val=-32768.0;
1434e4f6f26SMatthias Ringwald     return (SAMPLE_FORMAT) croped_val;
1447e6b1e83SMilanka Ringwald }
1457e6b1e83SMilanka Ringwald 
146e7a41128SMilanka Ringwald uint8_t * btstack_sbc_plc_zero_signal_frame(void){
1474e074f72SMilanka Ringwald     return (uint8_t *)&indices0;
1484e074f72SMilanka Ringwald }
1494e074f72SMilanka Ringwald 
150e7a41128SMilanka Ringwald void btstack_sbc_plc_init(btstack_sbc_plc_state_t *plc_state){
1514e074f72SMilanka Ringwald     plc_state->nbf=0;
1524e074f72SMilanka Ringwald     plc_state->bestlag=0;
153ee5b2fc6SMilanka Ringwald     // printf("size\n");
154b3f76298SMilanka Ringwald     memset(plc_state->hist,0,sizeof(plc_state->hist));
1554e074f72SMilanka Ringwald }
1564e074f72SMilanka Ringwald 
157ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
158ee5b2fc6SMilanka Ringwald typedef enum {
159ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_UNKNOWN = 0,
160ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_GOOD,
161ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_BAD
162ee5b2fc6SMilanka Ringwald } octave_frame_type_t;
163ee5b2fc6SMilanka Ringwald 
164ee5b2fc6SMilanka Ringwald static const char * octave_frame_type_name[] = {
165ee5b2fc6SMilanka Ringwald     "unknown",
166ee5b2fc6SMilanka Ringwald     "good",
167ee5b2fc6SMilanka Ringwald     "bad"
168ee5b2fc6SMilanka Ringwald };
169ee5b2fc6SMilanka Ringwald 
170ee5b2fc6SMilanka Ringwald static octave_frame_type_t octave_frame_type;
171ee5b2fc6SMilanka Ringwald static char octave_base_name[1000];
172ee5b2fc6SMilanka Ringwald 
173ee5b2fc6SMilanka Ringwald const char * octave_frame_type2str(int index){
174ee5b2fc6SMilanka Ringwald     if (index <= 0 || index >= sizeof(octave_frame_type_t)) return octave_frame_type_name[0];
175ee5b2fc6SMilanka Ringwald     return octave_frame_type_name[index];
176ee5b2fc6SMilanka Ringwald }
177ee5b2fc6SMilanka Ringwald 
178*d1550f90SMilanka Ringwald void btstack_sbc_plc_octave_set_base_name(const char * base_name){
179ee5b2fc6SMilanka Ringwald     strcpy(octave_base_name, base_name);
180ee5b2fc6SMilanka Ringwald     printf("OCTAVE: base name set to %s\n", octave_base_name);
181ee5b2fc6SMilanka Ringwald }
182ee5b2fc6SMilanka Ringwald 
183ee5b2fc6SMilanka Ringwald static void octave_fprintf_array_int16(FILE * oct_file, char * name, int data_len, int16_t * data){
184ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s = [", name);
185ee5b2fc6SMilanka Ringwald     int i;
186ee5b2fc6SMilanka Ringwald     for (i = 0; i < data_len - 1; i++){
187ee5b2fc6SMilanka Ringwald         fprintf(oct_file, "%d, ", data[i]);
188ee5b2fc6SMilanka Ringwald     }
189ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%d", data[i]);
190ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s", "];\n");
191ee5b2fc6SMilanka Ringwald }
192ee5b2fc6SMilanka Ringwald 
193ee5b2fc6SMilanka Ringwald static FILE * open_octave_file(btstack_sbc_plc_state_t *plc_state, octave_frame_type_t frame_type){
194ee5b2fc6SMilanka Ringwald     char oct_file_name[1200];
195ee5b2fc6SMilanka Ringwald     octave_frame_type = frame_type;
196ee5b2fc6SMilanka Ringwald     sprintf(oct_file_name, "%s_octave_plc_%d_%s.m", octave_base_name, plc_state->frame_count, octave_frame_type2str(octave_frame_type));
197ee5b2fc6SMilanka Ringwald 
198ee5b2fc6SMilanka Ringwald     FILE * oct_file = fopen(oct_file_name, "wb");
199ee5b2fc6SMilanka Ringwald     if (oct_file == NULL){
200ee5b2fc6SMilanka Ringwald         printf("OCTAVE: could not open file %s\n", oct_file_name);
201ee5b2fc6SMilanka Ringwald         return NULL;
202ee5b2fc6SMilanka Ringwald     }
203ee5b2fc6SMilanka Ringwald     printf("OCTAVE: opened file %s\n", oct_file_name);
204ee5b2fc6SMilanka Ringwald     return oct_file;
205ee5b2fc6SMilanka Ringwald }
206ee5b2fc6SMilanka Ringwald 
207ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_history_frame(btstack_sbc_plc_state_t *plc_state, FILE * oct_file, int frame_nr){
208ee5b2fc6SMilanka Ringwald     char title[100];
209ee5b2fc6SMilanka Ringwald     char hist_name[10];
210ee5b2fc6SMilanka Ringwald     sprintf(hist_name, "hist%d", plc_state->nbf);
211ee5b2fc6SMilanka Ringwald 
212ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, hist_name, SBC_LHIST, plc_state->hist);
213ee5b2fc6SMilanka Ringwald 
214ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "y = [min(%s):1000:max(%s)];\n", hist_name, hist_name);
215ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "x = zeros(1, size(y,2));\n");
216ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "b = [0: %d];\n", SBC_LHIST+SBC_FS+SBC_RT+SBC_OLAL);
217ee5b2fc6SMilanka Ringwald 
218ee5b2fc6SMilanka Ringwald     int pos = SBC_FS;
219ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "shift_x = x + %d;\n", pos);
220ee5b2fc6SMilanka Ringwald 
221ee5b2fc6SMilanka Ringwald     pos = SBC_LHIST - 1;
222ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_x = x + %d;\n", pos);
223ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
224ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal1_x = x + %d;\n", pos);
225ee5b2fc6SMilanka Ringwald     pos += SBC_FS - SBC_OLAL;
226ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_fs_x = x + %d;\n", pos);
227ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
228ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal2_x = x + %d;\n", pos);
229ee5b2fc6SMilanka Ringwald     pos += SBC_RT;
230ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_rt_x = x + %d;\n", pos);
231ee5b2fc6SMilanka Ringwald 
232ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "pattern_window_x = x + %d;\n", SBC_LHIST - SBC_M);
233ee5b2fc6SMilanka Ringwald 
234ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hf = figure();\n");
235ee5b2fc6SMilanka Ringwald     sprintf(title, "PLC %s frame %d", octave_frame_type2str(octave_frame_type), frame_nr);
236ee5b2fc6SMilanka Ringwald 
237ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hold on;\n");
238ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h1 = plot(%s); \n", hist_name);
239ee5b2fc6SMilanka Ringwald 
240ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "title(\"%s\");\n", title);
241ee5b2fc6SMilanka Ringwald 
242ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_x, y, 'k'); \n");
243ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_x) - 10, max(y)+1000, 'lhist'); \n");
244ee5b2fc6SMilanka Ringwald 
245ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal1_x, y, 'k'); \n");
246ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal1_x) - 10, max(y)+1000, 'OLAL'); \n");
247ee5b2fc6SMilanka Ringwald 
248ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_fs_x, y, 'k'); \n");
249ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_fs_x) - 10, max(y)+1000, 'FS'); \n");
250ee5b2fc6SMilanka Ringwald 
251ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal2_x, y, 'k'); \n");
252ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal2_x) - 10, max(y)+1000, 'OLAL'); \n");
253ee5b2fc6SMilanka Ringwald 
254ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_rt_x, y, 'k');\n");
255ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_rt_x) - 10, max(y)+1000, 'RT'); \n");
256ee5b2fc6SMilanka Ringwald 
257ee5b2fc6SMilanka Ringwald     if (octave_frame_type == OCTAVE_FRAME_TYPE_GOOD) return;
258ee5b2fc6SMilanka Ringwald 
259ee5b2fc6SMilanka Ringwald     int x0 = plc_state->bestlag;
260ee5b2fc6SMilanka Ringwald     int x1 = plc_state->bestlag + SBC_M - 1;
261ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
262ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(%d - 10, -10, 'bestlag'); \n", x0);
263ee5b2fc6SMilanka Ringwald 
264ee5b2fc6SMilanka Ringwald     x0 = plc_state->bestlag + SBC_M ;
265ee5b2fc6SMilanka Ringwald     x1 = plc_state->bestlag + SBC_M + SBC_FS - 1;
266ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'kd'); \n", x0, x1, hist_name, x0, x1);
267ee5b2fc6SMilanka Ringwald 
268ee5b2fc6SMilanka Ringwald     x0 = SBC_LHIST - SBC_M;
269ee5b2fc6SMilanka Ringwald     x1 = SBC_LHIST - 1;
270ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
271ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(pattern_window_x, y, 'g'); \n");
272ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(pattern_window_x) - 10, max(y)+1000, 'M'); \n");
273ee5b2fc6SMilanka Ringwald }
274ee5b2fc6SMilanka Ringwald 
275ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_output(btstack_sbc_plc_state_t *plc_state, FILE * oct_file){
276ee5b2fc6SMilanka Ringwald     if (!oct_file) return;
277ee5b2fc6SMilanka Ringwald     char out_name[10];
278ee5b2fc6SMilanka Ringwald     sprintf(out_name, "out%d", plc_state->nbf);
279ee5b2fc6SMilanka Ringwald     int x0  = SBC_LHIST;
280ee5b2fc6SMilanka Ringwald     int x1  = x0 + SBC_FS - 1;
281ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, out_name, SBC_FS, plc_state->hist+x0);
282ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h2 = plot(b(%d:%d), %s, 'cd'); \n", x0, x1, out_name);
283ee5b2fc6SMilanka Ringwald 
284ee5b2fc6SMilanka Ringwald     char rest_hist_name[10];
285ee5b2fc6SMilanka Ringwald     sprintf(rest_hist_name, "rest%d", plc_state->nbf);
286ee5b2fc6SMilanka Ringwald     x0  = SBC_LHIST + SBC_FS;
287ee5b2fc6SMilanka Ringwald     x1  = x0 + SBC_OLAL + SBC_RT - 1;
288ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, rest_hist_name, SBC_OLAL + SBC_RT, plc_state->hist+x0);
289ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h3 = plot(b(%d:%d), %s, 'kd'); \n", x0, x1, rest_hist_name);
290ee5b2fc6SMilanka Ringwald 
291ee5b2fc6SMilanka Ringwald     char new_hist_name[10];
292ee5b2fc6SMilanka Ringwald     sprintf(new_hist_name, "hist%d", plc_state->nbf);
293ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, new_hist_name, SBC_LHIST, plc_state->hist);
294ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h4 = plot(%s, 'r--'); \n", new_hist_name);
295ee5b2fc6SMilanka Ringwald 
296ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "legend ([h1, h2, h3, h4], {\"hist\", \"out\", \"rest\", \"new hist\"}, \"location\", \"northeast\");\n ");
297ee5b2fc6SMilanka Ringwald 
298ee5b2fc6SMilanka Ringwald     char fig_name[1200];
299ee5b2fc6SMilanka Ringwald     sprintf(fig_name, "../%s_octave_plc_%d_%s", octave_base_name, plc_state->frame_count, octave_frame_type2str(octave_frame_type));
300ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "print(hf, \"%s.jpg\", \"-djpg\");", fig_name);
301ee5b2fc6SMilanka Ringwald }
302ee5b2fc6SMilanka Ringwald #endif
303ee5b2fc6SMilanka Ringwald 
304ee5b2fc6SMilanka Ringwald 
3054e4f6f26SMatthias Ringwald void btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *ZIRbuf, SAMPLE_FORMAT *out){
3064e074f72SMilanka Ringwald     float val;
3077e6b1e83SMilanka Ringwald     int   i = 0;
3087e6b1e83SMilanka Ringwald     float sf = 1;
3097e6b1e83SMilanka Ringwald     plc_state->nbf++;
3107e6b1e83SMilanka Ringwald 
311de854f9aSMilanka Ringwald     plc_state->bad_frames_nr++;
312de854f9aSMilanka Ringwald     plc_state->frame_count++;
313de854f9aSMilanka Ringwald     if (plc_state->max_consecutive_bad_frames_nr < plc_state->nbf){
314de854f9aSMilanka Ringwald         plc_state->max_consecutive_bad_frames_nr = plc_state->nbf;
315de854f9aSMilanka Ringwald     }
316de854f9aSMilanka Ringwald 
3174e074f72SMilanka Ringwald     if (plc_state->nbf==1){
31822183937SMilanka Ringwald         // printf("first bad frame\n");
3194e4f6f26SMatthias Ringwald         // Perform pattern matching to find where to replicate
3204e074f72SMilanka Ringwald         plc_state->bestlag = PatternMatch(plc_state->hist);
321ee5b2fc6SMilanka Ringwald     }
322ee5b2fc6SMilanka Ringwald 
323ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
324ee5b2fc6SMilanka Ringwald     FILE * oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_BAD);
325ee5b2fc6SMilanka Ringwald     if (oct_file){
326ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
327ee5b2fc6SMilanka Ringwald     }
328ee5b2fc6SMilanka Ringwald #endif
329ee5b2fc6SMilanka Ringwald 
330ee5b2fc6SMilanka Ringwald     if (plc_state->nbf==1){
3314e4f6f26SMatthias Ringwald         // the replication begins after the template match
3327e6b1e83SMilanka Ringwald         plc_state->bestlag += SBC_M;
3334e074f72SMilanka Ringwald 
3344e4f6f26SMatthias Ringwald         // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
3354e074f72SMilanka Ringwald         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
33622183937SMilanka Ringwald         // printf("sf Apmlitude Match %f, new data %d, bestlag+M %d\n", sf, ZIRbuf[0], plc_state->hist[plc_state->bestlag]);
3377e6b1e83SMilanka Ringwald         for (i=0;i<SBC_OLAL;i++){
3387e6b1e83SMilanka Ringwald             float left  = ZIRbuf[i];
3397e6b1e83SMilanka Ringwald             float right = sf*plc_state->hist[plc_state->bestlag+i];
34062f77245SMilanka Ringwald             val = left*rcos[i] + right*rcos[SBC_OLAL-1-i];
341ee5b2fc6SMilanka Ringwald             // val = sf*plc_state->hist[plc_state->bestlag+i];
3424e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3434e074f72SMilanka Ringwald         }
3444e074f72SMilanka Ringwald 
3457e6b1e83SMilanka Ringwald         for (;i<SBC_FS;i++){
3467e6b1e83SMilanka Ringwald             val = sf*plc_state->hist[plc_state->bestlag+i];
3474e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3484e074f72SMilanka Ringwald         }
3494e074f72SMilanka Ringwald 
3507e6b1e83SMilanka Ringwald         for (;i<SBC_FS+SBC_OLAL;i++){
3517e6b1e83SMilanka Ringwald             float left  = sf*plc_state->hist[plc_state->bestlag+i];
3527e6b1e83SMilanka Ringwald             float right = plc_state->hist[plc_state->bestlag+i];
3534e4f6f26SMatthias Ringwald             val = left*rcos[i-SBC_FS]+right*rcos[SBC_OLAL-1-i+SBC_FS];
3544e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3554e074f72SMilanka Ringwald         }
3564e074f72SMilanka Ringwald 
3577e6b1e83SMilanka Ringwald         for (;i<SBC_FS+SBC_RT+SBC_OLAL;i++){
3587e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3597e6b1e83SMilanka Ringwald         }
3604e074f72SMilanka Ringwald     } else {
36122183937SMilanka Ringwald         // printf("succesive bad frame nr %d\n", plc_state->nbf);
3624e4f6f26SMatthias Ringwald         for (;i<SBC_FS+SBC_RT+SBC_OLAL;i++){
3637e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3644e074f72SMilanka Ringwald         }
365c5e169ecSMilanka Ringwald     }
3667e6b1e83SMilanka Ringwald     for (i=0;i<SBC_FS;i++){
3677e6b1e83SMilanka Ringwald         out[i] = plc_state->hist[SBC_LHIST+i];
3687e6b1e83SMilanka Ringwald     }
3694e074f72SMilanka Ringwald 
3704e4f6f26SMatthias Ringwald    // shift the history buffer
3717e6b1e83SMilanka Ringwald     for (i=0;i<SBC_LHIST+SBC_RT+SBC_OLAL;i++){
3727e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
3737e6b1e83SMilanka Ringwald     }
374ee5b2fc6SMilanka Ringwald 
375ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
376ee5b2fc6SMilanka Ringwald     if (oct_file){
377ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
378ee5b2fc6SMilanka Ringwald         fclose(oct_file);
379ee5b2fc6SMilanka Ringwald     }
380ee5b2fc6SMilanka Ringwald #endif
3814e074f72SMilanka Ringwald }
3824e074f72SMilanka Ringwald 
3834e4f6f26SMatthias Ringwald void btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *in, SAMPLE_FORMAT *out){
3847e6b1e83SMilanka Ringwald     float val;
3857e6b1e83SMilanka Ringwald     int i = 0;
386de854f9aSMilanka Ringwald     plc_state->good_frames_nr++;
387de854f9aSMilanka Ringwald     plc_state->frame_count++;
388de854f9aSMilanka Ringwald 
389ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
390ee5b2fc6SMilanka Ringwald     FILE * oct_file = NULL;
391ee5b2fc6SMilanka Ringwald     if (plc_state->nbf>0){
392ee5b2fc6SMilanka Ringwald         oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_GOOD);
393ee5b2fc6SMilanka Ringwald         if (oct_file){
394ee5b2fc6SMilanka Ringwald             octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
395ee5b2fc6SMilanka Ringwald         }
396ee5b2fc6SMilanka Ringwald     }
397ee5b2fc6SMilanka Ringwald #endif
398ee5b2fc6SMilanka Ringwald 
3994e074f72SMilanka Ringwald     if (plc_state->nbf>0){
4007e6b1e83SMilanka Ringwald         for (i=0;i<SBC_RT;i++){
4017e6b1e83SMilanka Ringwald             out[i] = plc_state->hist[SBC_LHIST+i];
4024e074f72SMilanka Ringwald         }
4037e6b1e83SMilanka Ringwald 
4044e4f6f26SMatthias Ringwald         for (i = SBC_RT;i<SBC_RT+SBC_OLAL;i++){
4057e6b1e83SMilanka Ringwald             float left  = plc_state->hist[SBC_LHIST+i];
4067e6b1e83SMilanka Ringwald             float right = in[i];
4074e4f6f26SMatthias Ringwald             val = left*rcos[i-SBC_RT] + right*rcos[SBC_OLAL+SBC_RT-1-i];
408ee5b2fc6SMilanka Ringwald             out[i] = crop_sample(val);
4097e6b1e83SMilanka Ringwald         }
4107e6b1e83SMilanka Ringwald     }
4114e4f6f26SMatthias Ringwald 
4127e6b1e83SMilanka Ringwald     for (;i<SBC_FS;i++){
4134e074f72SMilanka Ringwald         out[i] = in[i];
4147e6b1e83SMilanka Ringwald     }
4154e4f6f26SMatthias Ringwald     // Copy the output to the history buffer
4167e6b1e83SMilanka Ringwald     for (i=0;i<SBC_FS;i++){
4177e6b1e83SMilanka Ringwald         plc_state->hist[SBC_LHIST+i] = out[i];
4187e6b1e83SMilanka Ringwald     }
419ee5b2fc6SMilanka Ringwald 
4204e4f6f26SMatthias Ringwald     // shift the history buffer
4217e6b1e83SMilanka Ringwald     for (i=0;i<SBC_LHIST;i++){
4227e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
4237e6b1e83SMilanka Ringwald     }
4247e6b1e83SMilanka Ringwald 
425ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
426ee5b2fc6SMilanka Ringwald     if (oct_file){
427ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
428ee5b2fc6SMilanka Ringwald         fclose(oct_file);
429ee5b2fc6SMilanka Ringwald     }
430ee5b2fc6SMilanka Ringwald #endif
4314e074f72SMilanka Ringwald     plc_state->nbf=0;
4324e074f72SMilanka Ringwald }
433de854f9aSMilanka Ringwald 
434de854f9aSMilanka Ringwald void btstack_sbc_dump_statistics(btstack_sbc_plc_state_t * state){
435de854f9aSMilanka Ringwald     log_info("Good frames: %d\n", state->good_frames_nr);
436de854f9aSMilanka Ringwald     log_info("Bad frames: %d\n", state->bad_frames_nr);
437de854f9aSMilanka Ringwald     log_info("Max Consecutive bad frames: %d\n", state->max_consecutive_bad_frames_nr);
438de854f9aSMilanka Ringwald }
439