xref: /btstack/test/le_audio/lc3_test.c (revision dc0d751c88133f4edc6aa691ea2712628d58b9e6)
1533ea81fSMatthias Ringwald /*
2533ea81fSMatthias Ringwald  * Copyright (C) 2022 BlueKitchen GmbH
3533ea81fSMatthias Ringwald  *
4533ea81fSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5533ea81fSMatthias Ringwald  * modification, are permitted provided that the following conditions
6533ea81fSMatthias Ringwald  * are met:
7533ea81fSMatthias Ringwald  *
8533ea81fSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9533ea81fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10533ea81fSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11533ea81fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12533ea81fSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13533ea81fSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14533ea81fSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15533ea81fSMatthias Ringwald  *    from this software without specific prior written permission.
16533ea81fSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17533ea81fSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18533ea81fSMatthias Ringwald  *    monetary gain.
19533ea81fSMatthias Ringwald  *
20533ea81fSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21533ea81fSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22533ea81fSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23533ea81fSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24533ea81fSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25533ea81fSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26533ea81fSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27533ea81fSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28533ea81fSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29533ea81fSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30533ea81fSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31533ea81fSMatthias Ringwald  * SUCH DAMAGE.
32533ea81fSMatthias Ringwald  *
33533ea81fSMatthias Ringwald  * Please inquire about commercial licensing options at
34533ea81fSMatthias Ringwald  * [email protected]
35533ea81fSMatthias Ringwald  *
36533ea81fSMatthias Ringwald  */
37533ea81fSMatthias Ringwald 
38533ea81fSMatthias Ringwald #define BTSTACK_FILE__ "lc3_test.c"
39533ea81fSMatthias Ringwald 
40533ea81fSMatthias Ringwald /*
41533ea81fSMatthias Ringwald  * Measure LC3 encoding load
42533ea81fSMatthias Ringwald  */
43533ea81fSMatthias Ringwald 
44533ea81fSMatthias Ringwald #include <stdint.h>
45533ea81fSMatthias Ringwald #include <stdio.h>
46533ea81fSMatthias Ringwald #include <string.h>
47533ea81fSMatthias Ringwald #include <btstack_debug.h>
48533ea81fSMatthias Ringwald 
49533ea81fSMatthias Ringwald #include "bluetooth_data_types.h"
50533ea81fSMatthias Ringwald #include "btstack_stdin.h"
51533ea81fSMatthias Ringwald #include "btstack_event.h"
52533ea81fSMatthias Ringwald #include "btstack_run_loop.h"
53533ea81fSMatthias Ringwald #include "gap.h"
54533ea81fSMatthias Ringwald #include "hci.h"
55533ea81fSMatthias Ringwald #include "hci_cmd.h"
56533ea81fSMatthias Ringwald #include "hci_dump.h"
57533ea81fSMatthias Ringwald #include "btstack_lc3.h"
58533ea81fSMatthias Ringwald #include "btstack_lc3_google.h"
59533ea81fSMatthias Ringwald 
60533ea81fSMatthias Ringwald #include "hxcmod.h"
61533ea81fSMatthias Ringwald #include "mods/mod.h"
62533ea81fSMatthias Ringwald 
63533ea81fSMatthias Ringwald 
64533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
65533ea81fSMatthias Ringwald #include "wav_util.h"
66533ea81fSMatthias Ringwald #endif
67533ea81fSMatthias Ringwald 
68ab05be60SMatthias Ringwald #include "btstack_lc3plus_fraunhofer.h"
69ab05be60SMatthias Ringwald 
70533ea81fSMatthias Ringwald // max config
71533ea81fSMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
72533ea81fSMatthias Ringwald #define MAX_NUM_BIS 2
73533ea81fSMatthias Ringwald 
74533ea81fSMatthias Ringwald // lc3 codec config
75533ea81fSMatthias Ringwald static uint32_t sampling_frequency_hz;
76533ea81fSMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration;
77533ea81fSMatthias Ringwald static uint16_t number_samples_per_frame;
78533ea81fSMatthias Ringwald static uint16_t octets_per_frame;
79533ea81fSMatthias Ringwald static uint8_t  num_bis = 1;
80533ea81fSMatthias Ringwald 
81533ea81fSMatthias Ringwald // lc3 encoder
82533ea81fSMatthias Ringwald static const btstack_lc3_encoder_t * lc3_encoder;
83533ea81fSMatthias Ringwald static btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_BIS];
84533ea81fSMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
85533ea81fSMatthias Ringwald 
86533ea81fSMatthias Ringwald // lc3 decoder
87ab05be60SMatthias Ringwald static bool use_lc3plus_decoder = false;
88533ea81fSMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
89533ea81fSMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
90533ea81fSMatthias Ringwald 
91ab05be60SMatthias Ringwald static btstack_lc3_decoder_google_t google_decoder_contexts[MAX_NUM_BIS];
92ab05be60SMatthias Ringwald #ifdef HAVE_LC3PLUS
93ab05be60SMatthias Ringwald static btstack_lc3plus_fraunhofer_decoder_t fraunhofer_decoder_contexts[MAX_NUM_BIS];
94ab05be60SMatthias Ringwald #endif
95ab05be60SMatthias Ringwald static void * decoder_contexts[MAX_NR_BIS];
96ab05be60SMatthias Ringwald 
97533ea81fSMatthias Ringwald // PLC
98533ea81fSMatthias Ringwald static uint16_t plc_frame_counter;
99533ea81fSMatthias Ringwald static uint16_t plc_dopped_frame_interval;
100533ea81fSMatthias Ringwald 
101533ea81fSMatthias Ringwald // codec menu
102533ea81fSMatthias Ringwald static uint8_t menu_sampling_frequency;
103533ea81fSMatthias Ringwald static uint8_t menu_variant;
104533ea81fSMatthias Ringwald 
105533ea81fSMatthias Ringwald // mod player
106533ea81fSMatthias Ringwald static int hxcmod_initialized;
107533ea81fSMatthias Ringwald static modcontext mod_context;
108533ea81fSMatthias Ringwald static tracker_buffer_state trkbuf;
109533ea81fSMatthias Ringwald 
110533ea81fSMatthias Ringwald // sine generator
111533ea81fSMatthias Ringwald static uint8_t  sine_step;
112533ea81fSMatthias Ringwald static uint16_t sine_phases[MAX_NUM_BIS];
113533ea81fSMatthias Ringwald 
114533ea81fSMatthias Ringwald // audio producer
115533ea81fSMatthias Ringwald static enum {
116533ea81fSMatthias Ringwald     AUDIO_SOURCE_SINE,
117533ea81fSMatthias Ringwald     AUDIO_SOURCE_MODPLAYER
118533ea81fSMatthias Ringwald } audio_source = AUDIO_SOURCE_MODPLAYER;
119533ea81fSMatthias Ringwald 
120533ea81fSMatthias Ringwald // enumerate default codec configs
121533ea81fSMatthias Ringwald static struct {
122533ea81fSMatthias Ringwald     uint32_t samplingrate_hz;
123533ea81fSMatthias Ringwald     uint8_t  samplingrate_index;
124533ea81fSMatthias Ringwald     uint8_t  num_variants;
125533ea81fSMatthias Ringwald     struct {
126533ea81fSMatthias Ringwald         const char * name;
127533ea81fSMatthias Ringwald         btstack_lc3_frame_duration_t frame_duration;
128533ea81fSMatthias Ringwald         uint16_t octets_per_frame;
129533ea81fSMatthias Ringwald     } variants[6];
130533ea81fSMatthias Ringwald } codec_configurations[] = {
131533ea81fSMatthias Ringwald     {
132533ea81fSMatthias Ringwald         8000, 0x01, 2,
133533ea81fSMatthias Ringwald         {
134533ea81fSMatthias Ringwald             {  "8_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 26},
135533ea81fSMatthias Ringwald             {  "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
136533ea81fSMatthias Ringwald         }
137533ea81fSMatthias Ringwald     },
138533ea81fSMatthias Ringwald     {
139533ea81fSMatthias Ringwald        16000, 0x03, 2,
140533ea81fSMatthias Ringwald        {
141533ea81fSMatthias Ringwald             {  "16_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 30},
142533ea81fSMatthias Ringwald             {  "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
143533ea81fSMatthias Ringwald        }
144533ea81fSMatthias Ringwald     },
145533ea81fSMatthias Ringwald     {
146533ea81fSMatthias Ringwald         24000, 0x05, 2,
147533ea81fSMatthias Ringwald         {
148533ea81fSMatthias Ringwald             {  "24_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 45},
149533ea81fSMatthias Ringwald             {  "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
150533ea81fSMatthias Ringwald        }
151533ea81fSMatthias Ringwald     },
152533ea81fSMatthias Ringwald     {
153533ea81fSMatthias Ringwald         32000, 0x06, 2,
154533ea81fSMatthias Ringwald         {
155533ea81fSMatthias Ringwald             {  "32_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 60},
156533ea81fSMatthias Ringwald             {  "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
157533ea81fSMatthias Ringwald         }
158533ea81fSMatthias Ringwald     },
159533ea81fSMatthias Ringwald     {
160533ea81fSMatthias Ringwald         44100, 0x07, 2,
161533ea81fSMatthias Ringwald         {
162533ea81fSMatthias Ringwald             { "441_1",  BTSTACK_LC3_FRAME_DURATION_7500US,  97},
163533ea81fSMatthias Ringwald             { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
164533ea81fSMatthias Ringwald         }
165533ea81fSMatthias Ringwald     },
166533ea81fSMatthias Ringwald     {
167533ea81fSMatthias Ringwald         48000, 0x08, 6,
168533ea81fSMatthias Ringwald         {
169533ea81fSMatthias Ringwald             {  "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
170533ea81fSMatthias Ringwald             {  "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
171533ea81fSMatthias Ringwald             {  "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
172533ea81fSMatthias Ringwald             {  "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
173533ea81fSMatthias Ringwald             {  "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
174533ea81fSMatthias Ringwald             {  "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
175533ea81fSMatthias Ringwald         }
176533ea81fSMatthias Ringwald     },
177533ea81fSMatthias Ringwald };
178533ea81fSMatthias Ringwald 
179533ea81fSMatthias Ringwald 
180533ea81fSMatthias Ringwald // input signal: pre-computed int16 sine wave, 96000 Hz at 300 Hz
181533ea81fSMatthias Ringwald static const int16_t sine_int16[] = {
182533ea81fSMatthias Ringwald         0,    643,   1286,   1929,   2571,   3212,   3851,   4489,   5126,   5760,
183533ea81fSMatthias Ringwald         6393,   7022,   7649,   8273,   8894,   9512,  10126,  10735,  11341,  11943,
184533ea81fSMatthias Ringwald         12539,  13131,  13718,  14300,  14876,  15446,  16011,  16569,  17121,  17666,
185533ea81fSMatthias Ringwald         18204,  18736,  19260,  19777,  20286,  20787,  21280,  21766,  22242,  22710,
186533ea81fSMatthias Ringwald         23170,  23620,  24062,  24494,  24916,  25329,  25732,  26126,  26509,  26882,
187533ea81fSMatthias Ringwald         27245,  27597,  27938,  28269,  28589,  28898,  29196,  29482,  29757,  30021,
188533ea81fSMatthias Ringwald         30273,  30513,  30742,  30958,  31163,  31356,  31537,  31705,  31862,  32006,
189533ea81fSMatthias Ringwald         32137,  32257,  32364,  32458,  32540,  32609,  32666,  32710,  32742,  32761,
190533ea81fSMatthias Ringwald         32767,  32761,  32742,  32710,  32666,  32609,  32540,  32458,  32364,  32257,
191533ea81fSMatthias Ringwald         32137,  32006,  31862,  31705,  31537,  31356,  31163,  30958,  30742,  30513,
192533ea81fSMatthias Ringwald         30273,  30021,  29757,  29482,  29196,  28898,  28589,  28269,  27938,  27597,
193533ea81fSMatthias Ringwald         27245,  26882,  26509,  26126,  25732,  25329,  24916,  24494,  24062,  23620,
194533ea81fSMatthias Ringwald         23170,  22710,  22242,  21766,  21280,  20787,  20286,  19777,  19260,  18736,
195533ea81fSMatthias Ringwald         18204,  17666,  17121,  16569,  16011,  15446,  14876,  14300,  13718,  13131,
196533ea81fSMatthias Ringwald         12539,  11943,  11341,  10735,  10126,   9512,   8894,   8273,   7649,   7022,
197533ea81fSMatthias Ringwald         6393,   5760,   5126,   4489,   3851,   3212,   2571,   1929,   1286,    643,
198533ea81fSMatthias Ringwald         0,   -643,  -1286,  -1929,  -2571,  -3212,  -3851,  -4489,  -5126,  -5760,
199533ea81fSMatthias Ringwald         -6393,  -7022,  -7649,  -8273,  -8894,  -9512, -10126, -10735, -11341, -11943,
200533ea81fSMatthias Ringwald         -12539, -13131, -13718, -14300, -14876, -15446, -16011, -16569, -17121, -17666,
201533ea81fSMatthias Ringwald         -18204, -18736, -19260, -19777, -20286, -20787, -21280, -21766, -22242, -22710,
202533ea81fSMatthias Ringwald         -23170, -23620, -24062, -24494, -24916, -25329, -25732, -26126, -26509, -26882,
203533ea81fSMatthias Ringwald         -27245, -27597, -27938, -28269, -28589, -28898, -29196, -29482, -29757, -30021,
204533ea81fSMatthias Ringwald         -30273, -30513, -30742, -30958, -31163, -31356, -31537, -31705, -31862, -32006,
205533ea81fSMatthias Ringwald         -32137, -32257, -32364, -32458, -32540, -32609, -32666, -32710, -32742, -32761,
206533ea81fSMatthias Ringwald         -32767, -32761, -32742, -32710, -32666, -32609, -32540, -32458, -32364, -32257,
207533ea81fSMatthias Ringwald         -32137, -32006, -31862, -31705, -31537, -31356, -31163, -30958, -30742, -30513,
208533ea81fSMatthias Ringwald         -30273, -30021, -29757, -29482, -29196, -28898, -28589, -28269, -27938, -27597,
209533ea81fSMatthias Ringwald         -27245, -26882, -26509, -26126, -25732, -25329, -24916, -24494, -24062, -23620,
210533ea81fSMatthias Ringwald         -23170, -22710, -22242, -21766, -21280, -20787, -20286, -19777, -19260, -18736,
211533ea81fSMatthias Ringwald         -18204, -17666, -17121, -16569, -16011, -15446, -14876, -14300, -13718, -13131,
212533ea81fSMatthias Ringwald         -12539, -11943, -11341, -10735, -10126,  -9512,  -8894,  -8273,  -7649,  -7022,
213533ea81fSMatthias Ringwald         -6393,  -5760,  -5126,  -4489,  -3851,  -3212,  -2571,  -1929,  -1286,   -643,
214533ea81fSMatthias Ringwald };
215533ea81fSMatthias Ringwald 
216533ea81fSMatthias Ringwald static void show_usage(void);
217533ea81fSMatthias Ringwald 
print_config(void)218533ea81fSMatthias Ringwald static void print_config(void) {
219ab05be60SMatthias Ringwald     printf("Config '%s_%u': %u, %s ms, %u octets - %s, drop frame interval %u, decoder %s\n",
220533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
221533ea81fSMatthias Ringwald            num_bis,
222533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].samplingrate_hz,
223533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
224533ea81fSMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
225533ea81fSMatthias Ringwald            audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer",
226ab05be60SMatthias Ringwald            plc_dopped_frame_interval,
227ab05be60SMatthias Ringwald            use_lc3plus_decoder ? "LC3plus" : "LC3");
228533ea81fSMatthias Ringwald }
229533ea81fSMatthias Ringwald 
setup_lc3_encoder(void)230533ea81fSMatthias Ringwald static void setup_lc3_encoder(void){
231533ea81fSMatthias Ringwald     uint8_t channel;
232533ea81fSMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
233533ea81fSMatthias Ringwald         btstack_lc3_encoder_google_t * context = &encoder_contexts[channel];
234533ea81fSMatthias Ringwald         lc3_encoder = btstack_lc3_encoder_google_init_instance(context);
235da364eecSMatthias Ringwald         lc3_encoder->configure(context, sampling_frequency_hz, frame_duration, octets_per_frame);
236533ea81fSMatthias Ringwald     }
237*dc0d751cSMatthias Ringwald     number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration);
238533ea81fSMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
239533ea81fSMatthias Ringwald     printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n",
240533ea81fSMatthias Ringwald            sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
241533ea81fSMatthias Ringwald            number_samples_per_frame, octets_per_frame);
242533ea81fSMatthias Ringwald }
243533ea81fSMatthias Ringwald 
setup_lc3_decoder(void)244533ea81fSMatthias Ringwald static void setup_lc3_decoder(void){
245533ea81fSMatthias Ringwald     uint8_t channel;
246533ea81fSMatthias Ringwald         for (channel = 0 ; channel < num_bis ; channel++){
247ab05be60SMatthias Ringwald             // pick decoder
248ab05be60SMatthias Ringwald             void * decoder_context = NULL;
249ab05be60SMatthias Ringwald #ifdef HAVE_LC3PLUS
250ab05be60SMatthias Ringwald              if (use_lc3plus_decoder){
251ab05be60SMatthias Ringwald                 decoder_context = &fraunhofer_decoder_contexts[channel];
252ab05be60SMatthias Ringwald                 lc3_decoder = btstack_lc3plus_fraunhofer_decoder_init_instance(decoder_context);
253ab05be60SMatthias Ringwald             }
254ab05be60SMatthias Ringwald             else
255ab05be60SMatthias Ringwald #endif
256ab05be60SMatthias Ringwald             {
257ab05be60SMatthias Ringwald                 decoder_context = &google_decoder_contexts[channel];
258533ea81fSMatthias Ringwald                 lc3_decoder = btstack_lc3_decoder_google_init_instance(decoder_context);
259ab05be60SMatthias Ringwald             }
260ab05be60SMatthias Ringwald             decoder_contexts[channel] = decoder_context;
261da364eecSMatthias Ringwald             lc3_decoder->configure(decoder_context, sampling_frequency_hz, frame_duration, octets_per_frame);
262533ea81fSMatthias Ringwald         }
263*dc0d751cSMatthias Ringwald     number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration);
264533ea81fSMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
265533ea81fSMatthias Ringwald }
266533ea81fSMatthias Ringwald 
setup_mod_player(void)267533ea81fSMatthias Ringwald static void setup_mod_player(void){
268533ea81fSMatthias Ringwald     if (!hxcmod_initialized) {
269533ea81fSMatthias Ringwald         hxcmod_initialized = hxcmod_init(&mod_context);
270533ea81fSMatthias Ringwald         btstack_assert(hxcmod_initialized != 0);
271533ea81fSMatthias Ringwald     }
272533ea81fSMatthias Ringwald     hxcmod_unload(&mod_context);
273533ea81fSMatthias Ringwald     hxcmod_setcfg(&mod_context, sampling_frequency_hz, 16, 1, 1, 1);
274533ea81fSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
275533ea81fSMatthias Ringwald }
276533ea81fSMatthias Ringwald 
generate_audio(void)277533ea81fSMatthias Ringwald static void generate_audio(void){
278533ea81fSMatthias Ringwald     uint16_t sample;
279533ea81fSMatthias Ringwald     switch (audio_source) {
280533ea81fSMatthias Ringwald         case AUDIO_SOURCE_SINE:
281533ea81fSMatthias Ringwald             // generate sine wave for all channels
282533ea81fSMatthias Ringwald             for (sample = 0 ; sample < number_samples_per_frame ; sample++){
283533ea81fSMatthias Ringwald                 uint8_t channel;
284533ea81fSMatthias Ringwald                 for (channel = 0; channel < num_bis; channel++) {
285533ea81fSMatthias Ringwald                     int16_t value = sine_int16[sine_phases[channel]] / 4;
286533ea81fSMatthias Ringwald                     pcm[sample * num_bis + channel] = value;
287533ea81fSMatthias Ringwald                     sine_phases[channel] += sine_step * (1+channel);    // second channel, double frequency
288533ea81fSMatthias Ringwald                     if (sine_phases[channel] >= (sizeof(sine_int16) / sizeof(int16_t))) {
289533ea81fSMatthias Ringwald                         sine_phases[channel] = 0;
290533ea81fSMatthias Ringwald                     }
291533ea81fSMatthias Ringwald                 }
292533ea81fSMatthias Ringwald             }
293533ea81fSMatthias Ringwald             break;
294533ea81fSMatthias Ringwald         case AUDIO_SOURCE_MODPLAYER:
295533ea81fSMatthias Ringwald             // mod player configured for stereo
296533ea81fSMatthias Ringwald             hxcmod_fillbuffer(&mod_context, (unsigned short *) pcm, number_samples_per_frame, &trkbuf);
297533ea81fSMatthias Ringwald             if (num_bis == 1) {
298533ea81fSMatthias Ringwald                 // stereo -> mono
299533ea81fSMatthias Ringwald                 uint16_t i;
300533ea81fSMatthias Ringwald                 for (i=0;i<number_samples_per_frame;i++){
301533ea81fSMatthias Ringwald                     pcm[i] = (pcm[2*i] / 2) + (pcm[2*i+1] / 2);
302533ea81fSMatthias Ringwald                 }
303533ea81fSMatthias Ringwald             }
304533ea81fSMatthias Ringwald             break;
305533ea81fSMatthias Ringwald         default:
306533ea81fSMatthias Ringwald             btstack_unreachable();
307533ea81fSMatthias Ringwald             break;
308533ea81fSMatthias Ringwald     }
309533ea81fSMatthias Ringwald }
310533ea81fSMatthias Ringwald 
test_encoder()311533ea81fSMatthias Ringwald static void test_encoder(){
312533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
313533ea81fSMatthias Ringwald     wav_writer_open("lc3_test.wav", 1, sampling_frequency_hz);
314533ea81fSMatthias Ringwald #endif
315533ea81fSMatthias Ringwald 
316533ea81fSMatthias Ringwald     // encode 10 seconds of music
317533ea81fSMatthias Ringwald     uint32_t audio_duration_in_seconds = 10;
318533ea81fSMatthias Ringwald     uint32_t total_samples = sampling_frequency_hz * audio_duration_in_seconds;
319533ea81fSMatthias Ringwald     uint32_t generated_samples = 0;
320533ea81fSMatthias Ringwald     uint32_t player_ms = 0;
321533ea81fSMatthias Ringwald     uint32_t encoder_ms = 0;
322533ea81fSMatthias Ringwald     uint32_t decoder_ms = 0;
323533ea81fSMatthias Ringwald     plc_frame_counter = 0;
324533ea81fSMatthias Ringwald 
325533ea81fSMatthias Ringwald     printf("Encoding and decoding %u seconds of audio...\n", audio_duration_in_seconds);
326533ea81fSMatthias Ringwald     while (generated_samples < total_samples){
327533ea81fSMatthias Ringwald 
328533ea81fSMatthias Ringwald         // generate audio
329533ea81fSMatthias Ringwald         uint32_t block_start_ms = btstack_run_loop_get_time_ms();
330533ea81fSMatthias Ringwald         generate_audio();
331533ea81fSMatthias Ringwald         uint32_t block_generated_ms  = btstack_run_loop_get_time_ms();
332533ea81fSMatthias Ringwald 
333533ea81fSMatthias Ringwald         // encode frame
334533ea81fSMatthias Ringwald         uint8_t buffer[200];
335da364eecSMatthias Ringwald         lc3_encoder->encode_signed_16(&encoder_contexts[0], pcm, 1, buffer);
336533ea81fSMatthias Ringwald         generated_samples += number_samples_per_frame;
337533ea81fSMatthias Ringwald         uint32_t block_encoded_ms  = btstack_run_loop_get_time_ms();
338533ea81fSMatthias Ringwald         plc_frame_counter++;
339533ea81fSMatthias Ringwald 
340533ea81fSMatthias Ringwald         uint8_t BFI = 0;
341533ea81fSMatthias Ringwald         // simulate dropped packets
342533ea81fSMatthias Ringwald         if ((plc_dopped_frame_interval != 0) && (plc_frame_counter == plc_dopped_frame_interval)){
343533ea81fSMatthias Ringwald             plc_frame_counter = 0;
344533ea81fSMatthias Ringwald             BFI = 1;
345533ea81fSMatthias Ringwald         }
346533ea81fSMatthias Ringwald 
347533ea81fSMatthias Ringwald         // decode codec frame
348533ea81fSMatthias Ringwald         uint8_t tmp_BEC_detect;
349da364eecSMatthias Ringwald         (void) lc3_decoder->decode_signed_16(decoder_contexts[0], buffer, BFI, pcm, 1, &tmp_BEC_detect);
350533ea81fSMatthias Ringwald 
351533ea81fSMatthias Ringwald         uint32_t block_decoded_ms  = btstack_run_loop_get_time_ms();
352533ea81fSMatthias Ringwald 
353533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
354533ea81fSMatthias Ringwald         wav_writer_write_int16(number_samples_per_frame, pcm);
355533ea81fSMatthias Ringwald #endif
356533ea81fSMatthias Ringwald 
357533ea81fSMatthias Ringwald         // summary
358533ea81fSMatthias Ringwald         player_ms  += block_generated_ms - block_start_ms;
359533ea81fSMatthias Ringwald         encoder_ms += block_encoded_ms   - block_generated_ms;
360533ea81fSMatthias Ringwald         decoder_ms += block_decoded_ms   - block_encoded_ms;
361533ea81fSMatthias Ringwald     }
362533ea81fSMatthias Ringwald     printf("Player:  time %5u ms, duty cycle %3u %%\n", player_ms,  player_ms  / audio_duration_in_seconds / 10);
363533ea81fSMatthias Ringwald     printf("Encoder: time %5u ms, duty cycle %3u %%\n", encoder_ms, encoder_ms / audio_duration_in_seconds / 10);
364533ea81fSMatthias Ringwald     printf("Decoder: time %5u ms, duty cycle %3u %%\n", decoder_ms, decoder_ms / audio_duration_in_seconds / 10);
365533ea81fSMatthias Ringwald 
366533ea81fSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
367533ea81fSMatthias Ringwald     wav_writer_close();
368533ea81fSMatthias Ringwald #endif
369533ea81fSMatthias Ringwald }
370533ea81fSMatthias Ringwald 
show_usage(void)371533ea81fSMatthias Ringwald static void show_usage(void){
372533ea81fSMatthias Ringwald     printf("\n--- LC3 Encoder Test Console ---\n");
373533ea81fSMatthias Ringwald     print_config();
374533ea81fSMatthias Ringwald     printf("---\n");
375533ea81fSMatthias Ringwald     printf("f - next sampling frequency\n");
376533ea81fSMatthias Ringwald     printf("v - next codec variant\n");
377533ea81fSMatthias Ringwald     printf("t - toggle sine / modplayer\n");
378533ea81fSMatthias Ringwald     printf("p - simulated dropped frames\n");
379ab05be60SMatthias Ringwald #ifdef HAVE_LC3PLUS
380ab05be60SMatthias Ringwald     printf("q - use LC3plus\n");
381ab05be60SMatthias Ringwald #endif
382533ea81fSMatthias Ringwald     printf("s - start test\n");
383533ea81fSMatthias Ringwald     printf("---\n");
384533ea81fSMatthias Ringwald }
385533ea81fSMatthias Ringwald 
stdin_process(char c)386533ea81fSMatthias Ringwald static void stdin_process(char c){
387533ea81fSMatthias Ringwald     switch (c){
388533ea81fSMatthias Ringwald         case 'p':
389533ea81fSMatthias Ringwald             plc_dopped_frame_interval = 16 - plc_dopped_frame_interval;
390533ea81fSMatthias Ringwald             print_config();
391533ea81fSMatthias Ringwald             break;
392ab05be60SMatthias Ringwald #ifdef HAVE_LC3PLUS
393ab05be60SMatthias Ringwald         case 'q':
394ab05be60SMatthias Ringwald             use_lc3plus_decoder = true;
395ab05be60SMatthias Ringwald             // enforce 10ms as 7.5ms is not supported
396ab05be60SMatthias Ringwald             if ((menu_variant & 1) == 0){
397ab05be60SMatthias Ringwald                 menu_variant++;
398ab05be60SMatthias Ringwald             }
399ab05be60SMatthias Ringwald             print_config();
400ab05be60SMatthias Ringwald             break;
401ab05be60SMatthias Ringwald #endif
402533ea81fSMatthias Ringwald         case 'f':
403533ea81fSMatthias Ringwald             menu_sampling_frequency++;
404533ea81fSMatthias Ringwald             if (menu_sampling_frequency >= 6){
405533ea81fSMatthias Ringwald                 menu_sampling_frequency = 0;
406533ea81fSMatthias Ringwald             }
407533ea81fSMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
408533ea81fSMatthias Ringwald                 menu_variant = 0;
409533ea81fSMatthias Ringwald             }
410533ea81fSMatthias Ringwald             print_config();
411533ea81fSMatthias Ringwald             break;
412533ea81fSMatthias Ringwald         case 'v':
413533ea81fSMatthias Ringwald             menu_variant++;
414533ea81fSMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
415533ea81fSMatthias Ringwald                 menu_variant = 0;
416533ea81fSMatthias Ringwald             }
417533ea81fSMatthias Ringwald             print_config();
418533ea81fSMatthias Ringwald             break;
419533ea81fSMatthias Ringwald         case 's':
420533ea81fSMatthias Ringwald             // use values from table
421533ea81fSMatthias Ringwald             sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
422533ea81fSMatthias Ringwald             octets_per_frame      = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
423533ea81fSMatthias Ringwald             frame_duration        = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
424533ea81fSMatthias Ringwald 
425533ea81fSMatthias Ringwald             // get num samples per frame
426533ea81fSMatthias Ringwald             setup_lc3_encoder();
427533ea81fSMatthias Ringwald             setup_lc3_decoder();
428533ea81fSMatthias Ringwald 
429533ea81fSMatthias Ringwald             // setup mod player
430533ea81fSMatthias Ringwald             setup_mod_player();
431533ea81fSMatthias Ringwald 
432533ea81fSMatthias Ringwald             // setup sine generator
433533ea81fSMatthias Ringwald             if (sampling_frequency_hz == 44100){
434533ea81fSMatthias Ringwald                 sine_step = 2;
435533ea81fSMatthias Ringwald             } else {
436533ea81fSMatthias Ringwald                 sine_step = 96000 / sampling_frequency_hz;
437533ea81fSMatthias Ringwald             }
438533ea81fSMatthias Ringwald             test_encoder();
439533ea81fSMatthias Ringwald             break;
440533ea81fSMatthias Ringwald         case 't':
441533ea81fSMatthias Ringwald             audio_source = 1 - audio_source;
442533ea81fSMatthias Ringwald             print_config();
443533ea81fSMatthias Ringwald             break;
444533ea81fSMatthias Ringwald         case '\n':
445533ea81fSMatthias Ringwald         case '\r':
446533ea81fSMatthias Ringwald             break;
447533ea81fSMatthias Ringwald         default:
448533ea81fSMatthias Ringwald             show_usage();
449533ea81fSMatthias Ringwald             break;
450533ea81fSMatthias Ringwald     }
451533ea81fSMatthias Ringwald }
452533ea81fSMatthias Ringwald 
453533ea81fSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])454533ea81fSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
455533ea81fSMatthias Ringwald     (void) argv;
456533ea81fSMatthias Ringwald     (void) argc;
457533ea81fSMatthias Ringwald     btstack_stdin_setup(stdin_process);
458533ea81fSMatthias Ringwald     // default config
459533ea81fSMatthias Ringwald     menu_sampling_frequency = 5;
460533ea81fSMatthias Ringwald     menu_variant = 4;
461533ea81fSMatthias Ringwald     audio_source = AUDIO_SOURCE_SINE;
462533ea81fSMatthias Ringwald     show_usage();
463533ea81fSMatthias Ringwald     return 0;
464533ea81fSMatthias Ringwald }
465