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