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