xref: /btstack/test/le_audio/lc3_test.c (revision 533ea81febb4126dd506c94e83cc8f96e8197e91)
1*533ea81fSMatthias Ringwald /*
2*533ea81fSMatthias Ringwald  * Copyright (C) 2022 BlueKitchen GmbH
3*533ea81fSMatthias Ringwald  *
4*533ea81fSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*533ea81fSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*533ea81fSMatthias Ringwald  * are met:
7*533ea81fSMatthias Ringwald  *
8*533ea81fSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*533ea81fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*533ea81fSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*533ea81fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*533ea81fSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*533ea81fSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*533ea81fSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*533ea81fSMatthias Ringwald  *    from this software without specific prior written permission.
16*533ea81fSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*533ea81fSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*533ea81fSMatthias Ringwald  *    monetary gain.
19*533ea81fSMatthias Ringwald  *
20*533ea81fSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*533ea81fSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*533ea81fSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*533ea81fSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*533ea81fSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*533ea81fSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*533ea81fSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*533ea81fSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*533ea81fSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*533ea81fSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*533ea81fSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*533ea81fSMatthias Ringwald  * SUCH DAMAGE.
32*533ea81fSMatthias Ringwald  *
33*533ea81fSMatthias Ringwald  * Please inquire about commercial licensing options at
34*533ea81fSMatthias Ringwald  * [email protected]
35*533ea81fSMatthias Ringwald  *
36*533ea81fSMatthias Ringwald  */
37*533ea81fSMatthias Ringwald 
38*533ea81fSMatthias Ringwald #define BTSTACK_FILE__ "lc3_test.c"
39*533ea81fSMatthias Ringwald 
40*533ea81fSMatthias Ringwald /*
41*533ea81fSMatthias Ringwald  * Measure LC3 encoding load
42*533ea81fSMatthias Ringwald  */
43*533ea81fSMatthias Ringwald 
44*533ea81fSMatthias Ringwald #include <stdint.h>
45*533ea81fSMatthias Ringwald #include <stdio.h>
46*533ea81fSMatthias Ringwald #include <string.h>
47*533ea81fSMatthias Ringwald #include <btstack_debug.h>
48*533ea81fSMatthias Ringwald 
49*533ea81fSMatthias Ringwald #include "bluetooth_data_types.h"
50*533ea81fSMatthias Ringwald #include "btstack_stdin.h"
51*533ea81fSMatthias Ringwald #include "btstack_event.h"
52*533ea81fSMatthias Ringwald #include "btstack_run_loop.h"
53*533ea81fSMatthias Ringwald #include "gap.h"
54*533ea81fSMatthias Ringwald #include "hci.h"
55*533ea81fSMatthias Ringwald #include "hci_cmd.h"
56*533ea81fSMatthias Ringwald #include "hci_dump.h"
57*533ea81fSMatthias Ringwald #include "btstack_lc3.h"
58*533ea81fSMatthias Ringwald #include "btstack_lc3_google.h"
59*533ea81fSMatthias Ringwald 
60*533ea81fSMatthias Ringwald #include "hxcmod.h"
61*533ea81fSMatthias Ringwald #include "mods/mod.h"
62*533ea81fSMatthias Ringwald 
63*533ea81fSMatthias Ringwald 
64*533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
65*533ea81fSMatthias Ringwald #include "wav_util.h"
66*533ea81fSMatthias Ringwald #endif
67*533ea81fSMatthias Ringwald 
68*533ea81fSMatthias Ringwald // max config
69*533ea81fSMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
70*533ea81fSMatthias Ringwald #define MAX_NUM_BIS 2
71*533ea81fSMatthias Ringwald 
72*533ea81fSMatthias Ringwald // lc3 codec config
73*533ea81fSMatthias Ringwald static uint32_t sampling_frequency_hz;
74*533ea81fSMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration;
75*533ea81fSMatthias Ringwald static uint16_t number_samples_per_frame;
76*533ea81fSMatthias Ringwald static uint16_t octets_per_frame;
77*533ea81fSMatthias Ringwald static uint8_t  num_bis = 1;
78*533ea81fSMatthias Ringwald 
79*533ea81fSMatthias Ringwald // lc3 encoder
80*533ea81fSMatthias Ringwald static const btstack_lc3_encoder_t * lc3_encoder;
81*533ea81fSMatthias Ringwald static btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_BIS];
82*533ea81fSMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
83*533ea81fSMatthias Ringwald 
84*533ea81fSMatthias Ringwald // lc3 decoder
85*533ea81fSMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
86*533ea81fSMatthias Ringwald static btstack_lc3_decoder_google_t decoder_contexts[MAX_NUM_BIS];
87*533ea81fSMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
88*533ea81fSMatthias Ringwald 
89*533ea81fSMatthias Ringwald // PLC
90*533ea81fSMatthias Ringwald static uint16_t plc_frame_counter;
91*533ea81fSMatthias Ringwald static uint16_t plc_dopped_frame_interval;
92*533ea81fSMatthias Ringwald 
93*533ea81fSMatthias Ringwald // codec menu
94*533ea81fSMatthias Ringwald static uint8_t menu_sampling_frequency;
95*533ea81fSMatthias Ringwald static uint8_t menu_variant;
96*533ea81fSMatthias Ringwald 
97*533ea81fSMatthias Ringwald // mod player
98*533ea81fSMatthias Ringwald static int hxcmod_initialized;
99*533ea81fSMatthias Ringwald static modcontext mod_context;
100*533ea81fSMatthias Ringwald static tracker_buffer_state trkbuf;
101*533ea81fSMatthias Ringwald 
102*533ea81fSMatthias Ringwald // sine generator
103*533ea81fSMatthias Ringwald static uint8_t  sine_step;
104*533ea81fSMatthias Ringwald static uint16_t sine_phases[MAX_NUM_BIS];
105*533ea81fSMatthias Ringwald 
106*533ea81fSMatthias Ringwald // audio producer
107*533ea81fSMatthias Ringwald static enum {
108*533ea81fSMatthias Ringwald     AUDIO_SOURCE_SINE,
109*533ea81fSMatthias Ringwald     AUDIO_SOURCE_MODPLAYER
110*533ea81fSMatthias Ringwald } audio_source = AUDIO_SOURCE_MODPLAYER;
111*533ea81fSMatthias Ringwald 
112*533ea81fSMatthias Ringwald // enumerate default codec configs
113*533ea81fSMatthias Ringwald static struct {
114*533ea81fSMatthias Ringwald     uint32_t samplingrate_hz;
115*533ea81fSMatthias Ringwald     uint8_t  samplingrate_index;
116*533ea81fSMatthias Ringwald     uint8_t  num_variants;
117*533ea81fSMatthias Ringwald     struct {
118*533ea81fSMatthias Ringwald         const char * name;
119*533ea81fSMatthias Ringwald         btstack_lc3_frame_duration_t frame_duration;
120*533ea81fSMatthias Ringwald         uint16_t octets_per_frame;
121*533ea81fSMatthias Ringwald     } variants[6];
122*533ea81fSMatthias Ringwald } codec_configurations[] = {
123*533ea81fSMatthias Ringwald     {
124*533ea81fSMatthias Ringwald         8000, 0x01, 2,
125*533ea81fSMatthias Ringwald         {
126*533ea81fSMatthias Ringwald             {  "8_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 26},
127*533ea81fSMatthias Ringwald             {  "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
128*533ea81fSMatthias Ringwald         }
129*533ea81fSMatthias Ringwald     },
130*533ea81fSMatthias Ringwald     {
131*533ea81fSMatthias Ringwald        16000, 0x03, 2,
132*533ea81fSMatthias Ringwald        {
133*533ea81fSMatthias Ringwald             {  "16_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 30},
134*533ea81fSMatthias Ringwald             {  "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
135*533ea81fSMatthias Ringwald        }
136*533ea81fSMatthias Ringwald     },
137*533ea81fSMatthias Ringwald     {
138*533ea81fSMatthias Ringwald         24000, 0x05, 2,
139*533ea81fSMatthias Ringwald         {
140*533ea81fSMatthias Ringwald             {  "24_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 45},
141*533ea81fSMatthias Ringwald             {  "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
142*533ea81fSMatthias Ringwald        }
143*533ea81fSMatthias Ringwald     },
144*533ea81fSMatthias Ringwald     {
145*533ea81fSMatthias Ringwald         32000, 0x06, 2,
146*533ea81fSMatthias Ringwald         {
147*533ea81fSMatthias Ringwald             {  "32_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 60},
148*533ea81fSMatthias Ringwald             {  "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
149*533ea81fSMatthias Ringwald         }
150*533ea81fSMatthias Ringwald     },
151*533ea81fSMatthias Ringwald     {
152*533ea81fSMatthias Ringwald         44100, 0x07, 2,
153*533ea81fSMatthias Ringwald         {
154*533ea81fSMatthias Ringwald             { "441_1",  BTSTACK_LC3_FRAME_DURATION_7500US,  97},
155*533ea81fSMatthias Ringwald             { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
156*533ea81fSMatthias Ringwald         }
157*533ea81fSMatthias Ringwald     },
158*533ea81fSMatthias Ringwald     {
159*533ea81fSMatthias Ringwald         48000, 0x08, 6,
160*533ea81fSMatthias Ringwald         {
161*533ea81fSMatthias Ringwald             {  "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
162*533ea81fSMatthias Ringwald             {  "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
163*533ea81fSMatthias Ringwald             {  "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
164*533ea81fSMatthias Ringwald             {  "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
165*533ea81fSMatthias Ringwald             {  "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
166*533ea81fSMatthias Ringwald             {  "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
167*533ea81fSMatthias Ringwald         }
168*533ea81fSMatthias Ringwald     },
169*533ea81fSMatthias Ringwald };
170*533ea81fSMatthias Ringwald 
171*533ea81fSMatthias Ringwald 
172*533ea81fSMatthias Ringwald // input signal: pre-computed int16 sine wave, 96000 Hz at 300 Hz
173*533ea81fSMatthias Ringwald static const int16_t sine_int16[] = {
174*533ea81fSMatthias Ringwald         0,    643,   1286,   1929,   2571,   3212,   3851,   4489,   5126,   5760,
175*533ea81fSMatthias Ringwald         6393,   7022,   7649,   8273,   8894,   9512,  10126,  10735,  11341,  11943,
176*533ea81fSMatthias Ringwald         12539,  13131,  13718,  14300,  14876,  15446,  16011,  16569,  17121,  17666,
177*533ea81fSMatthias Ringwald         18204,  18736,  19260,  19777,  20286,  20787,  21280,  21766,  22242,  22710,
178*533ea81fSMatthias Ringwald         23170,  23620,  24062,  24494,  24916,  25329,  25732,  26126,  26509,  26882,
179*533ea81fSMatthias Ringwald         27245,  27597,  27938,  28269,  28589,  28898,  29196,  29482,  29757,  30021,
180*533ea81fSMatthias Ringwald         30273,  30513,  30742,  30958,  31163,  31356,  31537,  31705,  31862,  32006,
181*533ea81fSMatthias Ringwald         32137,  32257,  32364,  32458,  32540,  32609,  32666,  32710,  32742,  32761,
182*533ea81fSMatthias Ringwald         32767,  32761,  32742,  32710,  32666,  32609,  32540,  32458,  32364,  32257,
183*533ea81fSMatthias Ringwald         32137,  32006,  31862,  31705,  31537,  31356,  31163,  30958,  30742,  30513,
184*533ea81fSMatthias Ringwald         30273,  30021,  29757,  29482,  29196,  28898,  28589,  28269,  27938,  27597,
185*533ea81fSMatthias Ringwald         27245,  26882,  26509,  26126,  25732,  25329,  24916,  24494,  24062,  23620,
186*533ea81fSMatthias Ringwald         23170,  22710,  22242,  21766,  21280,  20787,  20286,  19777,  19260,  18736,
187*533ea81fSMatthias Ringwald         18204,  17666,  17121,  16569,  16011,  15446,  14876,  14300,  13718,  13131,
188*533ea81fSMatthias Ringwald         12539,  11943,  11341,  10735,  10126,   9512,   8894,   8273,   7649,   7022,
189*533ea81fSMatthias Ringwald         6393,   5760,   5126,   4489,   3851,   3212,   2571,   1929,   1286,    643,
190*533ea81fSMatthias Ringwald         0,   -643,  -1286,  -1929,  -2571,  -3212,  -3851,  -4489,  -5126,  -5760,
191*533ea81fSMatthias Ringwald         -6393,  -7022,  -7649,  -8273,  -8894,  -9512, -10126, -10735, -11341, -11943,
192*533ea81fSMatthias Ringwald         -12539, -13131, -13718, -14300, -14876, -15446, -16011, -16569, -17121, -17666,
193*533ea81fSMatthias Ringwald         -18204, -18736, -19260, -19777, -20286, -20787, -21280, -21766, -22242, -22710,
194*533ea81fSMatthias Ringwald         -23170, -23620, -24062, -24494, -24916, -25329, -25732, -26126, -26509, -26882,
195*533ea81fSMatthias Ringwald         -27245, -27597, -27938, -28269, -28589, -28898, -29196, -29482, -29757, -30021,
196*533ea81fSMatthias Ringwald         -30273, -30513, -30742, -30958, -31163, -31356, -31537, -31705, -31862, -32006,
197*533ea81fSMatthias Ringwald         -32137, -32257, -32364, -32458, -32540, -32609, -32666, -32710, -32742, -32761,
198*533ea81fSMatthias Ringwald         -32767, -32761, -32742, -32710, -32666, -32609, -32540, -32458, -32364, -32257,
199*533ea81fSMatthias Ringwald         -32137, -32006, -31862, -31705, -31537, -31356, -31163, -30958, -30742, -30513,
200*533ea81fSMatthias Ringwald         -30273, -30021, -29757, -29482, -29196, -28898, -28589, -28269, -27938, -27597,
201*533ea81fSMatthias Ringwald         -27245, -26882, -26509, -26126, -25732, -25329, -24916, -24494, -24062, -23620,
202*533ea81fSMatthias Ringwald         -23170, -22710, -22242, -21766, -21280, -20787, -20286, -19777, -19260, -18736,
203*533ea81fSMatthias Ringwald         -18204, -17666, -17121, -16569, -16011, -15446, -14876, -14300, -13718, -13131,
204*533ea81fSMatthias Ringwald         -12539, -11943, -11341, -10735, -10126,  -9512,  -8894,  -8273,  -7649,  -7022,
205*533ea81fSMatthias Ringwald         -6393,  -5760,  -5126,  -4489,  -3851,  -3212,  -2571,  -1929,  -1286,   -643,
206*533ea81fSMatthias Ringwald };
207*533ea81fSMatthias Ringwald 
208*533ea81fSMatthias Ringwald static void show_usage(void);
209*533ea81fSMatthias Ringwald 
210*533ea81fSMatthias Ringwald static void print_config(void) {
211*533ea81fSMatthias Ringwald     printf("Config '%s_%u': %u, %s ms, %u octets - %s, drop frame interval %u\n",
212*533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
213*533ea81fSMatthias Ringwald            num_bis,
214*533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].samplingrate_hz,
215*533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
216*533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
217*533ea81fSMatthias Ringwald            audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer",
218*533ea81fSMatthias Ringwald            plc_dopped_frame_interval);
219*533ea81fSMatthias Ringwald }
220*533ea81fSMatthias Ringwald 
221*533ea81fSMatthias Ringwald static void setup_lc3_encoder(void){
222*533ea81fSMatthias Ringwald     uint8_t channel;
223*533ea81fSMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
224*533ea81fSMatthias Ringwald         btstack_lc3_encoder_google_t * context = &encoder_contexts[channel];
225*533ea81fSMatthias Ringwald         lc3_encoder = btstack_lc3_encoder_google_init_instance(context);
226*533ea81fSMatthias Ringwald         lc3_encoder->configure(context, sampling_frequency_hz, frame_duration);
227*533ea81fSMatthias Ringwald     }
228*533ea81fSMatthias Ringwald     number_samples_per_frame = lc3_encoder->get_number_samples_per_frame(&encoder_contexts[0]);
229*533ea81fSMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
230*533ea81fSMatthias Ringwald     printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n",
231*533ea81fSMatthias Ringwald            sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
232*533ea81fSMatthias Ringwald            number_samples_per_frame, octets_per_frame);
233*533ea81fSMatthias Ringwald }
234*533ea81fSMatthias Ringwald 
235*533ea81fSMatthias Ringwald static void setup_lc3_decoder(void){
236*533ea81fSMatthias Ringwald     uint8_t channel;
237*533ea81fSMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
238*533ea81fSMatthias Ringwald         btstack_lc3_decoder_google_t * decoder_context = &decoder_contexts[channel];
239*533ea81fSMatthias Ringwald         lc3_decoder = btstack_lc3_decoder_google_init_instance(decoder_context);
240*533ea81fSMatthias Ringwald         lc3_decoder->configure(decoder_context, sampling_frequency_hz, frame_duration);
241*533ea81fSMatthias Ringwald     }
242*533ea81fSMatthias Ringwald     number_samples_per_frame = lc3_decoder->get_number_samples_per_frame(&decoder_contexts[0]);
243*533ea81fSMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
244*533ea81fSMatthias Ringwald }
245*533ea81fSMatthias Ringwald 
246*533ea81fSMatthias Ringwald static void setup_mod_player(void){
247*533ea81fSMatthias Ringwald     if (!hxcmod_initialized) {
248*533ea81fSMatthias Ringwald         hxcmod_initialized = hxcmod_init(&mod_context);
249*533ea81fSMatthias Ringwald         btstack_assert(hxcmod_initialized != 0);
250*533ea81fSMatthias Ringwald     }
251*533ea81fSMatthias Ringwald     hxcmod_unload(&mod_context);
252*533ea81fSMatthias Ringwald     hxcmod_setcfg(&mod_context, sampling_frequency_hz, 16, 1, 1, 1);
253*533ea81fSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
254*533ea81fSMatthias Ringwald }
255*533ea81fSMatthias Ringwald 
256*533ea81fSMatthias Ringwald static void generate_audio(void){
257*533ea81fSMatthias Ringwald     uint16_t sample;
258*533ea81fSMatthias Ringwald     switch (audio_source) {
259*533ea81fSMatthias Ringwald         case AUDIO_SOURCE_SINE:
260*533ea81fSMatthias Ringwald             // generate sine wave for all channels
261*533ea81fSMatthias Ringwald             for (sample = 0 ; sample < number_samples_per_frame ; sample++){
262*533ea81fSMatthias Ringwald                 uint8_t channel;
263*533ea81fSMatthias Ringwald                 for (channel = 0; channel < num_bis; channel++) {
264*533ea81fSMatthias Ringwald                     int16_t value = sine_int16[sine_phases[channel]] / 4;
265*533ea81fSMatthias Ringwald                     pcm[sample * num_bis + channel] = value;
266*533ea81fSMatthias Ringwald                     sine_phases[channel] += sine_step * (1+channel);    // second channel, double frequency
267*533ea81fSMatthias Ringwald                     if (sine_phases[channel] >= (sizeof(sine_int16) / sizeof(int16_t))) {
268*533ea81fSMatthias Ringwald                         sine_phases[channel] = 0;
269*533ea81fSMatthias Ringwald                     }
270*533ea81fSMatthias Ringwald                 }
271*533ea81fSMatthias Ringwald             }
272*533ea81fSMatthias Ringwald             break;
273*533ea81fSMatthias Ringwald         case AUDIO_SOURCE_MODPLAYER:
274*533ea81fSMatthias Ringwald             // mod player configured for stereo
275*533ea81fSMatthias Ringwald             hxcmod_fillbuffer(&mod_context, (unsigned short *) pcm, number_samples_per_frame, &trkbuf);
276*533ea81fSMatthias Ringwald             if (num_bis == 1) {
277*533ea81fSMatthias Ringwald                 // stereo -> mono
278*533ea81fSMatthias Ringwald                 uint16_t i;
279*533ea81fSMatthias Ringwald                 for (i=0;i<number_samples_per_frame;i++){
280*533ea81fSMatthias Ringwald                     pcm[i] = (pcm[2*i] / 2) + (pcm[2*i+1] / 2);
281*533ea81fSMatthias Ringwald                 }
282*533ea81fSMatthias Ringwald             }
283*533ea81fSMatthias Ringwald             break;
284*533ea81fSMatthias Ringwald         default:
285*533ea81fSMatthias Ringwald             btstack_unreachable();
286*533ea81fSMatthias Ringwald             break;
287*533ea81fSMatthias Ringwald     }
288*533ea81fSMatthias Ringwald }
289*533ea81fSMatthias Ringwald 
290*533ea81fSMatthias Ringwald static void test_encoder(){
291*533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
292*533ea81fSMatthias Ringwald     wav_writer_open("lc3_test.wav", 1, sampling_frequency_hz);
293*533ea81fSMatthias Ringwald #endif
294*533ea81fSMatthias Ringwald 
295*533ea81fSMatthias Ringwald     // encode 10 seconds of music
296*533ea81fSMatthias Ringwald     uint32_t audio_duration_in_seconds = 10;
297*533ea81fSMatthias Ringwald     uint32_t total_samples = sampling_frequency_hz * audio_duration_in_seconds;
298*533ea81fSMatthias Ringwald     uint32_t generated_samples = 0;
299*533ea81fSMatthias Ringwald     uint32_t player_ms = 0;
300*533ea81fSMatthias Ringwald     uint32_t encoder_ms = 0;
301*533ea81fSMatthias Ringwald     uint32_t decoder_ms = 0;
302*533ea81fSMatthias Ringwald     plc_frame_counter = 0;
303*533ea81fSMatthias Ringwald 
304*533ea81fSMatthias Ringwald     printf("Encoding and decoding %u seconds of audio...\n", audio_duration_in_seconds);
305*533ea81fSMatthias Ringwald     while (generated_samples < total_samples){
306*533ea81fSMatthias Ringwald 
307*533ea81fSMatthias Ringwald         // generate audio
308*533ea81fSMatthias Ringwald         uint32_t block_start_ms = btstack_run_loop_get_time_ms();
309*533ea81fSMatthias Ringwald         generate_audio();
310*533ea81fSMatthias Ringwald         uint32_t block_generated_ms  = btstack_run_loop_get_time_ms();
311*533ea81fSMatthias Ringwald 
312*533ea81fSMatthias Ringwald         // encode frame
313*533ea81fSMatthias Ringwald         uint8_t buffer[200];
314*533ea81fSMatthias Ringwald         lc3_encoder->encode_signed_16(&encoder_contexts[0], pcm, 1, buffer, octets_per_frame);
315*533ea81fSMatthias Ringwald         generated_samples += number_samples_per_frame;
316*533ea81fSMatthias Ringwald         uint32_t block_encoded_ms  = btstack_run_loop_get_time_ms();
317*533ea81fSMatthias Ringwald         plc_frame_counter++;
318*533ea81fSMatthias Ringwald 
319*533ea81fSMatthias Ringwald         uint8_t BFI = 0;
320*533ea81fSMatthias Ringwald         // simulate dropped packets
321*533ea81fSMatthias Ringwald         if ((plc_dopped_frame_interval != 0) && (plc_frame_counter == plc_dopped_frame_interval)){
322*533ea81fSMatthias Ringwald             plc_frame_counter = 0;
323*533ea81fSMatthias Ringwald             BFI = 1;
324*533ea81fSMatthias Ringwald         }
325*533ea81fSMatthias Ringwald 
326*533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
327*533ea81fSMatthias Ringwald         if (BFI){
328*533ea81fSMatthias Ringwald             // insert silence before for analysis in audacity
329*533ea81fSMatthias Ringwald             memset(pcm, 0, sizeof(pcm));
330*533ea81fSMatthias Ringwald             wav_writer_write_int16(number_samples_per_frame, pcm);
331*533ea81fSMatthias Ringwald         }
332*533ea81fSMatthias Ringwald #endif
333*533ea81fSMatthias Ringwald 
334*533ea81fSMatthias Ringwald         // decode codec frame
335*533ea81fSMatthias Ringwald         uint8_t tmp_BEC_detect;
336*533ea81fSMatthias Ringwald         (void) lc3_decoder->decode_signed_16(&decoder_contexts[0], buffer, octets_per_frame, BFI, pcm, 1, &tmp_BEC_detect);
337*533ea81fSMatthias Ringwald 
338*533ea81fSMatthias Ringwald         uint32_t block_decoded_ms  = btstack_run_loop_get_time_ms();
339*533ea81fSMatthias Ringwald 
340*533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
341*533ea81fSMatthias Ringwald         wav_writer_write_int16(number_samples_per_frame, pcm);
342*533ea81fSMatthias Ringwald         if (BFI){
343*533ea81fSMatthias Ringwald             // insert silence after for analysis in audacity
344*533ea81fSMatthias Ringwald             memset(pcm, 0, sizeof(pcm));
345*533ea81fSMatthias Ringwald             wav_writer_write_int16(number_samples_per_frame, pcm);
346*533ea81fSMatthias Ringwald         }
347*533ea81fSMatthias Ringwald #endif
348*533ea81fSMatthias Ringwald 
349*533ea81fSMatthias Ringwald         // summary
350*533ea81fSMatthias Ringwald         player_ms  += block_generated_ms - block_start_ms;
351*533ea81fSMatthias Ringwald         encoder_ms += block_encoded_ms   - block_generated_ms;
352*533ea81fSMatthias Ringwald         decoder_ms += block_decoded_ms   - block_encoded_ms;
353*533ea81fSMatthias Ringwald     }
354*533ea81fSMatthias Ringwald     printf("Player:  time %5u ms, duty cycle %3u %%\n", player_ms,  player_ms  / audio_duration_in_seconds / 10);
355*533ea81fSMatthias Ringwald     printf("Encoder: time %5u ms, duty cycle %3u %%\n", encoder_ms, encoder_ms / audio_duration_in_seconds / 10);
356*533ea81fSMatthias Ringwald     printf("Decoder: time %5u ms, duty cycle %3u %%\n", decoder_ms, decoder_ms / audio_duration_in_seconds / 10);
357*533ea81fSMatthias Ringwald 
358*533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
359*533ea81fSMatthias Ringwald     wav_writer_close();
360*533ea81fSMatthias Ringwald #endif
361*533ea81fSMatthias Ringwald }
362*533ea81fSMatthias Ringwald 
363*533ea81fSMatthias Ringwald static void show_usage(void){
364*533ea81fSMatthias Ringwald     printf("\n--- LC3 Encoder Test Console ---\n");
365*533ea81fSMatthias Ringwald     print_config();
366*533ea81fSMatthias Ringwald     printf("---\n");
367*533ea81fSMatthias Ringwald     printf("f - next sampling frequency\n");
368*533ea81fSMatthias Ringwald     printf("v - next codec variant\n");
369*533ea81fSMatthias Ringwald     printf("t - toggle sine / modplayer\n");
370*533ea81fSMatthias Ringwald     printf("p - simulated dropped frames\n");
371*533ea81fSMatthias Ringwald     printf("s - start test\n");
372*533ea81fSMatthias Ringwald     printf("---\n");
373*533ea81fSMatthias Ringwald }
374*533ea81fSMatthias Ringwald 
375*533ea81fSMatthias Ringwald static void stdin_process(char c){
376*533ea81fSMatthias Ringwald     switch (c){
377*533ea81fSMatthias Ringwald         case 'p':
378*533ea81fSMatthias Ringwald             plc_dopped_frame_interval = 16 - plc_dopped_frame_interval;
379*533ea81fSMatthias Ringwald             print_config();
380*533ea81fSMatthias Ringwald             break;
381*533ea81fSMatthias Ringwald         case 'f':
382*533ea81fSMatthias Ringwald             menu_sampling_frequency++;
383*533ea81fSMatthias Ringwald             if (menu_sampling_frequency >= 6){
384*533ea81fSMatthias Ringwald                 menu_sampling_frequency = 0;
385*533ea81fSMatthias Ringwald             }
386*533ea81fSMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
387*533ea81fSMatthias Ringwald                 menu_variant = 0;
388*533ea81fSMatthias Ringwald             }
389*533ea81fSMatthias Ringwald             print_config();
390*533ea81fSMatthias Ringwald             break;
391*533ea81fSMatthias Ringwald         case 'v':
392*533ea81fSMatthias Ringwald             menu_variant++;
393*533ea81fSMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
394*533ea81fSMatthias Ringwald                 menu_variant = 0;
395*533ea81fSMatthias Ringwald             }
396*533ea81fSMatthias Ringwald             print_config();
397*533ea81fSMatthias Ringwald             break;
398*533ea81fSMatthias Ringwald         case 's':
399*533ea81fSMatthias Ringwald             // use values from table
400*533ea81fSMatthias Ringwald             sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
401*533ea81fSMatthias Ringwald             octets_per_frame      = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
402*533ea81fSMatthias Ringwald             frame_duration        = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
403*533ea81fSMatthias Ringwald 
404*533ea81fSMatthias Ringwald             // get num samples per frame
405*533ea81fSMatthias Ringwald             setup_lc3_encoder();
406*533ea81fSMatthias Ringwald             setup_lc3_decoder();
407*533ea81fSMatthias Ringwald 
408*533ea81fSMatthias Ringwald             // setup mod player
409*533ea81fSMatthias Ringwald             setup_mod_player();
410*533ea81fSMatthias Ringwald 
411*533ea81fSMatthias Ringwald             // setup sine generator
412*533ea81fSMatthias Ringwald             if (sampling_frequency_hz == 44100){
413*533ea81fSMatthias Ringwald                 sine_step = 2;
414*533ea81fSMatthias Ringwald             } else {
415*533ea81fSMatthias Ringwald                 sine_step = 96000 / sampling_frequency_hz;
416*533ea81fSMatthias Ringwald             }
417*533ea81fSMatthias Ringwald             test_encoder();
418*533ea81fSMatthias Ringwald             break;
419*533ea81fSMatthias Ringwald         case 't':
420*533ea81fSMatthias Ringwald             audio_source = 1 - audio_source;
421*533ea81fSMatthias Ringwald             print_config();
422*533ea81fSMatthias Ringwald             break;
423*533ea81fSMatthias Ringwald         case '\n':
424*533ea81fSMatthias Ringwald         case '\r':
425*533ea81fSMatthias Ringwald             break;
426*533ea81fSMatthias Ringwald         default:
427*533ea81fSMatthias Ringwald             show_usage();
428*533ea81fSMatthias Ringwald             break;
429*533ea81fSMatthias Ringwald     }
430*533ea81fSMatthias Ringwald }
431*533ea81fSMatthias Ringwald 
432*533ea81fSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
433*533ea81fSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
434*533ea81fSMatthias Ringwald     (void) argv;
435*533ea81fSMatthias Ringwald     (void) argc;
436*533ea81fSMatthias Ringwald     btstack_stdin_setup(stdin_process);
437*533ea81fSMatthias Ringwald     // default config
438*533ea81fSMatthias Ringwald     menu_sampling_frequency = 5;
439*533ea81fSMatthias Ringwald     menu_variant = 4;
440*533ea81fSMatthias Ringwald     audio_source = AUDIO_SOURCE_SINE;
441*533ea81fSMatthias Ringwald     show_usage();
442*533ea81fSMatthias Ringwald     return 0;
443*533ea81fSMatthias Ringwald }
444