xref: /btstack/src/classic/btstack_sbc_plc.c (revision 9b037397d77d71c5e4ed8fd7ecf2e874254781fb)
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 
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 
584e074f72SMilanka Ringwald static uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
594e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
604e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
614e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
624e074f72SMilanka Ringwald 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
634e074f72SMilanka Ringwald 
644e074f72SMilanka Ringwald /* Raised COSine table for OLA */
657e6b1e83SMilanka Ringwald static float rcos[SBC_OLAL] = {
664e074f72SMilanka Ringwald     0.99148655f,0.96623611f,0.92510857f,0.86950446f,
674e074f72SMilanka Ringwald     0.80131732f,0.72286918f,0.63683150f,0.54613418f,
684e074f72SMilanka Ringwald     0.45386582f,0.36316850f,0.27713082f,0.19868268f,
694e074f72SMilanka Ringwald     0.13049554f,0.07489143f,0.03376389f,0.00851345f};
704e074f72SMilanka Ringwald 
7140e1e61cSMilanka Ringwald // taken from http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
7240e1e61cSMilanka Ringwald // Algorithm: Babylonian Method + some manipulations on IEEE 32 bit floating point representation
7340e1e61cSMilanka Ringwald static float sqrt3(const float x){
7440e1e61cSMilanka Ringwald     union {
7540e1e61cSMilanka Ringwald         int i;
7640e1e61cSMilanka Ringwald         float x;
7740e1e61cSMilanka Ringwald     } u;
7840e1e61cSMilanka Ringwald     u.x = x;
7940e1e61cSMilanka Ringwald     u.i = (1<<29) + (u.i >> 1) - (1<<22);
8040e1e61cSMilanka Ringwald 
8140e1e61cSMilanka Ringwald     // Two Babylonian Steps (simplified from:)
8240e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
8340e1e61cSMilanka Ringwald     // u.x = 0.5f * (u.x + x/u.x);
84c1ab6cc1SMatthias Ringwald     u.x =       u.x + (x/u.x);
85c1ab6cc1SMatthias Ringwald     u.x = (0.25f*u.x) + (x/u.x);
8640e1e61cSMilanka Ringwald 
8740e1e61cSMilanka Ringwald     return u.x;
8840e1e61cSMilanka Ringwald }
8940e1e61cSMilanka Ringwald 
9040e1e61cSMilanka Ringwald static float absolute(float x){
9140e1e61cSMilanka Ringwald      if (x < 0) x = -x;
9240e1e61cSMilanka Ringwald      return x;
9340e1e61cSMilanka Ringwald }
9440e1e61cSMilanka Ringwald 
954e4f6f26SMatthias Ringwald static float CrossCorrelation(SAMPLE_FORMAT *x, SAMPLE_FORMAT *y){
96c5e169ecSMilanka Ringwald     float num = 0;
97c5e169ecSMilanka Ringwald     float den = 0;
98c5e169ecSMilanka Ringwald     float x2 = 0;
99c5e169ecSMilanka Ringwald     float y2 = 0;
100c5e169ecSMilanka Ringwald     int   m;
101c5e169ecSMilanka Ringwald     for (m=0;m<SBC_M;m++){
102c5e169ecSMilanka Ringwald         num+=((float)x[m])*y[m];
103c5e169ecSMilanka Ringwald         x2+=((float)x[m])*x[m];
104c5e169ecSMilanka Ringwald         y2+=((float)y[m])*y[m];
105c5e169ecSMilanka Ringwald     }
10640e1e61cSMilanka Ringwald     den = (float)sqrt3(x2*y2);
107c5e169ecSMilanka Ringwald     return num/den;
108c5e169ecSMilanka Ringwald }
109c5e169ecSMilanka Ringwald 
1104e4f6f26SMatthias Ringwald static int PatternMatch(SAMPLE_FORMAT *y){
1114e4f6f26SMatthias Ringwald     float maxCn = -999999.0;  // large negative number
112c5e169ecSMilanka Ringwald     int   bestmatch = 0;
113c5e169ecSMilanka Ringwald     float Cn;
114c5e169ecSMilanka Ringwald     int   n;
115c5e169ecSMilanka Ringwald     for (n=0;n<SBC_N;n++){
1164e4f6f26SMatthias Ringwald         Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]);
117c5e169ecSMilanka Ringwald         if (Cn>maxCn){
118c5e169ecSMilanka Ringwald             bestmatch=n;
119c5e169ecSMilanka Ringwald             maxCn = Cn;
120c5e169ecSMilanka Ringwald         }
121c5e169ecSMilanka Ringwald     }
122c5e169ecSMilanka Ringwald     return bestmatch;
123c5e169ecSMilanka Ringwald }
124c5e169ecSMilanka Ringwald 
1254e4f6f26SMatthias Ringwald static float AmplitudeMatch(SAMPLE_FORMAT *y, SAMPLE_FORMAT bestmatch) {
126c5e169ecSMilanka Ringwald     int   i;
127c5e169ecSMilanka Ringwald     float sumx = 0;
128c5e169ecSMilanka Ringwald     float sumy = 0.000001f;
129c5e169ecSMilanka Ringwald     float sf;
130c5e169ecSMilanka Ringwald 
131c5e169ecSMilanka Ringwald     for (i=0;i<SBC_FS;i++){
13240e1e61cSMilanka Ringwald         sumx += absolute(y[SBC_LHIST-SBC_FS+i]);
13340e1e61cSMilanka Ringwald         sumy += absolute(y[bestmatch+i]);
134c5e169ecSMilanka Ringwald     }
135c5e169ecSMilanka Ringwald     sf = sumx/sumy;
1364e4f6f26SMatthias Ringwald     // This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
137c5e169ecSMilanka Ringwald     if (sf<0.75f) sf=0.75f;
138ee5b2fc6SMilanka Ringwald     if (sf>1.0f) sf=1.0f;
139c5e169ecSMilanka Ringwald     return sf;
140c5e169ecSMilanka Ringwald }
1414e074f72SMilanka Ringwald 
1424e4f6f26SMatthias Ringwald static SAMPLE_FORMAT crop_sample(float val){
143250a1e4aSMilanka Ringwald     float croped_val = val;
144250a1e4aSMilanka Ringwald     if (croped_val > 32767.0)  croped_val= 32767.0;
145250a1e4aSMilanka Ringwald     if (croped_val < -32768.0) croped_val=-32768.0;
1464e4f6f26SMatthias Ringwald     return (SAMPLE_FORMAT) croped_val;
1477e6b1e83SMilanka Ringwald }
1487e6b1e83SMilanka Ringwald 
149e7a41128SMilanka Ringwald uint8_t * btstack_sbc_plc_zero_signal_frame(void){
1504e074f72SMilanka Ringwald     return (uint8_t *)&indices0;
1514e074f72SMilanka Ringwald }
1524e074f72SMilanka Ringwald 
153e7a41128SMilanka Ringwald void btstack_sbc_plc_init(btstack_sbc_plc_state_t *plc_state){
1544e074f72SMilanka Ringwald     plc_state->nbf=0;
1554e074f72SMilanka Ringwald     plc_state->bestlag=0;
156b3f76298SMilanka Ringwald     memset(plc_state->hist,0,sizeof(plc_state->hist));
1574e074f72SMilanka Ringwald }
1584e074f72SMilanka Ringwald 
159ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
160ee5b2fc6SMilanka Ringwald typedef enum {
161ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_UNKNOWN = 0,
162ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_GOOD,
163ee5b2fc6SMilanka Ringwald     OCTAVE_FRAME_TYPE_BAD
164ee5b2fc6SMilanka Ringwald } octave_frame_type_t;
165ee5b2fc6SMilanka Ringwald 
166ee5b2fc6SMilanka Ringwald static const char * octave_frame_type_name[] = {
167ee5b2fc6SMilanka Ringwald     "unknown",
168ee5b2fc6SMilanka Ringwald     "good",
169ee5b2fc6SMilanka Ringwald     "bad"
170ee5b2fc6SMilanka Ringwald };
171ee5b2fc6SMilanka Ringwald 
172ee5b2fc6SMilanka Ringwald static octave_frame_type_t octave_frame_type;
173ee5b2fc6SMilanka Ringwald static char octave_base_name[1000];
174ee5b2fc6SMilanka Ringwald 
175ee5b2fc6SMilanka Ringwald const char * octave_frame_type2str(int index){
176ee5b2fc6SMilanka Ringwald     if (index <= 0 || index >= sizeof(octave_frame_type_t)) return octave_frame_type_name[0];
177ee5b2fc6SMilanka Ringwald     return octave_frame_type_name[index];
178ee5b2fc6SMilanka Ringwald }
179ee5b2fc6SMilanka Ringwald 
180d1550f90SMilanka Ringwald void btstack_sbc_plc_octave_set_base_name(const char * base_name){
181ee5b2fc6SMilanka Ringwald     strcpy(octave_base_name, base_name);
182ee5b2fc6SMilanka Ringwald     printf("OCTAVE: base name set to %s\n", octave_base_name);
183ee5b2fc6SMilanka Ringwald }
184ee5b2fc6SMilanka Ringwald 
185ee5b2fc6SMilanka Ringwald static void octave_fprintf_array_int16(FILE * oct_file, char * name, int data_len, int16_t * data){
186ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s = [", name);
187ee5b2fc6SMilanka Ringwald     int i;
188ee5b2fc6SMilanka Ringwald     for (i = 0; i < data_len - 1; i++){
189ee5b2fc6SMilanka Ringwald         fprintf(oct_file, "%d, ", data[i]);
190ee5b2fc6SMilanka Ringwald     }
191ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%d", data[i]);
192ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "%s", "];\n");
193ee5b2fc6SMilanka Ringwald }
194ee5b2fc6SMilanka Ringwald 
195ee5b2fc6SMilanka Ringwald static FILE * open_octave_file(btstack_sbc_plc_state_t *plc_state, octave_frame_type_t frame_type){
196ee5b2fc6SMilanka Ringwald     char oct_file_name[1200];
197ee5b2fc6SMilanka Ringwald     octave_frame_type = frame_type;
198ee5b2fc6SMilanka Ringwald     sprintf(oct_file_name, "%s_octave_plc_%d_%s.m", octave_base_name, plc_state->frame_count, octave_frame_type2str(octave_frame_type));
199ee5b2fc6SMilanka Ringwald 
200ee5b2fc6SMilanka Ringwald     FILE * oct_file = fopen(oct_file_name, "wb");
201ee5b2fc6SMilanka Ringwald     if (oct_file == NULL){
202ee5b2fc6SMilanka Ringwald         printf("OCTAVE: could not open file %s\n", oct_file_name);
203ee5b2fc6SMilanka Ringwald         return NULL;
204ee5b2fc6SMilanka Ringwald     }
205ee5b2fc6SMilanka Ringwald     printf("OCTAVE: opened file %s\n", oct_file_name);
206ee5b2fc6SMilanka Ringwald     return oct_file;
207ee5b2fc6SMilanka Ringwald }
208ee5b2fc6SMilanka Ringwald 
209ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_history_frame(btstack_sbc_plc_state_t *plc_state, FILE * oct_file, int frame_nr){
210ee5b2fc6SMilanka Ringwald     char title[100];
211ee5b2fc6SMilanka Ringwald     char hist_name[10];
212ee5b2fc6SMilanka Ringwald     sprintf(hist_name, "hist%d", plc_state->nbf);
213ee5b2fc6SMilanka Ringwald 
214ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, hist_name, SBC_LHIST, plc_state->hist);
215ee5b2fc6SMilanka Ringwald 
216ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "y = [min(%s):1000:max(%s)];\n", hist_name, hist_name);
217ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "x = zeros(1, size(y,2));\n");
218ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "b = [0: %d];\n", SBC_LHIST+SBC_FS+SBC_RT+SBC_OLAL);
219ee5b2fc6SMilanka Ringwald 
220ee5b2fc6SMilanka Ringwald     int pos = SBC_FS;
221ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "shift_x = x + %d;\n", pos);
222ee5b2fc6SMilanka Ringwald 
223ee5b2fc6SMilanka Ringwald     pos = SBC_LHIST - 1;
224ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_x = x + %d;\n", pos);
225ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
226ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal1_x = x + %d;\n", pos);
227ee5b2fc6SMilanka Ringwald     pos += SBC_FS - SBC_OLAL;
228ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_fs_x = x + %d;\n", pos);
229ee5b2fc6SMilanka Ringwald     pos += SBC_OLAL;
230ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_olal2_x = x + %d;\n", pos);
231ee5b2fc6SMilanka Ringwald     pos += SBC_RT;
232ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "lhist_rt_x = x + %d;\n", pos);
233ee5b2fc6SMilanka Ringwald 
234ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "pattern_window_x = x + %d;\n", SBC_LHIST - SBC_M);
235ee5b2fc6SMilanka Ringwald 
236ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hf = figure();\n");
237ee5b2fc6SMilanka Ringwald     sprintf(title, "PLC %s frame %d", octave_frame_type2str(octave_frame_type), frame_nr);
238ee5b2fc6SMilanka Ringwald 
239ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "hold on;\n");
240ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h1 = plot(%s); \n", hist_name);
241ee5b2fc6SMilanka Ringwald 
242ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "title(\"%s\");\n", title);
243ee5b2fc6SMilanka Ringwald 
244ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_x, y, 'k'); \n");
245ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_x) - 10, max(y)+1000, 'lhist'); \n");
246ee5b2fc6SMilanka Ringwald 
247ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal1_x, y, 'k'); \n");
248ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal1_x) - 10, max(y)+1000, 'OLAL'); \n");
249ee5b2fc6SMilanka Ringwald 
250ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_fs_x, y, 'k'); \n");
251ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_fs_x) - 10, max(y)+1000, 'FS'); \n");
252ee5b2fc6SMilanka Ringwald 
253ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_olal2_x, y, 'k'); \n");
254ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_olal2_x) - 10, max(y)+1000, 'OLAL'); \n");
255ee5b2fc6SMilanka Ringwald 
256ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(lhist_rt_x, y, 'k');\n");
257ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(lhist_rt_x) - 10, max(y)+1000, 'RT'); \n");
258ee5b2fc6SMilanka Ringwald 
259ee5b2fc6SMilanka Ringwald     if (octave_frame_type == OCTAVE_FRAME_TYPE_GOOD) return;
260ee5b2fc6SMilanka Ringwald 
261ee5b2fc6SMilanka Ringwald     int x0 = plc_state->bestlag;
262ee5b2fc6SMilanka Ringwald     int x1 = plc_state->bestlag + SBC_M - 1;
263ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
264ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(%d - 10, -10, 'bestlag'); \n", x0);
265ee5b2fc6SMilanka Ringwald 
266ee5b2fc6SMilanka Ringwald     x0 = plc_state->bestlag + SBC_M ;
267ee5b2fc6SMilanka Ringwald     x1 = plc_state->bestlag + SBC_M + SBC_FS - 1;
268ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'kd'); \n", x0, x1, hist_name, x0, x1);
269ee5b2fc6SMilanka Ringwald 
270ee5b2fc6SMilanka Ringwald     x0 = SBC_LHIST - SBC_M;
271ee5b2fc6SMilanka Ringwald     x1 = SBC_LHIST - 1;
272ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(b(%d:%d), %s(%d:%d), 'rd'); \n", x0, x1, hist_name, x0, x1);
273ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "plot(pattern_window_x, y, 'g'); \n");
274ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "text(max(pattern_window_x) - 10, max(y)+1000, 'M'); \n");
275ee5b2fc6SMilanka Ringwald }
276ee5b2fc6SMilanka Ringwald 
277ee5b2fc6SMilanka Ringwald static void octave_fprintf_plot_output(btstack_sbc_plc_state_t *plc_state, FILE * oct_file){
278ee5b2fc6SMilanka Ringwald     if (!oct_file) return;
279ee5b2fc6SMilanka Ringwald     char out_name[10];
280ee5b2fc6SMilanka Ringwald     sprintf(out_name, "out%d", plc_state->nbf);
281ee5b2fc6SMilanka Ringwald     int x0  = SBC_LHIST;
282ee5b2fc6SMilanka Ringwald     int x1  = x0 + SBC_FS - 1;
283ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, out_name, SBC_FS, plc_state->hist+x0);
284ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h2 = plot(b(%d:%d), %s, 'cd'); \n", x0, x1, out_name);
285ee5b2fc6SMilanka Ringwald 
286ee5b2fc6SMilanka Ringwald     char rest_hist_name[10];
287ee5b2fc6SMilanka Ringwald     sprintf(rest_hist_name, "rest%d", plc_state->nbf);
288ee5b2fc6SMilanka Ringwald     x0  = SBC_LHIST + SBC_FS;
289ee5b2fc6SMilanka Ringwald     x1  = x0 + SBC_OLAL + SBC_RT - 1;
290ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, rest_hist_name, SBC_OLAL + SBC_RT, plc_state->hist+x0);
291ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h3 = plot(b(%d:%d), %s, 'kd'); \n", x0, x1, rest_hist_name);
292ee5b2fc6SMilanka Ringwald 
293ee5b2fc6SMilanka Ringwald     char new_hist_name[10];
294ee5b2fc6SMilanka Ringwald     sprintf(new_hist_name, "hist%d", plc_state->nbf);
295ee5b2fc6SMilanka Ringwald     octave_fprintf_array_int16(oct_file, new_hist_name, SBC_LHIST, plc_state->hist);
296ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "h4 = plot(%s, 'r--'); \n", new_hist_name);
297ee5b2fc6SMilanka Ringwald 
298ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "legend ([h1, h2, h3, h4], {\"hist\", \"out\", \"rest\", \"new hist\"}, \"location\", \"northeast\");\n ");
299ee5b2fc6SMilanka Ringwald 
300ee5b2fc6SMilanka Ringwald     char fig_name[1200];
301ee5b2fc6SMilanka Ringwald     sprintf(fig_name, "../%s_octave_plc_%d_%s", octave_base_name, plc_state->frame_count, octave_frame_type2str(octave_frame_type));
302ee5b2fc6SMilanka Ringwald     fprintf(oct_file, "print(hf, \"%s.jpg\", \"-djpg\");", fig_name);
303ee5b2fc6SMilanka Ringwald }
304ee5b2fc6SMilanka Ringwald #endif
305ee5b2fc6SMilanka Ringwald 
306ee5b2fc6SMilanka Ringwald 
3074e4f6f26SMatthias Ringwald void btstack_sbc_plc_bad_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *ZIRbuf, SAMPLE_FORMAT *out){
3084e074f72SMilanka Ringwald     float val;
309*9b037397SMilanka Ringwald     int   i;
3107e6b1e83SMilanka Ringwald     float sf = 1;
3117e6b1e83SMilanka Ringwald 
312*9b037397SMilanka Ringwald     plc_state->nbf++;
313de854f9aSMilanka Ringwald     plc_state->bad_frames_nr++;
314de854f9aSMilanka Ringwald     plc_state->frame_count++;
315*9b037397SMilanka Ringwald 
316de854f9aSMilanka Ringwald     if (plc_state->max_consecutive_bad_frames_nr < plc_state->nbf){
317de854f9aSMilanka Ringwald         plc_state->max_consecutive_bad_frames_nr = plc_state->nbf;
318de854f9aSMilanka Ringwald     }
319de854f9aSMilanka Ringwald 
3204e074f72SMilanka Ringwald     if (plc_state->nbf==1){
32122183937SMilanka Ringwald         // printf("first bad frame\n");
3224e4f6f26SMatthias Ringwald         // Perform pattern matching to find where to replicate
3234e074f72SMilanka Ringwald         plc_state->bestlag = PatternMatch(plc_state->hist);
324ee5b2fc6SMilanka Ringwald     }
325ee5b2fc6SMilanka Ringwald 
326ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
327ee5b2fc6SMilanka Ringwald     FILE * oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_BAD);
328ee5b2fc6SMilanka Ringwald     if (oct_file){
329ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
330ee5b2fc6SMilanka Ringwald     }
331ee5b2fc6SMilanka Ringwald #endif
332ee5b2fc6SMilanka Ringwald 
333ee5b2fc6SMilanka Ringwald     if (plc_state->nbf==1){
3344e4f6f26SMatthias Ringwald         // the replication begins after the template match
3357e6b1e83SMilanka Ringwald         plc_state->bestlag += SBC_M;
3364e074f72SMilanka Ringwald 
3374e4f6f26SMatthias Ringwald         // Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
3384e074f72SMilanka Ringwald         sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
33922183937SMilanka Ringwald         // printf("sf Apmlitude Match %f, new data %d, bestlag+M %d\n", sf, ZIRbuf[0], plc_state->hist[plc_state->bestlag]);
3407e6b1e83SMilanka Ringwald         for (i=0; i<SBC_OLAL; i++){
3417e6b1e83SMilanka Ringwald             float left  = ZIRbuf[i];
3427e6b1e83SMilanka Ringwald             float right = sf*plc_state->hist[plc_state->bestlag+i];
343c1ab6cc1SMatthias Ringwald             val = (left*rcos[i]) + (right*rcos[SBC_OLAL-1-i]);
344ee5b2fc6SMilanka Ringwald             // val = sf*plc_state->hist[plc_state->bestlag+i];
3454e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3464e074f72SMilanka Ringwald         }
3474e074f72SMilanka Ringwald 
348*9b037397SMilanka Ringwald         for (i=SBC_OLAL; i<SBC_FS; i++){
3497e6b1e83SMilanka Ringwald             val = sf*plc_state->hist[plc_state->bestlag+i];
3504e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3514e074f72SMilanka Ringwald         }
3524e074f72SMilanka Ringwald 
353*9b037397SMilanka Ringwald         for (i=SBC_FS; i<(SBC_FS+SBC_OLAL); i++){
3547e6b1e83SMilanka Ringwald             float left  = sf*plc_state->hist[plc_state->bestlag+i];
3557e6b1e83SMilanka Ringwald             float right = plc_state->hist[plc_state->bestlag+i];
356c1ab6cc1SMatthias Ringwald             val = (left*rcos[i-SBC_FS])+(right*rcos[SBC_OLAL-1-i+SBC_FS]);
3574e4f6f26SMatthias Ringwald             plc_state->hist[SBC_LHIST+i] = crop_sample(val);
3584e074f72SMilanka Ringwald         }
3594e074f72SMilanka Ringwald 
360*9b037397SMilanka Ringwald         for (i=(SBC_FS+SBC_OLAL); i<(SBC_FS+SBC_RT+SBC_OLAL); i++){
3617e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3627e6b1e83SMilanka Ringwald         }
3634e074f72SMilanka Ringwald     } else {
36422183937SMilanka Ringwald         // printf("succesive bad frame nr %d\n", plc_state->nbf);
365*9b037397SMilanka Ringwald         for (i=0; i<(SBC_FS+SBC_RT+SBC_OLAL); i++){
3667e6b1e83SMilanka Ringwald             plc_state->hist[SBC_LHIST+i] = plc_state->hist[plc_state->bestlag+i];
3674e074f72SMilanka Ringwald         }
368c5e169ecSMilanka Ringwald     }
3697e6b1e83SMilanka Ringwald     for (i=0; i<SBC_FS; i++){
3707e6b1e83SMilanka Ringwald         out[i] = plc_state->hist[SBC_LHIST+i];
3717e6b1e83SMilanka Ringwald     }
3724e074f72SMilanka Ringwald 
3734e4f6f26SMatthias Ringwald    // shift the history buffer
3740e588213SMatthias Ringwald     for (i=0; i<(SBC_LHIST+SBC_RT+SBC_OLAL); i++){
3757e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
3767e6b1e83SMilanka Ringwald     }
377ee5b2fc6SMilanka Ringwald 
378ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
379ee5b2fc6SMilanka Ringwald     if (oct_file){
380ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
381ee5b2fc6SMilanka Ringwald         fclose(oct_file);
382ee5b2fc6SMilanka Ringwald     }
383ee5b2fc6SMilanka Ringwald #endif
3844e074f72SMilanka Ringwald }
3854e074f72SMilanka Ringwald 
3864e4f6f26SMatthias Ringwald void btstack_sbc_plc_good_frame(btstack_sbc_plc_state_t *plc_state, SAMPLE_FORMAT *in, SAMPLE_FORMAT *out){
3877e6b1e83SMilanka Ringwald     float val;
3887e6b1e83SMilanka Ringwald     int i = 0;
389de854f9aSMilanka Ringwald     plc_state->good_frames_nr++;
390de854f9aSMilanka Ringwald     plc_state->frame_count++;
391de854f9aSMilanka Ringwald 
392ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
393ee5b2fc6SMilanka Ringwald     FILE * oct_file = NULL;
394ee5b2fc6SMilanka Ringwald     if (plc_state->nbf>0){
395ee5b2fc6SMilanka Ringwald         oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_GOOD);
396ee5b2fc6SMilanka Ringwald         if (oct_file){
397ee5b2fc6SMilanka Ringwald             octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count);
398ee5b2fc6SMilanka Ringwald         }
399ee5b2fc6SMilanka Ringwald     }
400ee5b2fc6SMilanka Ringwald #endif
401ee5b2fc6SMilanka Ringwald 
4024e074f72SMilanka Ringwald     if (plc_state->nbf>0){
4037e6b1e83SMilanka Ringwald         for (i=0;i<SBC_RT;i++){
4047e6b1e83SMilanka Ringwald             out[i] = plc_state->hist[SBC_LHIST+i];
4054e074f72SMilanka Ringwald         }
4067e6b1e83SMilanka Ringwald 
407c1ab6cc1SMatthias Ringwald         for (i = SBC_RT;i<(SBC_RT+SBC_OLAL);i++){
4087e6b1e83SMilanka Ringwald             float left  = plc_state->hist[SBC_LHIST+i];
4097e6b1e83SMilanka Ringwald             float right = in[i];
410c1ab6cc1SMatthias Ringwald             val = (left*rcos[i-SBC_RT]) + (right*rcos[SBC_OLAL+SBC_RT-1-i]);
411ee5b2fc6SMilanka Ringwald             out[i] = crop_sample(val);
4127e6b1e83SMilanka Ringwald         }
4137e6b1e83SMilanka Ringwald     }
4144e4f6f26SMatthias Ringwald 
4157e6b1e83SMilanka Ringwald     for (;i<SBC_FS;i++){
4164e074f72SMilanka Ringwald         out[i] = in[i];
4177e6b1e83SMilanka Ringwald     }
4184e4f6f26SMatthias Ringwald     // Copy the output to the history buffer
4197e6b1e83SMilanka Ringwald     for (i=0;i<SBC_FS;i++){
4207e6b1e83SMilanka Ringwald         plc_state->hist[SBC_LHIST+i] = out[i];
4217e6b1e83SMilanka Ringwald     }
422ee5b2fc6SMilanka Ringwald 
4234e4f6f26SMatthias Ringwald     // shift the history buffer
4247e6b1e83SMilanka Ringwald     for (i=0;i<SBC_LHIST;i++){
4257e6b1e83SMilanka Ringwald         plc_state->hist[i] = plc_state->hist[i+SBC_FS];
4267e6b1e83SMilanka Ringwald     }
4277e6b1e83SMilanka Ringwald 
428ee5b2fc6SMilanka Ringwald #ifdef OCTAVE_OUTPUT
429ee5b2fc6SMilanka Ringwald     if (oct_file){
430ee5b2fc6SMilanka Ringwald         octave_fprintf_plot_output(plc_state, oct_file);
431ee5b2fc6SMilanka Ringwald         fclose(oct_file);
432ee5b2fc6SMilanka Ringwald     }
433ee5b2fc6SMilanka Ringwald #endif
4344e074f72SMilanka Ringwald     plc_state->nbf=0;
4354e074f72SMilanka Ringwald }
436de854f9aSMilanka Ringwald 
437de854f9aSMilanka Ringwald void btstack_sbc_dump_statistics(btstack_sbc_plc_state_t * state){
438de854f9aSMilanka Ringwald     log_info("Good frames: %d\n", state->good_frames_nr);
439de854f9aSMilanka Ringwald     log_info("Bad frames: %d\n", state->bad_frames_nr);
440de854f9aSMilanka Ringwald     log_info("Max Consecutive bad frames: %d\n", state->max_consecutive_bad_frames_nr);
441de854f9aSMilanka Ringwald }
442