xref: /btstack/src/classic/btstack_sbc_plc.c (revision a2c7346fc66c3c469b87742638169aeea91dd632)
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 
58*a2c7346fSMatthias Ringwald // Zero Frame (57 bytes) with padding zeros to avoid out of bound reads
59*a2c7346fSMatthias Ringwald static uint8_t indices0[] = {
60*a2c7346fSMatthias Ringwald     0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
61*a2c7346fSMatthias Ringwald     0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6,
62*a2c7346fSMatthias Ringwald     0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb,
63*a2c7346fSMatthias Ringwald     0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d,
64*a2c7346fSMatthias Ringwald     0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6,
65*a2c7346fSMatthias Ringwald     0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c,
66*a2c7346fSMatthias Ringwald     /*                padding            */   0x00, 0x00, 0x00
67*a2c7346fSMatthias 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,
74*a2c7346fSMatthias Ringwald     0.13049554f,0.07489143f,0.03376389f,0.00851345f
75*a2c7346fSMatthias 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
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 
9640e1e61cSMilanka Ringwald static float absolute(float x){
9740e1e61cSMilanka Ringwald      if (x < 0) x = -x;
9840e1e61cSMilanka Ringwald      return x;
9940e1e61cSMilanka Ringwald }
10040e1e61cSMilanka Ringwald 
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 
1164e4f6f26SMatthias Ringwald static int PatternMatch(SAMPLE_FORMAT *y){
1174e4f6f26SMatthias Ringwald     float maxCn = -999999.0;  // 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 
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 
1484e4f6f26SMatthias Ringwald static SAMPLE_FORMAT crop_sample(float val){
149250a1e4aSMilanka Ringwald     float croped_val = val;
150250a1e4aSMilanka Ringwald     if (croped_val > 32767.0)  croped_val= 32767.0;
151250a1e4aSMilanka Ringwald     if (croped_val < -32768.0) croped_val=-32768.0;
1524e4f6f26SMatthias Ringwald     return (SAMPLE_FORMAT) croped_val;
1537e6b1e83SMilanka Ringwald }
1547e6b1e83SMilanka Ringwald 
155e7a41128SMilanka Ringwald uint8_t * btstack_sbc_plc_zero_signal_frame(void){
1564e074f72SMilanka Ringwald     return (uint8_t *)&indices0;
1574e074f72SMilanka Ringwald }
1584e074f72SMilanka Ringwald 
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 
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 
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 
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 
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 
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 
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 
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 
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 
455de854f9aSMilanka Ringwald void btstack_sbc_dump_statistics(btstack_sbc_plc_state_t * state){
456de854f9aSMilanka Ringwald     log_info("Good frames: %d\n", state->good_frames_nr);
457de854f9aSMilanka Ringwald     log_info("Bad frames: %d\n", state->bad_frames_nr);
458de854f9aSMilanka Ringwald     log_info("Max Consecutive bad frames: %d\n", state->max_consecutive_bad_frames_nr);
459de854f9aSMilanka Ringwald }
460