From 36a3225a2bb950f2f2373bc309046390440ecf21 Mon Sep 17 00:00:00 2001 From: BotoX Date: Sat, 1 May 2021 18:38:37 +0200 Subject: [PATCH] change pretty much everything so it does what I want :^) --- .vscode/c_cpp_properties.json | 20 + demboyz/base/CRC.h | 2066 ++ demboyz/base/json.hpp | 25447 ++++++++++++++++ demboyz/base/jsonfile.cpp | 470 - demboyz/base/jsonfile.h | 147 - demboyz/base/steamid.h | 457 + demboyz/demboyz.cpp | 132 +- demboyz/demmessages/dem_consolecmd.cpp | 28 - demboyz/demmessages/dem_datatables.cpp | 90 +- demboyz/demmessages/dem_datatables.h | 103 +- demboyz/demmessages/dem_packet.cpp | 28 - demboyz/demmessages/dem_stop.cpp | 15 - demboyz/demmessages/dem_stringtables.cpp | 184 +- demboyz/demmessages/dem_synctick.cpp | 15 - demboyz/demmessages/dem_unknown.cpp | 15 - demboyz/demmessages/dem_usercmd.cpp | 27 - demboyz/demmessages/demhandlers.cpp | 33 - demboyz/demmessages/demhandlers.h | 31 - demboyz/demofile/demofile.cpp | 91 +- demboyz/demofile/demofile.h | 18 - demboyz/demofile/demojson.cpp | 161 - demboyz/demofile/demojson.h | 36 - demboyz/game/gameevents.cpp | 72 +- demboyz/game/gameevents.h | 8 +- demboyz/game/logic.cpp | 196 + demboyz/game/logic.h | 39 + demboyz/game/sourcecontext.cpp | 167 +- demboyz/game/sourcecontext.h | 97 +- demboyz/game/stringtables.cpp | 174 + demboyz/game/stringtables.h | 48 + demboyz/io/conlogwriter.cpp | 60 - demboyz/io/demoreader.cpp | 107 + demboyz/io/demoreader.h | 7 +- demboyz/io/demowriter.cpp | 108 - demboyz/io/demreader.cpp | 81 - demboyz/io/idemowriter.h | 55 - demboyz/io/jsonreader.cpp | 92 - demboyz/io/jsonwriter.cpp | 104 - demboyz/io/voicewriter/opusfilewriter.h | 81 + demboyz/io/voicewriter/voicedatawriter.cpp | 506 +- demboyz/io/voicewriter/voicedatawriter.h | 91 + demboyz/io/voicewriter/wavfilewriter.h | 28 +- demboyz/netmessages/net_disconnect.cpp | 29 - demboyz/netmessages/net_file.cpp | 35 - demboyz/netmessages/net_nop.cpp | 20 - demboyz/netmessages/net_setconvar.cpp | 50 +- demboyz/netmessages/net_signonstate.cpp | 33 - demboyz/netmessages/net_stringcmd.cpp | 29 - demboyz/netmessages/net_tick.cpp | 35 - demboyz/netmessages/netcontants.h | 4 +- demboyz/netmessages/nethandlers.cpp | 167 +- demboyz/netmessages/nethandlers.h | 36 - demboyz/netmessages/netmath.cpp | 18 + demboyz/netmessages/netmath.h | 15 +- demboyz/netmessages/netmessages.h | 6 +- demboyz/netmessages/svc_bspdecal.cpp | 53 - demboyz/netmessages/svc_classinfo.cpp | 64 - demboyz/netmessages/svc_cmdkeyvalues.cpp | 25 - demboyz/netmessages/svc_createstringtable.cpp | 204 +- demboyz/netmessages/svc_crosshairangle.cpp | 40 - demboyz/netmessages/svc_entitymessage.cpp | 41 - demboyz/netmessages/svc_fixangle.cpp | 43 - demboyz/netmessages/svc_gameevent.cpp | 52 +- demboyz/netmessages/svc_gameeventlist.cpp | 76 +- demboyz/netmessages/svc_getcvarvalue.cpp | 33 - demboyz/netmessages/svc_hltv.cpp | 23 - demboyz/netmessages/svc_menu.cpp | 52 - demboyz/netmessages/svc_packetentities.cpp | 87 +- demboyz/netmessages/svc_prefetch.cpp | 39 - demboyz/netmessages/svc_print.cpp | 29 - demboyz/netmessages/svc_sendtable.cpp | 37 - demboyz/netmessages/svc_serverinfo.cpp | 110 +- demboyz/netmessages/svc_serverinfo.h | 4 +- demboyz/netmessages/svc_setpause.cpp | 29 - demboyz/netmessages/svc_setpausetimed.cpp | 32 - demboyz/netmessages/svc_setview.cpp | 29 - demboyz/netmessages/svc_sounds.cpp | 49 - demboyz/netmessages/svc_tempentities.cpp | 44 - demboyz/netmessages/svc_terrainmod.cpp | 23 - demboyz/netmessages/svc_updatestringtable.cpp | 56 +- demboyz/netmessages/svc_usermessage.cpp | 37 - demboyz/netmessages/svc_voicedata.cpp | 41 +- demboyz/netmessages/svc_voiceinit.cpp | 46 - demboyz/netmessages/usermessages.h | 56 + external/SILK_SDK_SRC_FLP_v1.0.9/Makefile | 98 + external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK.sln | 56 + .../Silk_SDK_VS2005.sln | 44 + .../doc/SILK_Evaluation.pdf | Bin 0 -> 80724 bytes .../doc/SILK_RTP_PayloadFormat.pdf | Bin 0 -> 97683 bytes .../doc/SILK_SDK_API.pdf | Bin 0 -> 145561 bytes .../interface/SKP_Silk_SDK_API.h | 152 + .../interface/SKP_Silk_control.h | 91 + .../interface/SKP_Silk_errors.h | 89 + .../interface/SKP_Silk_typedef.h | 107 + external/SILK_SDK_SRC_FLP_v1.0.9/readme.txt | 94 + .../src/SKP_Silk_A2NLSF.c | 279 + .../src/SKP_Silk_CNG.c | 149 + .../src/SKP_Silk_HP_variable_cutoff_FLP.c | 104 + .../src/SKP_Silk_Inlines.h | 278 + .../src/SKP_Silk_LBRR_reset.c | 40 + .../src/SKP_Silk_LPC_analysis_filter_FLP.c | 238 + .../src/SKP_Silk_LPC_inv_pred_gain.c | 153 + .../src/SKP_Silk_LPC_inv_pred_gain_FLP.c | 81 + .../src/SKP_Silk_LPC_synthesis_filter.c | 84 + .../src/SKP_Silk_LPC_synthesis_order16.c | 122 + .../src/SKP_Silk_LP_variable_cutoff.c | 194 + .../src/SKP_Silk_LSF_cos_table.c | 65 + .../src/SKP_Silk_LTP_analysis_filter_FLP.c | 70 + .../src/SKP_Silk_LTP_scale_ctrl_FLP.c | 85 + .../SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_MA.c | 116 + .../src/SKP_Silk_NLSF2A.c | 151 + .../src/SKP_Silk_NLSF2A_stable.c | 58 + .../src/SKP_Silk_NLSF_MSVQ_decode.c | 91 + .../src/SKP_Silk_NLSF_MSVQ_decode_FLP.c | 89 + .../src/SKP_Silk_NLSF_MSVQ_encode_FLP.c | 233 + .../SKP_Silk_NLSF_VQ_rate_distortion_FLP.c | 57 + .../src/SKP_Silk_NLSF_VQ_sum_error_FLP.c | 132 + .../src/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c | 69 + .../src/SKP_Silk_NLSF_stabilize.c | 139 + .../src/SKP_Silk_NSQ.c | 421 + .../src/SKP_Silk_NSQ_del_dec.c | 703 + .../src/SKP_Silk_PLC.c | 388 + .../src/SKP_Silk_PLC.h | 79 + .../src/SKP_Silk_SigProc_FIX.h | 636 + .../src/SKP_Silk_SigProc_FLP.h | 254 + .../src/SKP_Silk_VAD.c | 320 + .../src/SKP_Silk_VQ_nearest_neighbor_FLP.c | 102 + .../src/SKP_Silk_allpass_int.c | 69 + .../src/SKP_Silk_allpass_int_FLP.c | 68 + .../src/SKP_Silk_ana_filt_bank_1.c | 80 + .../src/SKP_Silk_apply_sine_window_FLP.c | 77 + .../src/SKP_Silk_autocorrelation_FLP.c | 48 + .../src/SKP_Silk_biquad.c | 72 + .../src/SKP_Silk_biquad_alt.c | 73 + .../src/SKP_Silk_burg_modified_FLP.c | 156 + .../src/SKP_Silk_bwexpander.c | 49 + .../src/SKP_Silk_bwexpander_32.c | 46 + .../src/SKP_Silk_bwexpander_FLP.c | 47 + .../src/SKP_Silk_code_signs.c | 91 + .../src/SKP_Silk_common_pitch_est_defines.h | 76 + .../src/SKP_Silk_control_audio_bandwidth.c | 137 + .../src/SKP_Silk_control_codec_FLP.c | 411 + .../src/SKP_Silk_corrMatrix_FLP.c | 89 + .../src/SKP_Silk_create_init_destroy.c | 53 + .../src/SKP_Silk_dec_API.c | 279 + .../src/SKP_Silk_decimate2_coarse_FLP.c | 69 + .../src/SKP_Silk_decimate2_coarsest_FLP.c | 67 + .../src/SKP_Silk_decode_core.c | 242 + .../src/SKP_Silk_decode_frame.c | 155 + .../src/SKP_Silk_decode_parameters.c | 244 + .../src/SKP_Silk_decode_pitch.c | 57 + .../src/SKP_Silk_decode_pulses.c | 105 + .../src/SKP_Silk_decoder_set_fs.c | 80 + .../src/SKP_Silk_define.h | 306 + .../src/SKP_Silk_detect_SWB_input.c | 76 + .../src/SKP_Silk_enc_API.c | 247 + .../src/SKP_Silk_encode_frame_FLP.c | 398 + .../src/SKP_Silk_encode_parameters.c | 162 + .../src/SKP_Silk_encode_pulses.c | 195 + .../src/SKP_Silk_energy_FLP.c | 56 + .../src/SKP_Silk_find_LPC_FLP.c | 102 + .../src/SKP_Silk_find_LTP_FLP.c | 131 + .../src/SKP_Silk_find_pitch_lags_FLP.c | 116 + .../src/SKP_Silk_find_pred_coefs_FLP.c | 111 + .../src/SKP_Silk_gain_quant.c | 94 + .../src/SKP_Silk_init_encoder_FLP.c | 58 + .../src/SKP_Silk_inner_product_FLP.c | 56 + .../src/SKP_Silk_interpolate.c | 47 + .../src/SKP_Silk_k2a_FLP.c | 58 + .../src/SKP_Silk_levinsondurbin_FLP.c | 77 + .../src/SKP_Silk_lin2log.c | 49 + .../src/SKP_Silk_log2lin.c | 61 + .../src/SKP_Silk_lowpass_int.c | 61 + .../src/SKP_Silk_lowpass_short.c | 61 + .../src/SKP_Silk_macros.h | 125 + .../src/SKP_Silk_main.h | 388 + .../src/SKP_Silk_main_FLP.h | 433 + .../src/SKP_Silk_noise_shape_analysis_FLP.c | 382 + .../src/SKP_Silk_pitch_analysis_core_FLP.c | 625 + .../src/SKP_Silk_pitch_est_defines.h | 40 + .../src/SKP_Silk_pitch_est_defines_FLP.h | 40 + .../src/SKP_Silk_pitch_est_tables.c | 89 + .../src/SKP_Silk_prefilter_FLP.c | 202 + .../src/SKP_Silk_process_NLSFs_FLP.c | 106 + .../src/SKP_Silk_process_gains_FLP.c | 93 + .../src/SKP_Silk_quant_LTP_gains_FLP.c | 107 + .../src/SKP_Silk_range_coder.c | 372 + .../SKP_Silk_regularize_correlations_FLP.c | 43 + .../src/SKP_Silk_resampler.c | 323 + .../src/SKP_Silk_resampler_down2.c | 77 + .../src/SKP_Silk_resampler_down2_3.c | 102 + .../src/SKP_Silk_resampler_down3.c | 93 + .../src/SKP_Silk_resampler_private.h | 131 + .../src/SKP_Silk_resampler_private_AR2.c | 58 + .../src/SKP_Silk_resampler_private_ARMA4.c | 77 + .../src/SKP_Silk_resampler_private_IIR_FIR.c | 105 + .../src/SKP_Silk_resampler_private_copy.c | 49 + .../src/SKP_Silk_resampler_private_down4.c | 77 + .../src/SKP_Silk_resampler_private_down_FIR.c | 160 + .../src/SKP_Silk_resampler_private_up2_HQ.c | 118 + .../src/SKP_Silk_resampler_private_up4.c | 81 + .../src/SKP_Silk_resampler_rom.c | 269 + .../src/SKP_Silk_resampler_rom.h | 91 + .../src/SKP_Silk_resampler_structs.h | 80 + .../src/SKP_Silk_resampler_up2.c | 75 + .../src/SKP_Silk_residual_energy_FLP.c | 110 + .../src/SKP_Silk_scale_copy_vector_FLP.c | 53 + .../src/SKP_Silk_scale_vector_FLP.c | 52 + .../src/SKP_Silk_schur_FLP.c | 73 + .../src/SKP_Silk_setup_complexity.h | 99 + .../src/SKP_Silk_shell_coder.c | 155 + .../src/SKP_Silk_sigm_Q15.c | 78 + .../src/SKP_Silk_solve_LS_FLP.c | 203 + .../src/SKP_Silk_sort.c | 147 + .../src/SKP_Silk_sort_FLP.c | 128 + .../src/SKP_Silk_structs.h | 353 + .../src/SKP_Silk_structs_FLP.h | 168 + .../src/SKP_Silk_sum_sqr_shift.c | 100 + .../src/SKP_Silk_tables.h | 168 + .../src/SKP_Silk_tables_FLP.h | 52 + .../src/SKP_Silk_tables_LTP.c | 324 + .../src/SKP_Silk_tables_NLSF_CB0_10.c | 890 + .../src/SKP_Silk_tables_NLSF_CB0_10.h | 51 + .../src/SKP_Silk_tables_NLSF_CB0_10_FLP.c | 739 + .../src/SKP_Silk_tables_NLSF_CB0_16.c | 1320 + .../src/SKP_Silk_tables_NLSF_CB0_16.h | 51 + .../src/SKP_Silk_tables_NLSF_CB0_16_FLP.c | 1925 ++ .../src/SKP_Silk_tables_NLSF_CB1_10.c | 578 + .../src/SKP_Silk_tables_NLSF_CB1_10.h | 51 + .../src/SKP_Silk_tables_NLSF_CB1_10_FLP.c | 475 + .../src/SKP_Silk_tables_NLSF_CB1_16.c | 704 + .../src/SKP_Silk_tables_NLSF_CB1_16.h | 51 + .../src/SKP_Silk_tables_NLSF_CB1_16_FLP.c | 973 + .../src/SKP_Silk_tables_gain.c | 77 + .../src/SKP_Silk_tables_other.c | 148 + .../src/SKP_Silk_tables_other_FLP.c | 35 + .../src/SKP_Silk_tables_pitch_lag.c | 199 + .../src/SKP_Silk_tables_pulses_per_block.c | 235 + .../src/SKP_Silk_tables_sign.c | 42 + .../src/SKP_Silk_tables_type_offset.c | 52 + .../src/SKP_Silk_tuning_parameters.h | 183 + .../src/SKP_Silk_warped_autocorrelation_FLP.c | 69 + .../src/SKP_Silk_wrappers_FLP.c | 256 + .../src/Silk_FLP.vcproj | 744 + .../src/Silk_FLP.vcxproj | 331 + .../test/Dec_SDK.vcproj | 217 + .../test/Dec_SDK.vcxproj | 201 + .../SILK_SDK_SRC_FLP_v1.0.9/test/Decoder.c | 472 + .../test/Enc_SDK.vcproj | 217 + .../test/Enc_SDK.vcxproj | 201 + .../SILK_SDK_SRC_FLP_v1.0.9/test/Encoder.c | 369 + .../test/SignalCompare.vcproj | 197 + .../test/SignalCompare.vcxproj | 187 + .../test/signalCompare.c | 375 + .../How to use the test vectors.txt | 15 + ...yload_12_kHz_20_ms_24_kbps_10_loss_FEC.bit | Bin 0 -> 41125 bytes .../payload_12_kHz_40_ms_16_kbps.bit | Bin 0 -> 25590 bytes .../payload_12_kHz_60_ms_10_kbps.bit | Bin 0 -> 15883 bytes ...yload_16_kHz_20_ms_32_kbps_10_loss_FEC.bit | Bin 0 -> 53067 bytes .../payload_16_kHz_40_ms_20_kbps.bit | Bin 0 -> 30704 bytes .../payload_16_kHz_60_ms_12_kbps.bit | Bin 0 -> 19096 bytes ...yload_24_kHz_20_ms_40_kbps_10_loss_FEC.bit | Bin 0 -> 65310 bytes .../payload_24_kHz_40_ms_24_kbps.bit | Bin 0 -> 35977 bytes .../payload_24_kHz_60_ms_16_kbps.bit | Bin 0 -> 24404 bytes .../payload_32_kHz_max_8_kHz_20_ms_8_kbps.bit | Bin 0 -> 8009 bytes .../payload_44100_Hz_20_ms_7_kbps.bit | Bin 0 -> 12982 bytes ...ayload_8_kHz_20_ms_20_kbps_10_loss_FEC.bit | Bin 0 -> 34525 bytes .../bitstream/payload_8_kHz_40_ms_12_kbps.bit | Bin 0 -> 19365 bytes .../bitstream/payload_8_kHz_60_ms_8_kbps.bit | Bin 0 -> 12739 bytes .../input/testvector_input_12_kHz.pcm | Bin 0 -> 325206 bytes .../input/testvector_input_16_kHz.pcm | Bin 0 -> 433610 bytes .../input/testvector_input_24_kHz.pcm | Bin 0 -> 650410 bytes .../input/testvector_input_32_kHz.pcm | Bin 0 -> 487808 bytes .../input/testvector_input_44100_Hz.pcm | Bin 0 -> 1195130 bytes .../input/testvector_input_8_kHz.pcm | Bin 0 -> 216806 bytes ...utput_12_kHz_20_ms_24_kbps_10_loss_FEC.pcm | Bin 0 -> 649920 bytes ...testvector_output_12_kHz_40_ms_16_kbps.pcm | Bin 0 -> 648960 bytes ...testvector_output_12_kHz_60_ms_10_kbps.pcm | Bin 0 -> 648000 bytes ...output_12_kHz_60_ms_10_kbps_12_kHz_out.pcm | Bin 0 -> 324000 bytes ...output_12_kHz_60_ms_10_kbps_16_kHz_out.pcm | Bin 0 -> 432000 bytes ...output_12_kHz_60_ms_10_kbps_32_kHz_out.pcm | Bin 0 -> 864000 bytes ...tput_12_kHz_60_ms_10_kbps_44100_Hz_out.pcm | Bin 0 -> 1190700 bytes ...output_12_kHz_60_ms_10_kbps_48_kHz_out.pcm | Bin 0 -> 1296000 bytes ...utput_16_kHz_20_ms_32_kbps_10_loss_FEC.pcm | Bin 0 -> 649920 bytes ...testvector_output_16_kHz_40_ms_20_kbps.pcm | Bin 0 -> 648960 bytes ...testvector_output_16_kHz_60_ms_12_kbps.pcm | Bin 0 -> 648000 bytes ...output_16_kHz_60_ms_12_kbps_16_kHz_out.pcm | Bin 0 -> 432000 bytes ...utput_24_kHz_20_ms_40_kbps_10_loss_FEC.pcm | Bin 0 -> 649920 bytes ...testvector_output_24_kHz_40_ms_24_kbps.pcm | Bin 0 -> 648960 bytes ...testvector_output_24_kHz_60_ms_16_kbps.pcm | Bin 0 -> 648000 bytes ...r_output_32_kHz_max_8_kHz_20_ms_8_kbps.pcm | Bin 0 -> 365760 bytes ..._kHz_max_8_kHz_20_ms_8_kbps_32_kHz_out.pcm | Bin 0 -> 487680 bytes ...Hz_max_8_kHz_20_ms_8_kbps_44100_Hz_out.pcm | Bin 0 -> 672084 bytes ..._kHz_max_8_kHz_20_ms_8_kbps_48_kHz_out.pcm | Bin 0 -> 731520 bytes ...estvector_output_44100_Hz_20_ms_7_kbps.pcm | Bin 0 -> 649920 bytes ...output_8_kHz_20_ms_20_kbps_10_loss_FEC.pcm | Bin 0 -> 649920 bytes .../testvector_output_8_kHz_40_ms_12_kbps.pcm | Bin 0 -> 648960 bytes .../testvector_output_8_kHz_60_ms_8_kbps.pcm | Bin 0 -> 648000 bytes ...r_output_8_kHz_60_ms_8_kbps_12_kHz_out.pcm | Bin 0 -> 324000 bytes ...r_output_8_kHz_60_ms_8_kbps_16_kHz_out.pcm | Bin 0 -> 432000 bytes ...or_output_8_kHz_60_ms_8_kbps_8_kHz_out.pcm | Bin 0 -> 216000 bytes .../test_vectors/test_decoder.bat | 143 + .../test_vectors/test_decoder.sh | 142 + external/cbase64-1.1/AUTHORS | 24 - external/cbase64-1.1/LICENSE | 29 - external/cbase64-1.1/README.md | 169 - .../cbase64-1.1/include/cbase64/cbase64.h | 244 - external/celt-e18de77/config.h | 2 +- external/json_checker/JSON_checker.cpp | 398 - .../include/json_checker/JSON_checker.h | 17 - external/rapidjson-1.0.2/CHANGELOG.md | 79 - .../include/rapidjson/allocators.h | 261 - .../include/rapidjson/document.h | 2014 -- .../include/rapidjson/encodedstream.h | 261 - .../include/rapidjson/encodings.h | 625 - .../include/rapidjson/error/en.h | 65 - .../include/rapidjson/error/error.h | 146 - .../include/rapidjson/filereadstream.h | 88 - .../include/rapidjson/filewritestream.h | 91 - .../include/rapidjson/internal/biginteger.h | 280 - .../include/rapidjson/internal/diyfp.h | 247 - .../include/rapidjson/internal/dtoa.h | 217 - .../include/rapidjson/internal/ieee754.h | 77 - .../include/rapidjson/internal/itoa.h | 304 - .../include/rapidjson/internal/meta.h | 181 - .../include/rapidjson/internal/pow10.h | 55 - .../include/rapidjson/internal/stack.h | 179 - .../include/rapidjson/internal/strfunc.h | 39 - .../include/rapidjson/internal/strtod.h | 270 - .../include/rapidjson/memorybuffer.h | 70 - .../include/rapidjson/memorystream.h | 61 - .../include/rapidjson/msinttypes/inttypes.h | 316 - .../include/rapidjson/msinttypes/stdint.h | 300 - .../include/rapidjson/prettywriter.h | 207 - .../include/rapidjson/rapidjson.h | 654 - .../include/rapidjson/reader.h | 1452 - .../include/rapidjson/stringbuffer.h | 93 - .../include/rapidjson/writer.h | 395 - external/rapidjson-1.0.2/license.txt | 57 - external/rapidjson-1.0.2/readme.md | 129 - external/snappy-1.1.3/INSTALL | 370 - external/snappy-1.1.3/snappy-internal.h | 150 - external/snappy-1.1.3/snappy-stubs-internal.h | 491 - external/snappy-1.1.3/snappy.cc | 1553 - external/snappy-1.1.9/.appveyor.yml | 37 + external/snappy-1.1.9/.gitignore | 8 + external/snappy-1.1.9/.gitmodules | 6 + external/snappy-1.1.9/.travis.yml | 100 + .../{snappy-1.1.3 => snappy-1.1.9}/AUTHORS | 0 external/snappy-1.1.9/CMakeLists.txt | 398 + external/snappy-1.1.9/CONTRIBUTING.md | 46 + .../{snappy-1.1.3 => snappy-1.1.9}/COPYING | 0 external/{snappy-1.1.3 => snappy-1.1.9}/NEWS | 54 + .../README => snappy-1.1.9/README.md} | 89 +- .../snappy-1.1.9/cmake/SnappyConfig.cmake.in | 33 + external/snappy-1.1.9/cmake/config.h.in | 56 + external/snappy-1.1.9/docs/README.md | 72 + external/snappy-1.1.9/format_description.txt | 110 + external/snappy-1.1.9/framing_format.txt | 135 + .../snappy-c.cc | 4 +- .../snappy => snappy-1.1.9}/snappy-c.h | 0 external/snappy-1.1.9/snappy-internal.h | 317 + .../snappy-sinksource.cc | 35 +- .../snappy-sinksource.h | 22 +- .../snappy-stubs-internal.cc | 2 +- external/snappy-1.1.9/snappy-stubs-internal.h | 492 + .../snappy-stubs-public.h.in} | 60 +- external/snappy-1.1.9/snappy-test.cc | 503 + external/snappy-1.1.9/snappy-test.h | 342 + external/snappy-1.1.9/snappy.cc | 2193 ++ .../include/snappy => snappy-1.1.9}/snappy.h | 28 +- external/snappy-1.1.9/snappy_benchmark.cc | 330 + .../snappy-1.1.9/snappy_compress_fuzzer.cc | 60 + external/snappy-1.1.9/snappy_test_data.cc | 57 + external/snappy-1.1.9/snappy_test_data.h | 68 + external/snappy-1.1.9/snappy_test_tool.cc | 471 + .../snappy-1.1.9/snappy_uncompress_fuzzer.cc | 58 + external/snappy-1.1.9/snappy_unittest.cc | 966 + external/snappy-1.1.9/testdata/alice29.txt | 3609 +++ external/snappy-1.1.9/testdata/asyoulik.txt | 4122 +++ .../snappy-1.1.9/testdata/baddata1.snappy | Bin 0 -> 27512 bytes .../snappy-1.1.9/testdata/baddata2.snappy | Bin 0 -> 27483 bytes .../snappy-1.1.9/testdata/baddata3.snappy | Bin 0 -> 28384 bytes external/snappy-1.1.9/testdata/fireworks.jpeg | Bin 0 -> 123093 bytes external/snappy-1.1.9/testdata/geo.protodata | Bin 0 -> 118588 bytes external/snappy-1.1.9/testdata/html | 1 + external/snappy-1.1.9/testdata/html_x_4 | 1 + external/snappy-1.1.9/testdata/kppkn.gtb | Bin 0 -> 184320 bytes external/snappy-1.1.9/testdata/lcet10.txt | 7519 +++++ external/snappy-1.1.9/testdata/paper-100k.pdf | 598 + external/snappy-1.1.9/testdata/plrabn12.txt | 10699 +++++++ external/snappy-1.1.9/testdata/urls.10K | 10000 ++++++ external/sourcesdk/bitbuf.cpp | 1789 +- external/sourcesdk/common.cpp | 8 +- external/sourcesdk/include/sourcesdk/bitbuf.h | 835 +- .../include/sourcesdk/valve_support.h | 155 +- premake/celt.lua | 10 - premake/json_checker.lua | 20 - premake/premake5.lua | 22 +- premake/silk.lua | 20 + premake/snappy.lua | 9 +- premake/sourcesdk.lua | 2 +- 402 files changed, 106422 insertions(+), 18837 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 demboyz/base/CRC.h create mode 100644 demboyz/base/json.hpp delete mode 100644 demboyz/base/jsonfile.cpp delete mode 100644 demboyz/base/jsonfile.h create mode 100644 demboyz/base/steamid.h delete mode 100644 demboyz/demofile/demojson.cpp delete mode 100644 demboyz/demofile/demojson.h create mode 100644 demboyz/game/logic.cpp create mode 100644 demboyz/game/logic.h create mode 100644 demboyz/game/stringtables.cpp create mode 100644 demboyz/game/stringtables.h delete mode 100644 demboyz/io/conlogwriter.cpp create mode 100644 demboyz/io/demoreader.cpp delete mode 100644 demboyz/io/demowriter.cpp delete mode 100644 demboyz/io/demreader.cpp delete mode 100644 demboyz/io/idemowriter.h delete mode 100644 demboyz/io/jsonreader.cpp delete mode 100644 demboyz/io/jsonwriter.cpp create mode 100644 demboyz/io/voicewriter/opusfilewriter.h create mode 100644 demboyz/io/voicewriter/voicedatawriter.h create mode 100644 demboyz/netmessages/netmath.cpp create mode 100644 demboyz/netmessages/usermessages.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/Makefile create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK.sln create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK_VS2005.sln create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/doc/SILK_Evaluation.pdf create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/doc/SILK_RTP_PayloadFormat.pdf create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/doc/SILK_SDK_API.pdf create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/interface/SKP_Silk_SDK_API.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/interface/SKP_Silk_control.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/interface/SKP_Silk_errors.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/interface/SKP_Silk_typedef.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/readme.txt create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_A2NLSF.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_CNG.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_HP_variable_cutoff_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_Inlines.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LBRR_reset.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_analysis_filter_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_filter.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_order16.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LP_variable_cutoff.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LSF_cos_table.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_analysis_filter_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_scale_ctrl_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_MA.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A_stable.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_encode_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_sum_error_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_stabilize.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ_del_dec.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FIX.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FLP.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VAD.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VQ_nearest_neighbor_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_ana_filt_bank_1.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_apply_sine_window_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_autocorrelation_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad_alt.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_burg_modified_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_32.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_code_signs.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_common_pitch_est_defines.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_audio_bandwidth.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_codec_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_corrMatrix_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_create_init_destroy.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_dec_API.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarse_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarsest_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_core.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_frame.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_parameters.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pitch.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pulses.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decoder_set_fs.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_define.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_detect_SWB_input.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_enc_API.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_frame_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_parameters.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_pulses.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_energy_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LPC_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LTP_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pitch_lags_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pred_coefs_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_gain_quant.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_init_encoder_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_inner_product_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_interpolate.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_k2a_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_levinsondurbin_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lin2log.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_log2lin.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_int.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_short.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_macros.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main_FLP.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_noise_shape_analysis_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_analysis_core_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines_FLP.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_tables.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_prefilter_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_NLSFs_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_gains_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_quant_LTP_gains_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_range_coder.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_regularize_correlations_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2_3.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down3.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_AR2.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_ARMA4.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_IIR_FIR.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_copy.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down4.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down_FIR.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up2_HQ.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up4.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_structs.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_up2.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_residual_energy_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_copy_vector_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_vector_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_schur_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_setup_complexity.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_shell_coder.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sigm_Q15.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_solve_LS_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs_FLP.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sum_sqr_shift.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_FLP.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_LTP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_gain.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pitch_lag.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pulses_per_block.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_sign.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_type_offset.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tuning_parameters.h create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_warped_autocorrelation_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_wrappers_FLP.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcxproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcxproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Decoder.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcxproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/Encoder.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcxproj create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test/signalCompare.c create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/How to use the test vectors.txt create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_20_ms_24_kbps_10_loss_FEC.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_40_ms_16_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_60_ms_10_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_20_ms_32_kbps_10_loss_FEC.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_40_ms_20_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_60_ms_12_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_20_ms_40_kbps_10_loss_FEC.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_40_ms_24_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_60_ms_16_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_32_kHz_max_8_kHz_20_ms_8_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_44100_Hz_20_ms_7_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_20_ms_20_kbps_10_loss_FEC.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_40_ms_12_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_60_ms_8_kbps.bit create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_12_kHz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_16_kHz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_24_kHz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_32_kHz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_44100_Hz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/input/testvector_input_8_kHz.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_20_ms_24_kbps_10_loss_FEC.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_40_ms_16_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps_12_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps_16_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps_32_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps_44100_Hz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_12_kHz_60_ms_10_kbps_48_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_16_kHz_20_ms_32_kbps_10_loss_FEC.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_16_kHz_40_ms_20_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_16_kHz_60_ms_12_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_16_kHz_60_ms_12_kbps_16_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_24_kHz_20_ms_40_kbps_10_loss_FEC.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_24_kHz_40_ms_24_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_24_kHz_60_ms_16_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_32_kHz_max_8_kHz_20_ms_8_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_32_kHz_max_8_kHz_20_ms_8_kbps_32_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_32_kHz_max_8_kHz_20_ms_8_kbps_44100_Hz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_32_kHz_max_8_kHz_20_ms_8_kbps_48_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_44100_Hz_20_ms_7_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_20_ms_20_kbps_10_loss_FEC.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_40_ms_12_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_60_ms_8_kbps.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_60_ms_8_kbps_12_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_60_ms_8_kbps_16_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/output/testvector_output_8_kHz_60_ms_8_kbps_8_kHz_out.pcm create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/test_decoder.bat create mode 100755 external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/test_decoder.sh delete mode 100644 external/cbase64-1.1/AUTHORS delete mode 100644 external/cbase64-1.1/LICENSE delete mode 100644 external/cbase64-1.1/README.md delete mode 100644 external/cbase64-1.1/include/cbase64/cbase64.h delete mode 100644 external/json_checker/JSON_checker.cpp delete mode 100644 external/json_checker/include/json_checker/JSON_checker.h delete mode 100644 external/rapidjson-1.0.2/CHANGELOG.md delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/allocators.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/document.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/encodedstream.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/encodings.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/error/en.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/error/error.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/filereadstream.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/filewritestream.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/biginteger.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/diyfp.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/dtoa.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/ieee754.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/itoa.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/meta.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/pow10.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/stack.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/strfunc.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/internal/strtod.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/memorybuffer.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/memorystream.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/msinttypes/inttypes.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/msinttypes/stdint.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/prettywriter.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/rapidjson.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/reader.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/stringbuffer.h delete mode 100644 external/rapidjson-1.0.2/include/rapidjson/writer.h delete mode 100644 external/rapidjson-1.0.2/license.txt delete mode 100644 external/rapidjson-1.0.2/readme.md delete mode 100644 external/snappy-1.1.3/INSTALL delete mode 100644 external/snappy-1.1.3/snappy-internal.h delete mode 100644 external/snappy-1.1.3/snappy-stubs-internal.h delete mode 100644 external/snappy-1.1.3/snappy.cc create mode 100644 external/snappy-1.1.9/.appveyor.yml create mode 100644 external/snappy-1.1.9/.gitignore create mode 100644 external/snappy-1.1.9/.gitmodules create mode 100644 external/snappy-1.1.9/.travis.yml rename external/{snappy-1.1.3 => snappy-1.1.9}/AUTHORS (100%) create mode 100644 external/snappy-1.1.9/CMakeLists.txt create mode 100644 external/snappy-1.1.9/CONTRIBUTING.md rename external/{snappy-1.1.3 => snappy-1.1.9}/COPYING (100%) rename external/{snappy-1.1.3 => snappy-1.1.9}/NEWS (71%) rename external/{snappy-1.1.3/README => snappy-1.1.9/README.md} (59%) create mode 100644 external/snappy-1.1.9/cmake/SnappyConfig.cmake.in create mode 100644 external/snappy-1.1.9/cmake/config.h.in create mode 100644 external/snappy-1.1.9/docs/README.md create mode 100644 external/snappy-1.1.9/format_description.txt create mode 100644 external/snappy-1.1.9/framing_format.txt rename external/{snappy-1.1.3 => snappy-1.1.9}/snappy-c.cc (98%) rename external/{snappy-1.1.3/include/snappy => snappy-1.1.9}/snappy-c.h (100%) create mode 100644 external/snappy-1.1.9/snappy-internal.h rename external/{snappy-1.1.3 => snappy-1.1.9}/snappy-sinksource.cc (81%) rename external/{snappy-1.1.3 => snappy-1.1.9}/snappy-sinksource.h (93%) rename external/{snappy-1.1.3 => snappy-1.1.9}/snappy-stubs-internal.cc (96%) create mode 100644 external/snappy-1.1.9/snappy-stubs-internal.h rename external/{snappy-1.1.3/include/snappy/snappy-stubs-public.h => snappy-1.1.9/snappy-stubs-public.h.in} (71%) create mode 100644 external/snappy-1.1.9/snappy-test.cc create mode 100644 external/snappy-1.1.9/snappy-test.h create mode 100644 external/snappy-1.1.9/snappy.cc rename external/{snappy-1.1.3/include/snappy => snappy-1.1.9}/snappy.h (92%) create mode 100644 external/snappy-1.1.9/snappy_benchmark.cc create mode 100644 external/snappy-1.1.9/snappy_compress_fuzzer.cc create mode 100644 external/snappy-1.1.9/snappy_test_data.cc create mode 100644 external/snappy-1.1.9/snappy_test_data.h create mode 100644 external/snappy-1.1.9/snappy_test_tool.cc create mode 100644 external/snappy-1.1.9/snappy_uncompress_fuzzer.cc create mode 100644 external/snappy-1.1.9/snappy_unittest.cc create mode 100644 external/snappy-1.1.9/testdata/alice29.txt create mode 100644 external/snappy-1.1.9/testdata/asyoulik.txt create mode 100644 external/snappy-1.1.9/testdata/baddata1.snappy create mode 100644 external/snappy-1.1.9/testdata/baddata2.snappy create mode 100644 external/snappy-1.1.9/testdata/baddata3.snappy create mode 100644 external/snappy-1.1.9/testdata/fireworks.jpeg create mode 100644 external/snappy-1.1.9/testdata/geo.protodata create mode 100644 external/snappy-1.1.9/testdata/html create mode 100644 external/snappy-1.1.9/testdata/html_x_4 create mode 100644 external/snappy-1.1.9/testdata/kppkn.gtb create mode 100644 external/snappy-1.1.9/testdata/lcet10.txt create mode 100644 external/snappy-1.1.9/testdata/paper-100k.pdf create mode 100644 external/snappy-1.1.9/testdata/plrabn12.txt create mode 100644 external/snappy-1.1.9/testdata/urls.10K delete mode 100644 premake/json_checker.lua create mode 100644 premake/silk.lua diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..e328461 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,20 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "/usr/include/opus", + "${workspaceFolder}/external/sourcesdk/include", + "${workspaceFolder}/external/celt-e18de77/include", + "${workspaceFolder}/external/SILK_SDK_SRC_FLP_v1.0.9/interface", + "${workspaceFolder}/external/snappy-1.1.9", + "${workspaceFolder}/demboyz" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "intelliSenseMode": "linux-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/demboyz/base/CRC.h b/demboyz/base/CRC.h new file mode 100644 index 0000000..e20db35 --- /dev/null +++ b/demboyz/base/CRC.h @@ -0,0 +1,2066 @@ +/** + @file CRC.h + @author Daniel Bahr + @version 1.1.0.0 + @copyright + @parblock + CRC++ + Copyright (c) 2021, Daniel Bahr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of CRC++ nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + @endparblock +*/ + +/* + CRC++ can be configured by setting various #defines before #including this header file: + + #define crcpp_uint8 - Specifies the type used to store CRCs that have a width of 8 bits or less. + This type is not used in CRC calculations. Defaults to ::std::uint8_t. + #define crcpp_uint16 - Specifies the type used to store CRCs that have a width between 9 and 16 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint16_t. + #define crcpp_uint32 - Specifies the type used to store CRCs that have a width between 17 and 32 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint32_t. + #define crcpp_uint64 - Specifies the type used to store CRCs that have a width between 33 and 64 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint64_t. + #define crcpp_size - This type is used for loop iteration and function signatures only. Defaults to ::std::size_t. + #define CRCPP_USE_NAMESPACE - Define to place all CRC++ code within the ::CRCPP namespace. + #define CRCPP_BRANCHLESS - Define to enable a branchless CRC implementation. The branchless implementation uses a single integer + multiplication in the bit-by-bit calculation instead of a small conditional. The branchless implementation + may be faster on processor architectures which support single-instruction integer multiplication. + #define CRCPP_USE_CPP11 - Define to enables C++11 features (move semantics, constexpr, static_assert, etc.). + #define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS - Define to include definitions for little-used CRCs. +*/ + +#ifndef CRCPP_CRC_H_ +#define CRCPP_CRC_H_ + +#include // Includes CHAR_BIT +#ifdef CRCPP_USE_CPP11 +#include // Includes ::std::size_t +#include // Includes ::std::uint8_t, ::std::uint16_t, ::std::uint32_t, ::std::uint64_t +#else +#include // Includes size_t +#include // Includes uint8_t, uint16_t, uint32_t, uint64_t +#endif +#include // Includes ::std::numeric_limits +#include // Includes ::std::move + +#ifndef crcpp_uint8 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint8 ::std::uint8_t +# else + /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint8 uint8_t +# endif +#endif + +#ifndef crcpp_uint16 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint16 ::std::uint16_t +# else + /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint16 uint16_t +# endif +#endif + +#ifndef crcpp_uint32 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint32 ::std::uint32_t +# else + /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint32 uint32_t +# endif +#endif + +#ifndef crcpp_uint64 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint64 ::std::uint64_t +# else + /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint64 uint64_t +# endif +#endif + +#ifndef crcpp_size +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned size definition, used for specifying data sizes. +# define crcpp_size ::std::size_t +# else + /// @brief Unsigned size definition, used for specifying data sizes. +# define crcpp_size size_t +# endif +#endif + +#ifdef CRCPP_USE_CPP11 + /// @brief Compile-time expression definition. +# define crcpp_constexpr constexpr +#else + /// @brief Compile-time expression definition. +# define crcpp_constexpr const +#endif + +#ifdef CRCPP_USE_NAMESPACE +namespace CRCPP +{ +#endif + +/** + @brief Static class for computing CRCs. + @note This class supports computation of full and multi-part CRCs, using a bit-by-bit algorithm or a + byte-by-byte lookup table. The CRCs are calculated using as many optimizations as is reasonable. + If compiling with C++11, the constexpr keyword is used liberally so that many calculations are + performed at compile-time instead of at runtime. +*/ +class CRC +{ +public: + // Forward declaration + template + struct Table; + + /** + @brief CRC parameters. + */ + template + struct Parameters + { + CRCType polynomial; ///< CRC polynomial + CRCType initialValue; ///< Initial CRC value + CRCType finalXOR; ///< Value to XOR with the final CRC + bool reflectInput; ///< true to reflect all input bytes + bool reflectOutput; ///< true to reflect the output CRC (reflection occurs before the final XOR) + + Table MakeTable() const; + }; + + /** + @brief CRC lookup table. After construction, the CRC parameters are fixed. + @note A CRC table can be used for multiple CRC calculations. + */ + template + struct Table + { + // Constructors are intentionally NOT marked explicit. + Table(const Parameters & parameters); + +#ifdef CRCPP_USE_CPP11 + Table(Parameters && parameters); +#endif + + const Parameters & GetParameters() const; + + const CRCType * GetTable() const; + + CRCType operator[](unsigned char index) const; + + private: + void InitTable(); + + Parameters parameters; ///< CRC parameters used to construct the table + CRCType table[1 << CHAR_BIT]; ///< CRC lookup table + }; + + // The number of bits in CRCType must be at least as large as CRCWidth. + // CRCType must be an unsigned integer type or a custom type with operator overloads. + template + static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc); + + template + static CRCType CalculateBits(const void * data, crcpp_size size, const Parameters & parameters); + + template + static CRCType CalculateBits(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc); + + template + static CRCType CalculateBits(const void * data, crcpp_size size, const Table & lookupTable); + + template + static CRCType CalculateBits(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc); + + // Common CRCs up to 64 bits. + // Note: Check values are the computed CRCs when given an ASCII input of "123456789" (without null terminator) +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters< crcpp_uint8, 4> & CRC_4_ITU(); + static const Parameters< crcpp_uint8, 5> & CRC_5_EPC(); + static const Parameters< crcpp_uint8, 5> & CRC_5_ITU(); + static const Parameters< crcpp_uint8, 5> & CRC_5_USB(); + static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000A(); + static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000B(); + static const Parameters< crcpp_uint8, 6> & CRC_6_ITU(); + static const Parameters< crcpp_uint8, 6> & CRC_6_NR(); + static const Parameters< crcpp_uint8, 7> & CRC_7(); +#endif + static const Parameters< crcpp_uint8, 8> & CRC_8(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters< crcpp_uint8, 8> & CRC_8_EBU(); + static const Parameters< crcpp_uint8, 8> & CRC_8_MAXIM(); + static const Parameters< crcpp_uint8, 8> & CRC_8_WCDMA(); + static const Parameters< crcpp_uint8, 8> & CRC_8_LTE(); + static const Parameters & CRC_10(); + static const Parameters & CRC_10_CDMA2000(); + static const Parameters & CRC_11(); + static const Parameters & CRC_11_NR(); + static const Parameters & CRC_12_CDMA2000(); + static const Parameters & CRC_12_DECT(); + static const Parameters & CRC_12_UMTS(); + static const Parameters & CRC_13_BBC(); + static const Parameters & CRC_15(); + static const Parameters & CRC_15_MPT1327(); +#endif + static const Parameters & CRC_16_ARC(); + static const Parameters & CRC_16_BUYPASS(); + static const Parameters & CRC_16_CCITTFALSE(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_16_CDMA2000(); + static const Parameters & CRC_16_CMS(); + static const Parameters & CRC_16_DECTR(); + static const Parameters & CRC_16_DECTX(); + static const Parameters & CRC_16_DNP(); +#endif + static const Parameters & CRC_16_GENIBUS(); + static const Parameters & CRC_16_KERMIT(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_16_MAXIM(); + static const Parameters & CRC_16_MODBUS(); + static const Parameters & CRC_16_T10DIF(); + static const Parameters & CRC_16_USB(); +#endif + static const Parameters & CRC_16_X25(); + static const Parameters & CRC_16_XMODEM(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_17_CAN(); + static const Parameters & CRC_21_CAN(); + static const Parameters & CRC_24(); + static const Parameters & CRC_24_FLEXRAYA(); + static const Parameters & CRC_24_FLEXRAYB(); + static const Parameters & CRC_24_LTEA(); + static const Parameters & CRC_24_LTEB(); + static const Parameters & CRC_24_NRC(); + static const Parameters & CRC_30(); +#endif + static const Parameters & CRC_32(); + static const Parameters & CRC_32_BZIP2(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_32_C(); +#endif + static const Parameters & CRC_32_MPEG2(); + static const Parameters & CRC_32_POSIX(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_32_Q(); + static const Parameters & CRC_40_GSM(); + static const Parameters & CRC_64(); +#endif + +#ifdef CRCPP_USE_CPP11 + CRC() = delete; + CRC(const CRC & other) = delete; + CRC & operator=(const CRC & other) = delete; + CRC(CRC && other) = delete; + CRC & operator=(CRC && other) = delete; +#endif + +private: +#ifndef CRCPP_USE_CPP11 + CRC(); + CRC(const CRC & other); + CRC & operator=(const CRC & other); +#endif + + template + static IntegerType Reflect(IntegerType value, crcpp_uint16 numBits); + + template + static CRCType Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); + + template + static CRCType UndoFinalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); + + template + static CRCType CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder); + + template + static CRCType CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder); + + template + static CRCType CalculateRemainderBits(unsigned char byte, crcpp_size numBits, const Parameters & parameters, CRCType remainder); +}; + +/** + @brief Returns a CRC lookup table construct using these CRC parameters. + @note This function primarily exists to allow use of the auto keyword instead of instantiating + a table directly, since template parameters are not inferred in constructors. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC lookup table +*/ +template +inline CRC::Table CRC::Parameters::MakeTable() const +{ + // This should take advantage of RVO and optimize out the copy. + return CRC::Table(*this); +} + +/** + @brief Constructs a CRC table from a set of CRC parameters + @param[in] params CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline CRC::Table::Table(const Parameters & params) : + parameters(params) +{ + InitTable(); +} + +#ifdef CRCPP_USE_CPP11 +/** + @brief Constructs a CRC table from a set of CRC parameters + @param[in] params CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline CRC::Table::Table(Parameters && params) : + parameters(::std::move(params)) +{ + InitTable(); +} +#endif + +/** + @brief Gets the CRC parameters used to construct the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC parameters +*/ +template +inline const CRC::Parameters & CRC::Table::GetParameters() const +{ + return parameters; +} + +/** + @brief Gets the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC table +*/ +template +inline const CRCType * CRC::Table::GetTable() const +{ + return table; +} + +/** + @brief Gets an entry in the CRC table + @param[in] index Index into the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC table entry +*/ +template +inline CRCType CRC::Table::operator[](unsigned char index) const +{ + return table[index]; +} + +/** + @brief Initializes a CRC table. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline void CRC::Table::InitTable() +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK((CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1))); + + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + CRCType crc; + unsigned char byte = 0; + + // Loop over each dividend (each possible number storable in an unsigned char) + do + { + crc = CRC::CalculateRemainder(&byte, sizeof(byte), parameters, CRCType(0)); + + // This mask might not be necessary; all unit tests pass with this line commented out, + // but that might just be a coincidence based on the CRC parameters used for testing. + // In any case, this is harmless to leave in and only adds a single machine instruction per loop iteration. + crc &= BIT_MASK; + + if (!parameters.reflectInput && CRCWidth < CHAR_BIT) + { + // Undo the special operation at the end of the CalculateRemainder() + // function for non-reflected CRCs < CHAR_BIT. + crc = static_cast(crc << SHIFT); + } + + table[byte] = crc; + } + while (++byte); +} + +/** + @brief Computes a CRC. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bytes + @param[in] parameters CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters) +{ + CRCType remainder = CalculateRemainder(data, size, parameters, parameters.initialValue); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} +/** + @brief Appends additional data to a previous CRC calculation. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bytes + @param[in] parameters CRC parameters + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc) +{ + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + remainder = CalculateRemainder(data, size, parameters, remainder); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Computes a CRC via a lookup table. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bytes + @param[in] lookupTable CRC lookup table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = CalculateRemainder(data, size, lookupTable, parameters.initialValue); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Appends additional data to a previous CRC calculation using a lookup table. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bytes + @param[in] lookupTable CRC lookup table + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + remainder = CalculateRemainder(data, size, lookupTable, remainder); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Computes a CRC. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bits + @param[in] parameters CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Parameters & parameters) +{ + CRCType remainder = parameters.initialValue; + + // Calculate the remainder on a whole number of bytes first, then call + // a special-case function for the remaining bits. + crcpp_size wholeNumberOfBytes = size / CHAR_BIT; + if (wholeNumberOfBytes > 0) + { + remainder = CalculateRemainder(data, wholeNumberOfBytes, parameters, remainder); + } + + crcpp_size remainingNumberOfBits = size % CHAR_BIT; + if (remainingNumberOfBits != 0) + { + unsigned char lastByte = *(reinterpret_cast(data) + wholeNumberOfBytes); + remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder); + } + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} +/** + @brief Appends additional data to a previous CRC calculation. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bits + @param[in] parameters CRC parameters + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc) +{ + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + // Calculate the remainder on a whole number of bytes first, then call + // a special-case function for the remaining bits. + crcpp_size wholeNumberOfBytes = size / CHAR_BIT; + if (wholeNumberOfBytes > 0) + { + remainder = CalculateRemainder(data, wholeNumberOfBytes, parameters, parameters.initialValue); + } + + crcpp_size remainingNumberOfBits = size % CHAR_BIT; + if (remainingNumberOfBits != 0) + { + unsigned char lastByte = *(reinterpret_cast(data) + wholeNumberOfBytes); + remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder); + } + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Computes a CRC via a lookup table. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bits + @param[in] lookupTable CRC lookup table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Table & lookupTable) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = parameters.initialValue; + + // Calculate the remainder on a whole number of bytes first, then call + // a special-case function for the remaining bits. + crcpp_size wholeNumberOfBytes = size / CHAR_BIT; + if (wholeNumberOfBytes > 0) + { + remainder = CalculateRemainder(data, wholeNumberOfBytes, lookupTable, remainder); + } + + crcpp_size remainingNumberOfBits = size % CHAR_BIT; + if (remainingNumberOfBits != 0) + { + unsigned char lastByte = *(reinterpret_cast(data) + wholeNumberOfBytes); + remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder); + } + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Appends additional data to a previous CRC calculation using a lookup table. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data, in bits + @param[in] lookupTable CRC lookup table + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::CalculateBits(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + // Calculate the remainder on a whole number of bytes first, then call + // a special-case function for the remaining bits. + crcpp_size wholeNumberOfBytes = size / CHAR_BIT; + if (wholeNumberOfBytes > 0) + { + remainder = CalculateRemainder(data, wholeNumberOfBytes, lookupTable, parameters.initialValue); + } + + crcpp_size remainingNumberOfBits = size % CHAR_BIT; + if (remainingNumberOfBits > 0) + { + unsigned char lastByte = *(reinterpret_cast(data) + wholeNumberOfBytes); + remainder = CalculateRemainderBits(lastByte, remainingNumberOfBits, parameters, remainder); + } + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Reflects (i.e. reverses the bits within) an integer value. + @param[in] value Value to reflect + @param[in] numBits Number of bits in the integer which will be reflected + @tparam IntegerType Integer type of the value being reflected + @return Reflected value +*/ +template +inline IntegerType CRC::Reflect(IntegerType value, crcpp_uint16 numBits) +{ + IntegerType reversedValue(0); + + for (crcpp_uint16 i = 0; i < numBits; ++i) + { + reversedValue = static_cast((reversedValue << 1) | (value & 1)); + value = static_cast(value >> 1); + } + + return reversedValue; +} + +/** + @brief Computes the final reflection and XOR of a CRC remainder. + @param[in] remainder CRC remainder to reflect and XOR + @param[in] finalXOR Final value to XOR with the remainder + @param[in] reflectOutput true to reflect each byte of the remainder before the XOR + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return Final CRC +*/ +template +inline CRCType CRC::Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput) +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); + + if (reflectOutput) + { + remainder = Reflect(remainder, CRCWidth); + } + + return (remainder ^ finalXOR) & BIT_MASK; +} + +/** + @brief Undoes the process of computing the final reflection and XOR of a CRC remainder. + @note This function allows for computation of multi-part CRCs + @note Calling UndoFinalize() followed by Finalize() (or vice versa) will always return the original remainder value: + + CRCType x = ...; + CRCType y = Finalize(x, finalXOR, reflectOutput); + CRCType z = UndoFinalize(y, finalXOR, reflectOutput); + assert(x == z); + + @param[in] crc Reflected and XORed CRC + @param[in] finalXOR Final value XORed with the remainder + @param[in] reflectOutput true if the remainder is to be reflected + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return Un-finalized CRC remainder +*/ +template +inline CRCType CRC::UndoFinalize(CRCType crc, CRCType finalXOR, bool reflectOutput) +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); + + crc = (crc & BIT_MASK) ^ finalXOR; + + if (reflectOutput) + { + crc = Reflect(crc, CRCWidth); + } + + return crc; +} + +/** + @brief Computes a CRC remainder. + @param[in] data Data over which the remainder will be computed + @param[in] size Size of the data, in bytes + @param[in] parameters CRC parameters + @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC remainder +*/ +template +inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder) +{ +#ifdef CRCPP_USE_CPP11 + // This static_assert is put here because this function will always be compiled in no matter what + // the template parameters are and whether or not a table lookup or bit-by-bit algorithm is used. + static_assert(::std::numeric_limits::digits >= CRCWidth, "CRCType is too small to contain a CRC of width CRCWidth."); +#else + // Catching this compile-time error is very important. Sadly, the compiler error will be very cryptic, but it's + // better than nothing. + enum { static_assert_failed_CRCType_is_too_small_to_contain_a_CRC_of_width_CRCWidth = 1 / (::std::numeric_limits::digits >= CRCWidth ? 1 : 0) }; +#endif + + const unsigned char * current = reinterpret_cast(data); + + // Slightly different implementations based on the parameters. The current implementations try to eliminate as much + // computation from the inner loop (looping over each bit) as possible. + if (parameters.reflectInput) + { + CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth); + while (size--) + { + remainder = static_cast(remainder ^ *current++); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & 1) + // remainder = (remainder >> 1) ^ polynomial; + // else + // remainder >>= 1; + remainder = static_cast((remainder >> 1) ^ ((remainder & 1) * polynomial)); +#else + remainder = static_cast((remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1)); +#endif + } + } + } + else if (CRCWidth >= CHAR_BIT) + { + static crcpp_constexpr CRCType CRC_WIDTH_MINUS_ONE(CRCWidth - CRCType(1)); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast(CRCWidth - CHAR_BIT) : 0); + + while (size--) + { + remainder = static_cast(remainder ^ (static_cast(*current++) << SHIFT)); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CRC_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ parameters.polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial)); +#else + remainder = static_cast((remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1)); +#endif + } + } + } + else + { + static crcpp_constexpr CRCType CHAR_BIT_MINUS_ONE(CHAR_BIT - 1); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + CRCType polynomial = static_cast(parameters.polynomial << SHIFT); + remainder = static_cast(remainder << SHIFT); + + while (size--) + { + remainder = static_cast(remainder ^ *current++); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CHAR_BIT_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial)); +#else + remainder = static_cast((remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1)); +#endif + } + } + + remainder = static_cast(remainder >> SHIFT); + } + + return remainder; +} + +/** + @brief Computes a CRC remainder using lookup table. + @param[in] data Data over which the remainder will be computed + @param[in] size Size of the data, in bytes + @param[in] lookupTable CRC lookup table + @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC remainder +*/ +template +inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder) +{ + const unsigned char * current = reinterpret_cast(data); + + if (lookupTable.GetParameters().reflectInput) + { + while (size--) + { +#if defined(WIN32) || defined(_WIN32) || defined(WINCE) + // Disable warning about data loss when doing (remainder >> CHAR_BIT) when + // remainder is one byte long. The algorithm is still correct in this case, + // though it's possible that one additional machine instruction will be executed. +# pragma warning (push) +# pragma warning (disable : 4333) +#endif + remainder = static_cast((remainder >> CHAR_BIT) ^ lookupTable[static_cast(remainder ^ *current++)]); +#if defined(WIN32) || defined(_WIN32) || defined(WINCE) +# pragma warning (pop) +#endif + } + } + else if (CRCWidth >= CHAR_BIT) + { + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast(CRCWidth - CHAR_BIT) : 0); + + while (size--) + { + remainder = static_cast((remainder << CHAR_BIT) ^ lookupTable[static_cast((remainder >> SHIFT) ^ *current++)]); + } + } + else + { + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + remainder = static_cast(remainder << SHIFT); + + while (size--) + { + // Note: no need to mask here since remainder is guaranteed to fit in a single byte. + remainder = lookupTable[static_cast(remainder ^ *current++)]; + } + + remainder = static_cast(remainder >> SHIFT); + } + + return remainder; +} + +template +inline CRCType CRC::CalculateRemainderBits(unsigned char byte, crcpp_size numBits, const Parameters & parameters, CRCType remainder) +{ + // Slightly different implementations based on the parameters. The current implementations try to eliminate as much + // computation from the inner loop (looping over each bit) as possible. + if (parameters.reflectInput) + { + CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth); + remainder = static_cast(remainder ^ byte); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < numBits; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & 1) + // remainder = (remainder >> 1) ^ polynomial; + // else + // remainder >>= 1; + remainder = static_cast((remainder >> 1) ^ ((remainder & 1) * polynomial)); +#else + remainder = static_cast((remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1)); +#endif + } + } + else if (CRCWidth >= CHAR_BIT) + { + static crcpp_constexpr CRCType CRC_WIDTH_MINUS_ONE(CRCWidth - CRCType(1)); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast(CRCWidth - CHAR_BIT) : 0); + + remainder = static_cast(remainder ^ (static_cast(byte) << SHIFT)); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < numBits; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CRC_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ parameters.polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial)); +#else + remainder = static_cast((remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1)); +#endif + } + } + else + { + static crcpp_constexpr CRCType CHAR_BIT_MINUS_ONE(CHAR_BIT - 1); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + CRCType polynomial = static_cast(parameters.polynomial << SHIFT); + remainder = static_cast((remainder << SHIFT) ^ byte); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < numBits; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CHAR_BIT_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial)); +#else + remainder = static_cast((remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1)); +#endif + } + + remainder = static_cast(remainder >> SHIFT); + } + + return remainder; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-4 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-4 ITU has the following parameters and check value: + - polynomial = 0x3 + - initial value = 0x0 + - final XOR = 0x0 + - reflect input = true + - reflect output = true + - check value = 0x7 + @return CRC-4 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_4_ITU() +{ + static const Parameters parameters = { 0x3, 0x0, 0x0, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 EPC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 EPC has the following parameters and check value: + - polynomial = 0x09 + - initial value = 0x09 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x00 + @return CRC-5 EPC parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_EPC() +{ + static const Parameters parameters = { 0x09, 0x09, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 ITU has the following parameters and check value: + - polynomial = 0x15 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x07 + @return CRC-5 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_ITU() +{ + static const Parameters parameters = { 0x15, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 USB. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 USB has the following parameters and check value: + - polynomial = 0x05 + - initial value = 0x1F + - final XOR = 0x1F + - reflect input = true + - reflect output = true + - check value = 0x19 + @return CRC-5 USB parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_USB() +{ + static const Parameters parameters = { 0x05, 0x1F, 0x1F, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 CDMA2000-A. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 CDMA2000-A has the following parameters and check value: + - polynomial = 0x27 + - initial value = 0x3F + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x0D + @return CRC-6 CDMA2000-A parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_CDMA2000A() +{ + static const Parameters parameters = { 0x27, 0x3F, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 CDMA2000-B. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 CDMA2000-A has the following parameters and check value: + - polynomial = 0x07 + - initial value = 0x3F + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x3B + @return CRC-6 CDMA2000-B parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_CDMA2000B() +{ + static const Parameters parameters = { 0x07, 0x3F, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 ITU has the following parameters and check value: + - polynomial = 0x03 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x06 + @return CRC-6 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_ITU() +{ + static const Parameters parameters = { 0x03, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 NR. + @note The parameters are static and are delayed-constructed to reduce memory + footprint. + @note CRC-6 NR has the following parameters and check value: + - polynomial = 0x21 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x15 + @return CRC-6 NR parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_NR() +{ + static const Parameters parameters = { 0x21, 0x00, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-7 JEDEC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-7 JEDEC has the following parameters and check value: + - polynomial = 0x09 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x75 + @return CRC-7 JEDEC parameters +*/ +inline const CRC::Parameters & CRC::CRC_7() +{ + static const Parameters parameters = { 0x09, 0x00, 0x00, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-8 SMBus. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 SMBus has the following parameters and check value: + - polynomial = 0x07 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0xF4 + @return CRC-8 SMBus parameters +*/ +inline const CRC::Parameters & CRC::CRC_8() +{ + static const Parameters parameters = { 0x07, 0x00, 0x00, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-8 EBU (aka CRC-8 AES). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 EBU has the following parameters and check value: + - polynomial = 0x1D + - initial value = 0xFF + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x97 + @return CRC-8 EBU parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_EBU() +{ + static const Parameters parameters = { 0x1D, 0xFF, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-8 MAXIM (aka CRC-8 DOW-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 MAXIM has the following parameters and check value: + - polynomial = 0x31 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0xA1 + @return CRC-8 MAXIM parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_MAXIM() +{ + static const Parameters parameters = { 0x31, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-8 WCDMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 WCDMA has the following parameters and check value: + - polynomial = 0x9B + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x25 + @return CRC-8 WCDMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_WCDMA() +{ + static const Parameters parameters = { 0x9B, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-8 LTE. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 LTE has the following parameters and check value: + - polynomial = 0x9B + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0xEA + @return CRC-8 LTE parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_LTE() +{ + static const Parameters parameters = { 0x9B, 0x00, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-10 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-10 ITU has the following parameters and check value: + - polynomial = 0x233 + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x199 + @return CRC-10 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_10() +{ + static const Parameters parameters = { 0x233, 0x000, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-10 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-10 CDMA2000 has the following parameters and check value: + - polynomial = 0x3D9 + - initial value = 0x3FF + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x233 + @return CRC-10 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_10_CDMA2000() +{ + static const Parameters parameters = { 0x3D9, 0x3FF, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-11 FlexRay. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-11 FlexRay has the following parameters and check value: + - polynomial = 0x385 + - initial value = 0x01A + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x5A3 + @return CRC-11 FlexRay parameters +*/ +inline const CRC::Parameters & CRC::CRC_11() +{ + static const Parameters parameters = { 0x385, 0x01A, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-11 NR. + @note The parameters are static and are delayed-constructed to reduce memory + footprint. + @note CRC-11 NR has the following parameters and check value: + - polynomial = 0x621 + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x5CA + @return CRC-11 NR parameters +*/ +inline const CRC::Parameters & CRC::CRC_11_NR() +{ + static const Parameters parameters = { 0x621, 0x000, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 CDMA2000 has the following parameters and check value: + - polynomial = 0xF13 + - initial value = 0xFFF + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0xD4D + @return CRC-12 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_CDMA2000() +{ + static const Parameters parameters = { 0xF13, 0xFFF, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 DECT (aka CRC-12 X-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 DECT has the following parameters and check value: + - polynomial = 0x80F + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0xF5B + @return CRC-12 DECT parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_DECT() +{ + static const Parameters parameters = { 0x80F, 0x000, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 UMTS (aka CRC-12 3GPP). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 UMTS has the following parameters and check value: + - polynomial = 0x80F + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = true + - check value = 0xDAF + @return CRC-12 UMTS parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_UMTS() +{ + static const Parameters parameters = { 0x80F, 0x000, 0x000, false, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-13 BBC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-13 BBC has the following parameters and check value: + - polynomial = 0x1CF5 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x04FA + @return CRC-13 BBC parameters +*/ +inline const CRC::Parameters & CRC::CRC_13_BBC() +{ + static const Parameters parameters = { 0x1CF5, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-15 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-15 CAN has the following parameters and check value: + - polynomial = 0x4599 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x059E + @return CRC-15 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_15() +{ + static const Parameters parameters = { 0x4599, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-15 MPT1327. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-15 MPT1327 has the following parameters and check value: + - polynomial = 0x6815 + - initial value = 0x0000 + - final XOR = 0x0001 + - reflect input = false + - reflect output = false + - check value = 0x2566 + @return CRC-15 MPT1327 parameters +*/ +inline const CRC::Parameters & CRC::CRC_15_MPT1327() +{ + static const Parameters parameters = { 0x6815, 0x0000, 0x0001, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 ARC (aka CRC-16 IBM, CRC-16 LHA). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 ARC has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0xBB3D + @return CRC-16 ARC parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_ARC() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0x0000, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 BUYPASS (aka CRC-16 VERIFONE, CRC-16 UMTS). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 BUYPASS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xFEE8 + @return CRC-16 BUYPASS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_BUYPASS() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 CCITT FALSE. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CCITT FALSE has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x29B1 + @return CRC-16 CCITT FALSE parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CCITTFALSE() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-16 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CDMA2000 has the following parameters and check value: + - polynomial = 0xC867 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x4C06 + @return CRC-16 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CDMA2000() +{ + static const Parameters parameters = { 0xC867, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 CMS. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CMS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xAEE7 + @return CRC-16 CMS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CMS() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DECT-R (aka CRC-16 R-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DECT-R has the following parameters and check value: + - polynomial = 0x0589 + - initial value = 0x0000 + - final XOR = 0x0001 + - reflect input = false + - reflect output = false + - check value = 0x007E + @return CRC-16 DECT-R parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DECTR() +{ + static const Parameters parameters = { 0x0589, 0x0000, 0x0001, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DECT-X (aka CRC-16 X-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DECT-X has the following parameters and check value: + - polynomial = 0x0589 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x007F + @return CRC-16 DECT-X parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DECTX() +{ + static const Parameters parameters = { 0x0589, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DNP. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DNP has the following parameters and check value: + - polynomial = 0x3D65 + - initial value = 0x0000 + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0xEA82 + @return CRC-16 DNP parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DNP() +{ + static const Parameters parameters = { 0x3D65, 0x0000, 0xFFFF, true, true }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 GENIBUS (aka CRC-16 EPC, CRC-16 I-CODE, CRC-16 DARC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 GENIBUS has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = false + - reflect output = false + - check value = 0xD64E + @return CRC-16 GENIBUS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_GENIBUS() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 KERMIT (aka CRC-16 CCITT, CRC-16 CCITT-TRUE). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 KERMIT has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0x2189 + @return CRC-16 KERMIT parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_KERMIT() +{ + static const Parameters parameters = { 0x1021, 0x0000, 0x0000, true, true }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-16 MAXIM. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 MAXIM has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0x44C2 + @return CRC-16 MAXIM parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_MAXIM() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0xFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 MODBUS. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 MODBUS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0x4B37 + @return CRC-16 MODBUS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_MODBUS() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0x0000, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 T10-DIF. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 T10-DIF has the following parameters and check value: + - polynomial = 0x8BB7 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xD0DB + @return CRC-16 T10-DIF parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_T10DIF() +{ + static const Parameters parameters = { 0x8BB7, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 USB. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 USB has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0xB4C8 + @return CRC-16 USB parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_USB() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0xFFFF, true, true }; + return parameters; +} + +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 X-25 (aka CRC-16 IBM-SDLC, CRC-16 ISO-HDLC, CRC-16 B). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 X-25 has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0x906E + @return CRC-16 X-25 parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_X25() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 XMODEM (aka CRC-16 ZMODEM, CRC-16 ACORN, CRC-16 LTE). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 XMODEM has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x31C3 + @return CRC-16 XMODEM parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_XMODEM() +{ + static const Parameters parameters = { 0x1021, 0x0000, 0x0000, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-17 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-17 CAN has the following parameters and check value: + - polynomial = 0x1685B + - initial value = 0x00000 + - final XOR = 0x00000 + - reflect input = false + - reflect output = false + - check value = 0x04F03 + @return CRC-17 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_17_CAN() +{ + static const Parameters parameters = { 0x1685B, 0x00000, 0x00000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-21 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-21 CAN has the following parameters and check value: + - polynomial = 0x102899 + - initial value = 0x000000 + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x0ED841 + @return CRC-21 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_21_CAN() +{ + static const Parameters parameters = { 0x102899, 0x000000, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 OPENPGP. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 OPENPGP has the following parameters and check value: + - polynomial = 0x864CFB + - initial value = 0xB704CE + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x21CF02 + @return CRC-24 OPENPGP parameters +*/ +inline const CRC::Parameters & CRC::CRC_24() +{ + static const Parameters parameters = { 0x864CFB, 0xB704CE, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 FlexRay-A. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 FlexRay-A has the following parameters and check value: + - polynomial = 0x5D6DCB + - initial value = 0xFEDCBA + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x7979BD + @return CRC-24 FlexRay-A parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_FLEXRAYA() +{ + static const Parameters parameters = { 0x5D6DCB, 0xFEDCBA, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 FlexRay-B. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 FlexRay-B has the following parameters and check value: + - polynomial = 0x5D6DCB + - initial value = 0xABCDEF + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x1F23B8 + @return CRC-24 FlexRay-B parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_FLEXRAYB() +{ + static const Parameters parameters = { 0x5D6DCB, 0xABCDEF, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 LTE-A/NR-A. + @note The parameters are static and are delayed-constructed to reduce memory + footprint. + @note CRC-24 LTE-A has the following parameters and check value: + - polynomial = 0x864CFB + - initial value = 0x000000 + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0xCDE703 + @return CRC-24 LTE-A parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_LTEA() +{ + static const Parameters parameters = { 0x864CFB, 0x000000, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 LTE-B/NR-B. + @note The parameters are static and are delayed-constructed to reduce memory + footprint. + @note CRC-24 LTE-B has the following parameters and check value: + - polynomial = 0x800063 + - initial value = 0x000000 + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x23EF52 + @return CRC-24 LTE-B parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_LTEB() +{ + static const Parameters parameters = { 0x800063, 0x000000, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 NR-C. + @note The parameters are static and are delayed-constructed to reduce memory + footprint. + @note CRC-24 NR-C has the following parameters and check value: + - polynomial = 0xB2B117 + - initial value = 0x000000 + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0xF48279 + @return CRC-24 NR-C parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_NRC() +{ + static const Parameters parameters = { 0xB2B117, 0x000000, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-30 CDMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-30 CDMA has the following parameters and check value: + - polynomial = 0x2030B9C7 + - initial value = 0x3FFFFFFF + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x3B3CB540 + @return CRC-30 CDMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_30() +{ + static const Parameters parameters = { 0x2030B9C7, 0x3FFFFFFF, 0x00000000, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-32 (aka CRC-32 ADCCP, CRC-32 PKZip). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = true + - reflect output = true + - check value = 0xCBF43926 + @return CRC-32 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-32 BZIP2 (aka CRC-32 AAL5, CRC-32 DECT-B, CRC-32 B-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 BZIP2 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0xFC891918 + @return CRC-32 BZIP2 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_BZIP2() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-32 C (aka CRC-32 ISCSI, CRC-32 Castagnoli, CRC-32 Interlaken). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 C has the following parameters and check value: + - polynomial = 0x1EDC6F41 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = true + - reflect output = true + - check value = 0xE3069283 + @return CRC-32 C parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_C() +{ + static const Parameters parameters = { 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; + return parameters; +} +#endif + +/** + @brief Returns a set of parameters for CRC-32 MPEG-2. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 MPEG-2 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x0376E6E7 + @return CRC-32 MPEG-2 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_MPEG2() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-32 POSIX. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 POSIX has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0x00000000 + - final XOR = 0xFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0x765E7680 + @return CRC-32 POSIX parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_POSIX() +{ + static const Parameters parameters = { 0x04C11DB7, 0x00000000, 0xFFFFFFFF, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-32 Q. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 Q has the following parameters and check value: + - polynomial = 0x814141AB + - initial value = 0x00000000 + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x3010BF7F + @return CRC-32 Q parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_Q() +{ + static const Parameters parameters = { 0x814141AB, 0x00000000, 0x00000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-40 GSM. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-40 GSM has the following parameters and check value: + - polynomial = 0x0004820009 + - initial value = 0x0000000000 + - final XOR = 0xFFFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0xD4164FC646 + @return CRC-40 GSM parameters +*/ +inline const CRC::Parameters & CRC::CRC_40_GSM() +{ + static const Parameters parameters = { 0x0004820009, 0x0000000000, 0xFFFFFFFFFF, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-64 ECMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-64 ECMA has the following parameters and check value: + - polynomial = 0x42F0E1EBA9EA3693 + - initial value = 0x0000000000000000 + - final XOR = 0x0000000000000000 + - reflect input = false + - reflect output = false + - check value = 0x6C40DF5F0B497347 + @return CRC-64 ECMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_64() +{ + static const Parameters parameters = { 0x42F0E1EBA9EA3693, 0x0000000000000000, 0x0000000000000000, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +#ifdef CRCPP_USE_NAMESPACE +} +#endif + +#endif // CRCPP_CRC_H_ diff --git a/demboyz/base/json.hpp b/demboyz/base/json.hpp new file mode 100644 index 0000000..a70aaf8 --- /dev/null +++ b/demboyz/base/json.hpp @@ -0,0 +1,25447 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.9.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 9 +#define NLOHMANN_JSON_VERSION_PATCH 1 + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 13) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 13 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP \ +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). +json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; +} // namespace detail +} // namespace nlohmann + +// #include +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ +#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; + +template +struct ordered_map; + +/*! +@brief ordered JSON class + +This type preserves the insertion order of object keys. + +@since version 3.9.0 +*/ +using ordered_json = basic_json; + +} // namespace nlohmann + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using iterator_t = typename T::iterator; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, + enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + + +/////////////////// +// is_ functions // +/////////////////// + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + std::is_constructible::value && + std::is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (std::is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (std::is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl < + BasicJsonType, CompatibleStringType, + enable_if_t::value >> +{ + static constexpr auto value = + std::is_constructible::value; +}; + +template +struct is_compatible_string_type + : is_compatible_string_type_impl {}; + +template +struct is_constructible_string_type_impl : std::false_type {}; + +template +struct is_constructible_string_type_impl < + BasicJsonType, ConstructibleStringType, + enable_if_t::value >> +{ + static constexpr auto value = + std::is_constructible::value; +}; + +template +struct is_constructible_string_type + : is_constructible_string_type_impl {}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < is_detected::value&& + is_detected::value&& +// This is needed because json_reverse_iterator has a ::iterator type... +// Therefore it is detected as a CompatibleArrayType. +// The real fix would be to have an Iterable concept. + !is_iterator_traits < + iterator_traits>::value >> +{ + static constexpr bool value = + std::is_constructible::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + std::is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_detected::value&& +is_complete_type < +detected_t>::value >> +{ + static constexpr bool value = + // This is needed because json_reverse_iterator has a ::iterator type, + // furthermore, std::back_insert_iterator (and other iterators) have a + // base class `iterator`... Therefore it is detected as a + // ConstructibleArrayType. The real fix would be to have an Iterable + // concept. + !is_iterator_traits>::value && + + (std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, typename ConstructibleArrayType::value_type >::value); +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B1 { }; +template +struct conjunction +: std::conditional, B1>::type {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +} +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +template +void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + { + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename ConstructibleStringType, + enable_if_t < + is_constructible_string_type::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ConstructibleStringType& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.clear(); + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N]) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) +{ + arr = *j.template get_ptr(); +} + +template +auto from_json_array_impl(const BasicJsonType& j, std::array& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + j.template get(), + void()) +{ + using std::end; + + ConstructibleArrayType ret; + ret.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(ret, end(ret)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template +void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, + priority_tag<0> /*unused*/) +{ + using std::end; + + ConstructibleArrayType ret; + std::transform( + j.begin(), j.end(), std::inserter(ret, end(ret)), + [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get(), +void()) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<3> {}); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); + } + + bin = *j.template get_ptr(); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + ConstructibleObjectType ret; + auto inner_object = j.template get_ptr(); + using value_type = typename ConstructibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(ret, ret.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); + obj = std::move(ret); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence /*unused*/) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +struct from_json_fn +{ + template + auto operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } +}; +} // namespace detail + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} // namespace +} // namespace nlohmann + +// #include + + +#include // copy +#include // begin, end +#include // string +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + + +#include // size_t +#include // input_iterator_tag +#include // string, to_string +#include // tuple_size, get, tuple_element + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +void int_to_string( string_type& target, std::size_t value ) +{ + // For ADL + using std::to_string; + target = to_string(value); +} +template class iteration_proxy_value +{ + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_value; + using pointer = value_type * ; + using reference = value_type & ; + using iterator_category = std::input_iterator_tag; + using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; + + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable string_type array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + const string_type empty_str = ""; + + public: + explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_value& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_value& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_value& o) const + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_value& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + const string_type& key() const + { + JSON_ASSERT(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + int_to_string( array_index_str, array_index ); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } +}; + +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_value begin() noexcept + { + return iteration_proxy_value(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_value end() noexcept + { + return iteration_proxy_value(container.end()); + } +}; +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) +{ + return i.key(); +} +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) +{ + return i.value(); +} +} // namespace detail +} // namespace nlohmann + +// The Addition to the STD Namespace is required to add +// Structured Bindings Support to the iteration_proxy_value class +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +namespace std +{ +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::iteration_proxy_value> + : public std::integral_constant {}; + +template +class tuple_element> +{ + public: + using type = decltype( + get(std::declval < + ::nlohmann::detail::iteration_proxy_value> ())); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif +} // namespace std + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + { + j.m_type = value_t::binary; + typename BasicJsonType::binary_t value{b}; + j.m_value = value; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + { + j.m_type = value_t::binary; + typename BasicJsonType::binary_t value{std::move(b)}; + j.m_value = value; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + if (arr.size() > 0) + { + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + } + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) +{ + external_constructor::construct(j, bin); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t < !std::is_constructible::value, + int > = 0 > +void to_json(BasicJsonType& j, const T(&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = { p.first, p.second }; +} + +// for https://github.com/nlohmann/json/pull/1134 +template>::value, int> = 0> +void to_json(BasicJsonType& j, const T& b) +{ + j = { {b.key(), b.value()} }; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +{ + j = { std::get(t)... }; +} + +template::value, int > = 0> +void to_json(BasicJsonType& j, const T& t) +{ + to_json_tuple_impl(j, t, make_index_sequence::value> {}); +} + +struct to_json_fn +{ + template + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } +}; +} // namespace detail + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} // namespace +} // namespace nlohmann + + +namespace nlohmann +{ + +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static auto from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + -> decltype(::nlohmann::from_json(std::forward(j), val), void()) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; + +} // namespace nlohmann + +// #include + + +#include // uint8_t +#include // tie +#include // move + +namespace nlohmann +{ + +/*! +@brief an internal type for a backed binary type + +This type extends the template parameter @a BinaryType provided to `basic_json` +with a subtype used by BSON and MessagePack. This type exists so that the user +does not have to specify a type themselves with a specific naming scheme in +order to override the binary type. + +@tparam BinaryType container to store bytes (`std::vector` by + default) + +@since version 3.8.0 +*/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + /// the type of the underlying container + using container_type = BinaryType; + + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + byte_container_with_subtype(const container_type& b, std::uint8_t subtype) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + byte_container_with_subtype(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype) + , m_has_subtype(true) + {} + + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + + /*! + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return size_t(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa @ref subtype() -- return the binary subtype + @sa @ref set_subtype() -- sets the binary subtype + @sa @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; +}; + +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +#include // size_t, uint8_t +#include // hash + +namespace nlohmann +{ +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@brief hash a JSON value + +The hash function tries to rely on std::hash where possible. Furthermore, the +type of the JSON value is taken into account to have different hash values for +null, 0, 0U, and false, etc. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + using string_t = typename BasicJsonType::string_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + const auto type = static_cast(j.type()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case nlohmann::detail::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, j.get_binary().subtype()); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } +} + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // generate_n +#include // array +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf +#include // memcpy +#include // back_inserter +#include // numeric_limits +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + + +#include // array +#include // size_t +#include //FILE * +#include // strlen +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson, bson }; + +//////////////////// +// input adapters // +//////////////////// + +/*! +Input adapter for stdio file access. This adapter read only 1 byte and do not use any + buffer. This adapter is a very low level adapter. +*/ +class file_input_adapter +{ + public: + using char_type = char; + + JSON_HEDLEY_NON_NULL(2) + explicit file_input_adapter(std::FILE* f) noexcept + : m_file(f) + {} + + // make class move-only + file_input_adapter(const file_input_adapter&) = delete; + file_input_adapter(file_input_adapter&&) = default; + file_input_adapter& operator=(const file_input_adapter&) = delete; + file_input_adapter& operator=(file_input_adapter&&) = delete; + + std::char_traits::int_type get_character() noexcept + { + return std::fgetc(m_file); + } + + private: + /// the file pointer to read from + std::FILE* m_file; +}; + + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter +{ + public: + using char_type = char; + + ~input_stream_adapter() + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags, except eof + if (is != nullptr) + { + is->clear(is->rdstate() & std::ios::eofbit); + } + } + + explicit input_stream_adapter(std::istream& i) + : is(&i), sb(i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete; + + input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb) + { + rhs.is = nullptr; + rhs.sb = nullptr; + } + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() + { + auto res = sb->sbumpc(); + // set eof manually, as we don't use the istream interface. + if (JSON_HEDLEY_UNLIKELY(res == EOF)) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + + private: + /// the associated input stream + std::istream* is = nullptr; + std::streambuf* sb = nullptr; +}; + +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter +{ + public: + using char_type = typename std::iterator_traits::value_type; + + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) {} + + typename std::char_traits::int_type get_character() + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + auto result = std::char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + else + { + return std::char_traits::eof(); + } + } + + private: + IteratorType current; + IteratorType end; + + template + friend struct wide_string_input_helper; + + bool empty() const + { + return current == end; + } + +}; + + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper +{ + // UTF-32 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc || wc >= 0xE000) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else + { + if (JSON_HEDLEY_UNLIKELY(!input.empty())) + { + const auto wc2 = static_cast(input.get_character()); + const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); + utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } + } +}; + +// Wraps another input apdater to convert wide character types into individual bytes. +template +class wide_string_input_adapter +{ + public: + using char_type = char; + + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} + + typename std::char_traits::int_type get_character() noexcept + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + fill_buffer(); + + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); + } + + // use buffer + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + BaseInputAdapter base_adapter; + + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(std::move(first), std::move(last)); + } +}; + +template +struct is_iterator_of_multibyte +{ + using value_type = typename std::iterator_traits::value_type; + enum + { + value = sizeof(value_type) > 1 + }; +}; + +template +struct iterator_input_adapter_factory::value>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) +{ + using factory_type = iterator_input_adapter_factory; + return factory_type::create(first, last); +} + +// Convenience shorthand from container to iterator +template +auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) +{ + // Enable ADL + using std::begin; + using std::end; + + return input_adapter(begin(container), end(container)); +} + +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) +{ + return file_input_adapter(file); +} + +inline input_stream_adapter input_adapter(std::istream& stream) +{ + return input_stream_adapter(stream); +} + +inline input_stream_adapter input_adapter(std::istream&& stream) +{ + return input_stream_adapter(stream); +} + +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + +// Null-delimited strings, and the like. +template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > +contiguous_bytes_input_adapter input_adapter(CharT b) +{ + auto length = std::strlen(reinterpret_cast(b)); + const auto* ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); +} + +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) +{ + return input_adapter(array, array + N); +} + +// This class only handles inputs of input_buffer_adapter type. +// It's required so that expressions like {ptr, len} can be implicitely casted +// to the correct adapter. +class span_input_adapter +{ + public: + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > + span_input_adapter(CharT b, std::size_t l) + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + span_input_adapter(IteratorType first, IteratorType last) + : ia(input_adapter(first, last)) {} + + contiguous_bytes_input_adapter&& get() + { + return std::move(ia); + } + + private: + contiguous_bytes_input_adapter ia; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include +#include // string +#include // move +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief an floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary string was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + virtual ~json_sax() = default; +}; + + +namespace detail +{ +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @param[in, out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) + : root(r), allow_exceptions(allow_exceptions_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive object size: " + std::to_string(len))); + } + + return true; + } + + bool key(string_t& val) + { + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive array size: " + std::to_string(len))); + } + + return true; + } + + bool end_array() + { + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + + json_sax_dom_callback_parser(BasicJsonType& r, + const parser_callback_t cb, + const bool allow_exceptions_ = true) + : root(r), callback(cb), allow_exceptions(allow_exceptions_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + // check object limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); + } + + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back() && !callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + // check array limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (!keep) + { + // discard array + *ref_stack.back() = discarded; + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, &root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->push_back(std::move(value)); + return {true, &(ref_stack.back()->m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; +} // namespace detail + +} // namespace nlohmann + +// #include + + +#include // array +#include // localeconv +#include // size_t +#include // snprintf +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // char_traits, string +#include // move +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +template +class lexer_base +{ + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + JSON_HEDLEY_RETURNS_NON_NULL + JSON_HEDLEY_CONST + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_unsigned: + case token_type::value_integer: + case token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } +}; +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer : public lexer_base +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + using token_type = typename lexer_base::token_type; + + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer(lexer&&) = default; + lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = default; + ~lexer() = default; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + JSON_ASSERT(current == 'u'); + int codepoint = 0; + + const auto factors = { 12u, 8u, 4u, 0u }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' && current <= '9') + { + codepoint += static_cast((static_cast(current) - 0x30u) << factor); + } + else if (current >= 'A' && current <= 'F') + { + codepoint += static_cast((static_cast(current) - 0x37u) << factor); + } + else if (current >= 'a' && current <= 'f') + { + codepoint += static_cast((static_cast(current) - 0x57u) << factor); + } + else + { + return -1; + } + } + + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + JSON_ASSERT(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = static_cast( + // high surrogate occupies the most significant 22 bits + (static_cast(codepoint1) << 10u) + // low surrogate occupies the least significant 15 bits + + static_cast(codepoint2) + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00u); + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(static_cast(codepoint)); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + + case 0x1F: + { + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case std::char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case std::char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + continue; + } + } + } + + default: + continue; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() // lgtm [cpp/use-of-goto] + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // all other characters are rejected outside scan_number() + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + JSON_HEDLEY_NON_NULL(2) + token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type return_type) + { + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + char_int_type get() + { + ++position.chars_read_total; + ++position.chars_read_current_line; + + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia.get_character(); + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + + if (current == '\n') + { + ++position.lines_read; + position.chars_read_current_line = 0; + } + + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. + */ + void unget() + { + next_unget = true; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + JSON_ASSERT(!token_string.empty()); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(char_int_type c) + { + token_buffer.push_back(static_cast(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr position_t get_position() const noexcept + { + return position; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if (static_cast(c) <= '\x1F') + { + // escape control characters + std::array cs{{}}; + (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); + result += cs.data(); + } + else + { + // add character as is + result.push_back(static_cast(c)); + } + } + + return result; + } + + /// return syntax error message + JSON_HEDLEY_RETURNS_NON_NULL + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + // check if we completely parse the BOM + return get() == 0xBB && get() == 0xBF; + } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + + token_type scan() + { + // initially, skip the BOM + if (position.chars_read_total == 0 && !skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + skip_whitespace(); + + // ignore comments + while (ignore_comments && current == '/') + { + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); + } + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + { + std::array true_literal = {{'t', 'r', 'u', 'e'}}; + return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); + } + case 'f': + { + std::array false_literal = {{'f', 'a', 'l', 's', 'e'}}; + return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); + } + case 'n': + { + std::array null_literal = {{'n', 'u', 'l', 'l'}}; + return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); + } + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + InputAdapterType ia; + + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the start position of the current token + position_t position {}; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char_int_type decimal_point_char = '.'; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // declval +#include // string + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +using null_function_t = decltype(std::declval().null()); + +template +using boolean_function_t = + decltype(std::declval().boolean(std::declval())); + +template +using number_integer_function_t = + decltype(std::declval().number_integer(std::declval())); + +template +using number_unsigned_function_t = + decltype(std::declval().number_unsigned(std::declval())); + +template +using number_float_function_t = decltype(std::declval().number_float( + std::declval(), std::declval())); + +template +using string_function_t = + decltype(std::declval().string(std::declval())); + +template +using binary_function_t = + decltype(std::declval().binary(std::declval())); + +template +using start_object_function_t = + decltype(std::declval().start_object(std::declval())); + +template +using key_function_t = + decltype(std::declval().key(std::declval())); + +template +using end_object_function_t = decltype(std::declval().end_object()); + +template +using start_array_function_t = + decltype(std::declval().start_array(std::declval())); + +template +using end_array_function_t = decltype(std::declval().end_array()); + +template +using parse_error_function_t = decltype(std::declval().parse_error( + std::declval(), std::declval(), + std::declval())); + +template +struct is_sax +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static constexpr bool value = + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value; +}; + +template +struct is_sax_static_asserts +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static_assert(is_detected_exact::value, + "Missing/invalid function: bool null()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_integer(number_integer_t)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool string(string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool binary(binary_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_object(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool key(string_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_object()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_array(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_array()"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool parse_error(std::size_t, const " + "std::string&, const exception&)"); +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore ///< ignore tags +}; + +/*! +@brief determine system byte order + +@return true if and only if system's byte order is little endian + +@note from https://stackoverflow.com/a/1001328/266378 +*/ +static inline bool little_endianess(int num = 1) noexcept +{ + return *reinterpret_cast(&num) == 1; +} + + +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR, MessagePack, and UBJSON values +*/ +template> +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using json_sax_t = SAX; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter)) + { + (void)detail::is_sax_static_asserts {}; + } + + // make class move-only + binary_reader(const binary_reader&) = delete; + binary_reader(binary_reader&&) = default; + binary_reader& operator=(const binary_reader&) = delete; + binary_reader& operator=(binary_reader&&) = default; + ~binary_reader() = default; + + /*! + @param[in] format the binary format to parse + @param[in] sax_ a SAX event processor + @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags + + @return + */ + JSON_HEDLEY_NON_NULL(3) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + sax = sax_; + bool result = false; + + switch (format) + { + case input_format_t::bson: + result = parse_bson_internal(); + break; + + case input_format_t::cbor: + result = parse_cbor_internal(true, tag_handler); + break; + + case input_format_t::msgpack: + result = parse_msgpack_internal(); + break; + + case input_format_t::ubjson: + result = parse_ubjson_internal(); + break; + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + + // strict mode: next byte must be EOF + if (result && strict) + { + if (format == input_format_t::ubjson) + { + get_ignore_noop(); + } + else + { + get(); + } + + if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) + { + return sax->parse_error(chars_read, get_token_string(), + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); + } + } + + return result; + } + + private: + ////////// + // BSON // + ////////// + + /*! + @brief Reads in a BSON-object and passes it to the SAX-parser. + @return whether a valid BSON-value was passed to the SAX parser + */ + bool parse_bson_internal() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) + { + return false; + } + + return sax->end_object(); + } + + /*! + @brief Parses a C-style string from the BSON input. + @param[in, out] result A reference to the string variable where the read + string is to be stored. + @return `true` if the \x00-byte indicating the end of the string was + encountered before the EOF; false` indicates an unexpected EOF. + */ + bool get_bson_cstr(string_t& result) + { + auto out = std::back_inserter(result); + while (true) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + { + return false; + } + if (current == 0x00) + { + return true; + } + *out++ = static_cast(current); + } + } + + /*! + @brief Parses a zero-terminated string of length @a len from the BSON + input. + @param[in] len The length (including the zero-byte at the end) of the + string to be read. + @param[in, out] result A reference to the string variable where the read + string is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 1 + @return `true` if the string was successfully parsed + */ + template + bool get_bson_string(const NumberType len, string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 1)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"))); + } + + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); + } + + /*! + @brief Parses a byte array input of length @a len from the BSON input. + @param[in] len The length of the byte array to be read. + @param[in, out] result A reference to the binary variable where the read + array is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 0 + @return `true` if the byte array was successfully parsed + */ + template + bool get_bson_binary(const NumberType len, binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 0)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); + } + + // All BSON binary values have a subtype + std::uint8_t subtype{}; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); + + return get_binary(input_format_t::bson, len, result); + } + + /*! + @brief Read a BSON document element of the given @a element_type. + @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html + @param[in] element_type_parse_position The position in the input stream, + where the `element_type` was read. + @warning Not all BSON element types are supported yet. An unsupported + @a element_type will give rise to a parse_error.114: + Unsupported BSON record type 0x... + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_internal(const char_int_type element_type, + const std::size_t element_type_parse_position) + { + switch (element_type) + { + case 0x01: // double + { + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + } + + case 0x02: // string + { + std::int32_t len{}; + string_t value; + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + } + + case 0x03: // object + { + return parse_bson_internal(); + } + + case 0x04: // array + { + return parse_bson_array(); + } + + case 0x05: // binary + { + std::int32_t len{}; + binary_t value; + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + } + + case 0x08: // boolean + { + return sax->boolean(get() != 0); + } + + case 0x0A: // null + { + return sax->null(); + } + + case 0x10: // int32 + { + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + case 0x12: // int64 + { + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + default: // anything else not supported (yet) + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); + return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()))); + } + } + } + + /*! + @brief Read a BSON element list (as specified in the BSON-spec) + + The same binary layout is used for objects and arrays, hence it must be + indicated with the argument @a is_array which one is expected + (true --> array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(std::size_t(-1), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(std::size_t(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); + } + + case cbor_tag_handler_t::ignore: + { + switch (current) + { + case 0xD8: + { + std::uint8_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xD9: + { + std::uint16_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDA: + { + std::uint32_t len{}; + get_number(input_format_t::cbor, len); + break; + } + case 0xDB: + { + std::uint64_t len{}; + get_number(input_format_t::cbor, len); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"))); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"))); + } + } + } + + /*! + @param[in] len the length of the array or std::size_t(-1) for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or std::size_t(-1) for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"))); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + default: + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"))); + } + } + + /*! + @param[out] result determined size + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result) + { + switch (get_ignore_noop()) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"))); + } + } + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result) + { + result.first = string_t::npos; // size + result.second = 0; // type + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"))); + } + + return get_ubjson_size_value(result.first); + } + + if (current == '#') + { + return get_ubjson_size_value(result.first); + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case std::char_traits::eof(): // EOF + return unexpect_eof(input_format_t::ubjson, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'd': + { + float number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"))); + } + } + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + string_t key; + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + auto res = get_ubjson_size_value(size); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + auto number_ia = detail::input_adapter(std::forward(number_vector)); + auto number_lexer = detail::lexer(std::move(number_ia), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"))); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianess, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + { + return false; + } + + // reverse byte order prior to conversion if necessary + if (is_little_endian != InputIsLittleEndian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + }; + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + + return error_msg + " " + context + ": " + detail; + } + + private: + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the SAX parser + json_sax_t* sax = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + sax_parse_internal(&sdp); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions); + sax_parse_internal(&sdp); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::uninitialized, "value"))); + } + + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::literal_or_value, "value"))); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_array, "array"))); + } + else // object + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_object, "object"))); + } + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += "while parsing " + context + " "; + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) noexcept + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) noexcept + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // all_of +#include // isdigit +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`.,json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @brief append another JSON pointer at the end of this JSON pointer + + @param[in] ptr JSON pointer to append + @return JSON pointer with @a ptr appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::string) to append a reference token + @sa @ref operator/=(std::size_t) to append an array index + @sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /*! + @brief append an unescaped reference token at the end of this JSON pointer + + @param[in] token reference token to append + @return JSON pointer with @a token appended without escaping @a token + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + @sa @ref operator/=(std::size_t) to append an array index + @sa @ref operator/(const json_pointer&, std::size_t) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::string token) + { + push_back(std::move(token)); + return *this; + } + + /*! + @brief append an array index at the end of this JSON pointer + + @param[in] array_idx array index to append + @return JSON pointer with @a array_idx appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + @sa @ref operator/=(std::string) to append a reference token + @sa @ref operator/(const json_pointer&, std::string) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /*! + @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + + @param[in] lhs JSON pointer + @param[in] rhs JSON pointer + @return a new JSON pointer with @a rhs appended to @a lhs + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a lhs and @a rhs. + + @sa @ref operator/=(const json_pointer&) to append a JSON pointer + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /*! + @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] token reference token + @return a new JSON pointer with unescaped @a token appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::string) to append a reference token + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::string token) + { + return json_pointer(ptr) /= std::move(token); + } + + /*! + @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] array_idx array index + @return a new JSON pointer with @a array_idx appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa @ref operator/=(std::size_t) to append an array index + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx) + { + return json_pointer(ptr) /= array_idx; + } + + /*! + @brief returns the parent of this JSON pointer + + @return parent of this JSON pointer; in case this JSON pointer is the root, + the root itself is returned + + @complexity Linear in the length of the JSON pointer. + + @liveexample{The example shows the result of `parent_pointer` for different + JSON Pointers.,json_pointer__parent_pointer} + + @since version 3.6.0 + */ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /*! + @brief remove last reference token + + @pre not `empty()` + + @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + reference_tokens.pop_back(); + } + + /*! + @brief return last reference token + + @pre not `empty()` + @return last reference token + + @liveexample{The example shows the usage of `back`.,json_pointer__back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + const std::string& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + return reference_tokens.back(); + } + + /*! + @brief append an unescaped token at the end of the reference pointer + + @param[in] token token to add + + @complexity Amortized constant. + + @liveexample{The example shows the result of `push_back` for different + JSON Pointers.,json_pointer__push_back} + + @since version 3.6.0 + */ + void push_back(const std::string& token) + { + reference_tokens.push_back(token); + } + + /// @copydoc push_back(const std::string&) + void push_back(std::string&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /*! + @brief return whether pointer points to the root document + + @return true iff the JSON pointer points to the root document + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example shows the result of `empty` for different JSON + Pointers.,json_pointer__empty} + + @since version 3.6.0 + */ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + static typename BasicJsonType::size_type array_index(const std::string& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + s + + "' must not begin with '0'")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); + } + + std::size_t processed_chars = 0; + unsigned long long res = 0; + JSON_TRY + { + res = std::stoull(s, &processed_chars); + } + JSON_CATCH(std::out_of_range&) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + // check if the string was completely read + if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) + { + JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == std::string::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = (slash == std::string::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + /*! + @brief compares two JSON pointers for equality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is equal to @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return lhs.reference_tokens == rhs.reference_tokens; + } + + /*! + @brief compares two JSON pointers for inequality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is not equal @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return !(lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens; +}; +} // namespace nlohmann + +// #include + + +#include +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)) + , is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + , value_ref(&owned_value) + , is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue = true; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits +#include // string +#include // isnan, isinf + +// #include + +// #include + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) noexcept + : v(vec) + {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) noexcept + : stream(s) + {} + + void write_character(CharType c) override + { + stream.put(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) noexcept + : str(s) + {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + JSON_ASSERT(oa); + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + { + write_bson_object(*j.m_value.object); + break; + } + + default: + { + JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()))); + } + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(to_char_type(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xF5) + : to_char_type(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(to_char_type(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: + { + if (std::isnan(j.m_value.number_float)) + { + // NaN is 0xf97e00 in CBOR + oa->write_character(to_char_type(0xF9)); + oa->write_character(to_char_type(0x7E)); + oa->write_character(to_char_type(0x00)); + } + else if (std::isinf(j.m_value.number_float)) + { + // Infinity is 0xf97c00, -Infinity is 0xf9fc00 + oa->write_character(to_char_type(0xf9)); + oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); + oa->write_character(to_char_type(0x00)); + } + else + { + write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); + } + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::binary: + { + if (j.m_value.binary->has_subtype()) + { + write_number(static_cast(0xd8)); + write_number(j.m_value.binary->subtype()); + } + + // step 1: write control byte and the binary array size + const auto N = j.m_value.binary->size(); + if (N <= 0x17) + { + write_number(static_cast(0x40 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x58)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x59)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(to_char_type(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xC3) + : to_char_type(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(to_char_type(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(to_char_type(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(to_char_type(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(to_char_type(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: + { + write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(to_char_type(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(to_char_type(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(to_char_type(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(to_char_type(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(to_char_type(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::binary: + { + // step 0: determine if the binary type has a set subtype to + // determine whether or not to use the ext or fixext types + const bool use_ext = j.m_value.binary->has_subtype(); + + // step 1: write control byte and the byte string length + const auto N = j.m_value.binary->size(); + if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type{}; + bool fixed = true; + if (use_ext) + { + switch (N) + { + case 1: + output_type = 0xD4; // fixext 1 + break; + case 2: + output_type = 0xD5; // fixext 2 + break; + case 4: + output_type = 0xD6; // fixext 4 + break; + case 8: + output_type = 0xD7; // fixext 8 + break; + case 16: + output_type = 0xD8; // fixext 16 + break; + default: + output_type = 0xC7; // ext 8 + fixed = false; + break; + } + + } + else + { + output_type = 0xC4; // bin 8 + fixed = false; + } + + oa->write_character(to_char_type(output_type)); + if (!fixed) + { + write_number(static_cast(N)); + } + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC8 // ext 16 + : 0xC5; // bin 16 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC9 // ext 32 + : 0xC6; // bin 32 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + + // step 1.5: if this is an ext type, write the subtype + if (use_ext) + { + write_number(static_cast(j.m_value.binary->subtype())); + } + + // step 2: write the byte string + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(to_char_type(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(to_char_type(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true) + { + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(to_char_type('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + { + oa->write_character(j.m_value.boolean + ? to_char_type('T') + : to_char_type('F')); + } + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(to_char_type('S')); + } + write_number_with_ubjson_prefix(j.m_value.string->size(), true); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.array->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.array->size(), true); + } + + for (const auto& el : *j.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::binary: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + if (use_type && !j.m_value.binary->empty()) + { + JSON_ASSERT(use_count); + oa->write_character(to_char_type('$')); + oa->write_character('U'); + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.binary->size(), true); + } + + if (use_type) + { + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + j.m_value.binary->size()); + } + else + { + for (size_t i = 0; i < j.m_value.binary->size(); ++i) + { + oa->write_character(to_char_type('U')); + oa->write_character(j.m_value.binary->data()[i]); + } + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::object: + { + if (add_prefix) + { + oa->write_character(to_char_type('{')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.object->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.object->size(), true); + } + + for (const auto& el : *j.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type('}')); + } + + break; + } + + default: + break; + } + } + + private: + ////////// + // BSON // + ////////// + + /*! + @return The size of a BSON document entry header, including the id marker + and the entry name size (and its null-terminator). + */ + static std::size_t calc_bson_entry_header_size(const string_t& name) + { + const auto it = name.find(static_cast(0)); + if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) + { + JSON_THROW(out_of_range::create(409, + "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")")); + } + + return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; + } + + /*! + @brief Writes the given @a element_type and @a name to the output adapter + */ + void write_bson_entry_header(const string_t& name, + const std::uint8_t element_type) + { + oa->write_character(to_char_type(element_type)); // boolean + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + } + + /*! + @brief Writes a BSON element with key @a name and boolean value @a value + */ + void write_bson_boolean(const string_t& name, + const bool value) + { + write_bson_entry_header(name, 0x08); + oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and double value @a value + */ + void write_bson_double(const string_t& name, + const double value) + { + write_bson_entry_header(name, 0x01); + write_number(value); + } + + /*! + @return The size of the BSON-encoded string in @a value + */ + static std::size_t calc_bson_string_size(const string_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and string value @a value + */ + void write_bson_string(const string_t& name, + const string_t& value) + { + write_bson_entry_header(name, 0x02); + + write_number(static_cast(value.size() + 1ul)); + oa->write_characters( + reinterpret_cast(value.c_str()), + value.size() + 1); + } + + /*! + @brief Writes a BSON element with key @a name and null value + */ + void write_bson_null(const string_t& name) + { + write_bson_entry_header(name, 0x0A); + } + + /*! + @return The size of the BSON-encoded integer @a value + */ + static std::size_t calc_bson_integer_size(const std::int64_t value) + { + return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and integer @a value + */ + void write_bson_integer(const string_t& name, + const std::int64_t value) + { + if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) + { + write_bson_entry_header(name, 0x10); // int32 + write_number(static_cast(value)); + } + else + { + write_bson_entry_header(name, 0x12); // int64 + write_number(static_cast(value)); + } + } + + /*! + @return The size of the BSON-encoded unsigned integer in @a j + */ + static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept + { + return (value <= static_cast((std::numeric_limits::max)())) + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and unsigned @a value + */ + void write_bson_unsigned(const string_t& name, + const std::uint64_t value) + { + if (value <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x10 /* int32 */); + write_number(static_cast(value)); + } + else if (value <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x12 /* int64 */); + write_number(static_cast(value)); + } + else + { + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64")); + } + } + + /*! + @brief Writes a BSON element with key @a name and object @a value + */ + void write_bson_object_entry(const string_t& name, + const typename BasicJsonType::object_t& value) + { + write_bson_entry_header(name, 0x03); // object + write_bson_object(value); + } + + /*! + @return The size of the BSON-encoded array @a value + */ + static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) + { + std::size_t array_index = 0ul; + + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + { + return result + calc_bson_element_size(std::to_string(array_index++), el); + }); + + return sizeof(std::int32_t) + embedded_document_size + 1ul; + } + + /*! + @return The size of the BSON-encoded binary array @a value + */ + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and array @a value + */ + void write_bson_array(const string_t& name, + const typename BasicJsonType::array_t& value) + { + write_bson_entry_header(name, 0x04); // array + write_number(static_cast(calc_bson_array_size(value))); + + std::size_t array_index = 0ul; + + for (const auto& el : value) + { + write_bson_element(std::to_string(array_index++), el); + } + + oa->write_character(to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and binary value @a value + */ + void write_bson_binary(const string_t& name, + const binary_t& value) + { + write_bson_entry_header(name, 0x05); + + write_number(static_cast(value.size())); + write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); + + oa->write_characters(reinterpret_cast(value.data()), value.size()); + } + + /*! + @brief Calculates the size necessary to serialize the JSON value @a j with its @a name + @return The calculated size for the BSON document entry for @a j with the given @a name. + */ + static std::size_t calc_bson_element_size(const string_t& name, + const BasicJsonType& j) + { + const auto header_size = calc_bson_entry_header_size(name); + switch (j.type()) + { + case value_t::object: + return header_size + calc_bson_object_size(*j.m_value.object); + + case value_t::array: + return header_size + calc_bson_array_size(*j.m_value.array); + + case value_t::binary: + return header_size + calc_bson_binary_size(*j.m_value.binary); + + case value_t::boolean: + return header_size + 1ul; + + case value_t::number_float: + return header_size + 8ul; + + case value_t::number_integer: + return header_size + calc_bson_integer_size(j.m_value.number_integer); + + case value_t::number_unsigned: + return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); + + case value_t::string: + return header_size + calc_bson_string_size(*j.m_value.string); + + case value_t::null: + return header_size + 0ul; + + // LCOV_EXCL_START + default: + JSON_ASSERT(false); + return 0ul; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Serializes the JSON value @a j to BSON and associates it with the + key @a name. + @param name The name to associate with the JSON entity @a j within the + current BSON document + @return The size of the BSON entry + */ + void write_bson_element(const string_t& name, + const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + return write_bson_object_entry(name, *j.m_value.object); + + case value_t::array: + return write_bson_array(name, *j.m_value.array); + + case value_t::binary: + return write_bson_binary(name, *j.m_value.binary); + + case value_t::boolean: + return write_bson_boolean(name, j.m_value.boolean); + + case value_t::number_float: + return write_bson_double(name, j.m_value.number_float); + + case value_t::number_integer: + return write_bson_integer(name, j.m_value.number_integer); + + case value_t::number_unsigned: + return write_bson_unsigned(name, j.m_value.number_unsigned); + + case value_t::string: + return write_bson_string(name, *j.m_value.string); + + case value_t::null: + return write_bson_null(name); + + // LCOV_EXCL_START + default: + JSON_ASSERT(false); + return; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Calculates the size of the BSON serialization of the given + JSON-object @a j. + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) + { + std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), + [](size_t result, const typename BasicJsonType::object_t::value_type & el) + { + return result += calc_bson_element_size(el.first, el.second); + }); + + return sizeof(std::int32_t) + document_size + 1ul; + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson_object(const typename BasicJsonType::object_t& value) + { + write_number(static_cast(calc_bson_object_size(value))); + + for (const auto& el : value) + { + write_bson_element(el.first, el.second); + } + + oa->write_character(to_char_type(0x00)); + } + + ////////// + // CBOR // + ////////// + + static constexpr CharType get_cbor_float_prefix(float /*unused*/) + { + return to_char_type(0xFA); // Single-Precision Float + } + + static constexpr CharType get_cbor_float_prefix(double /*unused*/) + { + return to_char_type(0xFB); // Double-Precision Float + } + + ///////////// + // MsgPack // + ///////////// + + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) + { + return to_char_type(0xCA); // float 32 + } + + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) + { + return to_char_type(0xCB); // float 64 + } + + //////////// + // UBJSON // + //////////// + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (add_prefix) + { + oa->write_character(get_ubjson_float_prefix(n)); + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + } + + // UBJSON: write number (signed integer) + template < typename NumberType, typename std::enable_if < + std::is_signed::value&& + !std::is_floating_point::value, int >::type = 0 > + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + */ + CharType ubjson_prefix(const BasicJsonType& j) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'i'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'U'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'I'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'l'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_float: + return get_ubjson_float_prefix(j.m_value.number_float); + + case value_t::string: + return 'S'; + + case value_t::array: // fallthrough + case value_t::binary: + return '['; + + case value_t::object: + return '{'; + + default: // discarded values + return 'N'; + } + } + + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) + { + return 'd'; // float 32 + } + + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) + { + return 'D'; // float 64 + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /* + @brief write a number to output input + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + @tparam OutputIsLittleEndian Set to true if output data is + required to be little endian + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(const NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian != OutputIsLittleEndian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + void write_compact_float(const number_float_t n, detail::input_format_t format) + { + if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && + static_cast(n) <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(n)) == static_cast(n)) + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(static_cast(n)) + : get_msgpack_float_prefix(static_cast(n))); + write_number(static_cast(n)); + } + else + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(n) + : get_msgpack_float_prefix(n)); + write_number(n); + } + } + + public: + // The following to_char_type functions are implement the conversion + // between uint8_t and CharType. In case CharType is not unsigned, + // such a conversion is required to allow values greater than 128. + // See for a discussion. + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return *reinterpret_cast(&x); + } + + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > + static CharType to_char_type(std::uint8_t x) noexcept + { + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); + static_assert(std::is_trivial::value, "CharType must be trivial"); + CharType result; + std::memcpy(&result, &x, sizeof(x)); + return result; + } + + template::value>* = nullptr> + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return x; + } + + template < typename InputCharType, typename C = CharType, + enable_if_t < + std::is_signed::value && + std::is_signed::value && + std::is_same::type>::value + > * = nullptr > + static constexpr CharType to_char_type(InputCharType x) noexcept + { + return x; + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // numeric_limits +#include // string, char_traits +#include // is_same +#include // move + +// #include + + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const std::uint64_t bits = reinterpret_bits(value); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + else if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + else if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + else if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + else if (n >= 100000) + { + pow10 = 100000; + return 6; + } + else if (n >= 10000) + { + pow10 = 10000; + return 5; + } + else if (n >= 1000) + { + pow10 = 1000; + return 4; + } + else if (n >= 100) + { + pow10 = 100; + return 3; + } + else if (n >= 10) + { + pow10 = 10; + return 2; + } + else + { + pow10 = 1; + return 1; + } +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +/// how to treat decoding errors +enum class error_handler_t +{ + strict, ///< throw a type_error exception in case of invalid UTF-8 + replace, ///< replace invalid UTF-8 sequences with U+FFFD + ignore ///< ignore invalid UTF-8 sequences +}; + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; + static constexpr std::uint8_t UTF8_ACCEPT = 0; + static constexpr std::uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + @param[in] error_handler_ how to react on decoding errors + */ + serializer(output_adapter_t s, const char ichar, + error_handler_t error_handler_ = error_handler_t::strict) + : o(std::move(s)) + , loc(std::localeconv()) + , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) + , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) + , indent_char(ichar) + , indent_string(512, indent_char) + , error_handler(error_handler_) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + - binary values are serialized as objects containing the subtype and the + byte array + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, + const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::binary: + { + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_characters("{\"bytes\":[", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\"subtype\":", 12); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } + } + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + + private: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + std::uint32_t codepoint; + std::uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + // number of bytes written at the point of the last valid byte + std::size_t bytes_after_last_accept = 0; + std::size_t undumped_chars = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint)); + bytes += 6; + } + else + { + (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + // remember the byte position of this accept + bytes_after_last_accept = bytes; + undumped_chars = 0; + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(3, '\0'); + (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn)); + } + + case error_handler_t::ignore: + case error_handler_t::replace: + { + // in case we saw this character the first time, we + // would like to read it again, because the byte + // may be OK for itself, but just not OK for the + // previous sequence + if (undumped_chars > 0) + { + --i; + } + + // reset length buffer to the last accepted index; + // thus removing/ignoring the invalid characters + bytes = bytes_after_last_accept; + + if (error_handler == error_handler_t::replace) + { + // add a replacement character + if (ensure_ascii) + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'u'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'd'; + } + else + { + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + bytes_after_last_accept = bytes; + } + + undumped_chars = 0; + + // continue processing the string + state = UTF8_ACCEPT; + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + break; + } + + default: // decode found yet incomplete multi-byte code point + { + if (!ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + ++undumped_chars; + break; + } + } + } + + // we finished processing the string + if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(3, '\0'); + (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); + } + + case error_handler_t::ignore: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + break; + } + + case error_handler_t::replace: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + // add a replacement character + if (ensure_ascii) + { + o->write_characters("\\ufffd", 6); + } + else + { + o->write_characters("\xEF\xBF\xBD", 3); + } + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + } + } + + /*! + @brief count digits + + Count the number of decimal (base 10) digits for an input unsigned integer. + + @param[in] x unsigned integer number to count its digits + @return number of decimal digits + */ + inline unsigned int count_digits(number_unsigned_t x) noexcept + { + unsigned int n_digits = 1; + for (;;) + { + if (x < 10) + { + return n_digits; + } + if (x < 100) + { + return n_digits + 1; + } + if (x < 1000) + { + return n_digits + 2; + } + if (x < 10000) + { + return n_digits + 3; + } + x = x / 10000u; + n_digits += 4; + } + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template < typename NumberType, detail::enable_if_t < + std::is_same::value || + std::is_same::value || + std::is_same::value, + int > = 0 > + void dump_integer(NumberType x) + { + static constexpr std::array, 100> digits_to_99 + { + { + {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, + {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, + {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, + {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, + {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, + {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, + {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, + {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, + {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, + {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, + } + }; + + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + // use a pointer to fill the buffer + auto buffer_ptr = number_buffer.begin(); + + const bool is_negative = std::is_same::value && !(x >= 0); // see issue #755 + number_unsigned_t abs_value; + + unsigned int n_chars; + + if (is_negative) + { + *buffer_ptr = '-'; + abs_value = remove_sign(static_cast(x)); + + // account one more byte for the minus sign + n_chars = 1 + count_digits(abs_value); + } + else + { + abs_value = static_cast(x); + n_chars = count_digits(abs_value); + } + + // spare 1 byte for '\0' + JSON_ASSERT(n_chars < number_buffer.size() - 1); + + // jump to the end to generate the string from backward + // so we later avoid reversing the result + buffer_ptr += n_chars; + + // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu + // See: https://www.youtube.com/watch?v=o4-CwDo2zpg + while (abs_value >= 100) + { + const auto digits_index = static_cast((abs_value % 100)); + abs_value /= 100; + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + + if (abs_value >= 10) + { + const auto digits_index = static_cast(abs_value); + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + else + { + *(--buffer_ptr) = static_cast('0' + abs_value); + } + + o->write_characters(number_buffer.data(), n_chars); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (!std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || + (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + char* begin = number_buffer.data(); + char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + JSON_ASSERT(len > 0); + // check if buffer was large enough + JSON_ASSERT(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + JSON_ASSERT((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' && decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return c == '.' || c == 'e'; + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const std::uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6u) + : (0xFFu >> type) & (byte); + + std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); + JSON_ASSERT(index < 400); + state = utf8d[index]; + return state; + } + + /* + * Overload to make the compiler happy while it is instantiating + * dump_integer for number_unsigned_t. + * Must never be called. + */ + number_unsigned_t remove_sign(number_unsigned_t x) + { + JSON_ASSERT(false); // LCOV_EXCL_LINE + return x; // LCOV_EXCL_LINE + } + + /* + * Helper function for dump_integer + * + * This function takes a negative signed integer and returns its absolute + * value as unsigned integer. The plus/minus shuffling is necessary as we can + * not directly remove the sign of an arbitrary signed integer as the + * absolute values of INT_MIN and INT_MAX are usually not the same. See + * #1708 for details. + */ + inline number_unsigned_t remove_sign(number_integer_t x) noexcept + { + JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); + return static_cast(-(x + 1)) + 1; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; + + /// error_handler how to react on decoding errors + const error_handler_t error_handler; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // less +#include // allocator +#include // pair +#include // vector + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template , + class Allocator = std::allocator>> + struct ordered_map : std::vector, Allocator> +{ + using key_type = Key; + using mapped_type = T; + using Container = std::vector, Allocator>; + using typename Container::iterator; + using typename Container::const_iterator; + using typename Container::size_type; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} + + std::pair emplace(const key_type& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + Container::emplace_back(key, t); + return {--this->end(), true}; + } + + T& operator[](const Key& key) + { + return emplace(key, T{}).first->second; + } + + const T& operator[](const Key& key) const + { + return at(key); + } + + T& at(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + throw std::out_of_range("key not found"); + } + + const T& at(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + throw std::out_of_range("key not found"); + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + iterator erase(iterator pos) + { + auto it = pos; + + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return pos; + } + + size_type count(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return 1; + } + } + return 0; + } + + iterator find(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + std::pair insert( value_type&& value ) + { + return emplace(value.first, std::move(value.second)); + } + + std::pair insert( const value_type& value ) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == value.first) + { + return {it, false}; + } + } + Container::push_back(value); + return {--this->end(), true}; + } +}; + +} // namespace nlohmann + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam BinaryType type for packed binary data for compatibility with binary +serialization formats (`std::vector` by default; will be used in +@ref binary_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType): + JSON values have + [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](https://en.cppreference.com/w/cpp/named_req/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from https://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + + template + friend class ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + template + friend class ::nlohmann::detail::json_sax_dom_parser; + template + friend class ::nlohmann::detail::json_sax_dom_callback_parser; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer_base; + + template + static ::nlohmann::detail::parser parser( + InputAdapterType adapter, + detail::parser_callback_tcb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false + ) + { + return ::nlohmann::detail::parser(std::move(adapter), + std::move(cb), allow_exceptions, ignore_comments); + } + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + template + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// JSON Pointer, see @ref nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// how to treat decoding errors + using error_handler_t = detail::error_handler_t; + /// how to treat CBOR tags + using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + using input_format_t = detail::input_format_t; + /// SAX interface type, see @ref nlohmann::json_sax + using json_sax_t = json_sax; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2020 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_PATCH); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, it is unspecified which + one of the values for a given key will be chosen. For instance, + `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or + `{"key": 2}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /*! + @brief a type for a packed binary type + + This type is a type designed to carry binary data that appears in various + serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and + BSON's generic binary subtype. This type is NOT a part of standard JSON and + exists solely for compatibility with these binary types. As such, it is + simply defined as an ordered sequence of zero or more byte values. + + Additionally, as an implementation detail, the subtype of the binary data is + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). + + [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type + as: + > Major type 2: a byte string. The string's length in bytes is represented + > following the rules for positive integers (major type 0). + + [MessagePack's documentation on the bin type + family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) + describes this type as: + > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes + > in addition to the size of the byte array. + + [BSON's specifications](http://bsonspec.org/spec.html) describe several + binary types; however, this type is intended to represent the generic binary + type which has the description: + > Generic binary subtype - This is the most commonly used binary subtype and + > should be the 'default' for drivers and tools. + + None of these impose any limitations on the internal representation other + than the basic unit of storage be some type of array whose parts are + decomposable into bytes. + + The default representation of this binary format is a + `std::vector`, which is a very common way to represent a byte + array in modern C++. + + #### Default type + + The default values for @a BinaryType is `std::vector` + + #### Storage + + Binary Arrays are stored as pointers in a @ref basic_json type. That is, + for any access to array values, a pointer of the type `binary_t*` must be + dereferenced. + + #### Notes on subtypes + + - CBOR + - Binary values are represented as byte strings. No subtypes are + supported and will be ignored when CBOR is written. + - MessagePack + - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, + or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) + is used. For other sizes, the ext family (ext8, ext16, ext32) is used. + The subtype is then added as singed 8-bit integer. + - If no subtype is given, the bin family (bin8, bin16, bin32) is used. + - BSON + - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If no subtype is given, the generic binary subtype 0x00 is used. + + @sa @ref binary -- create a binary array + + @since version 3.8.0 + */ + using binary_t = nlohmann::byte_container_with_subtype; + /// @} + + private: + + /// helper for exception-safe object creation + template + JSON_HEDLEY_RETURNS_NON_NULL + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + JSON_ASSERT(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + binary | binary | pointer to @ref binary_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// binary (stored with pointer to save storage) + binary_t* binary; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::binary: + { + binary = create(); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + /// constructor for binary arrays + json_value(const typename binary_t::container_type& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays + json_value(typename binary_t::container_type&& value) + { + binary = create(std::move(value)); + } + + /// constructor for binary arrays (internal type) + json_value(const binary_t& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays (internal type) + json_value(binary_t&& value) + { + binary = create(std::move(value)); + } + + void destroy(value_t t) noexcept + { + // flatten the current json_value to a heap-allocated stack + std::vector stack; + + // move the top-level items to stack + if (t == value_t::array) + { + stack.reserve(array->size()); + std::move(array->begin(), array->end(), std::back_inserter(stack)); + } + else if (t == value_t::object) + { + stack.reserve(object->size()); + for (auto&& it : *object) + { + stack.push_back(std::move(it.second)); + } + } + + while (!stack.empty()) + { + // move the last item to local variable to be processed + basic_json current_item(std::move(stack.back())); + stack.pop_back(); + + // if current_item is array/object, move + // its children to the stack to be processed later + if (current_item.is_array()) + { + std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), + std::back_inserter(stack)); + + current_item.m_value.array->clear(); + } + else if (current_item.is_object()) + { + for (auto&& it : *current_item.m_value.object) + { + stack.push_back(std::move(it.second)); + } + + current_item.m_value.object->clear(); + } + + // it's now safe that current_item get destructed + // since it doesn't have any children + } + + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + case value_t::binary: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const noexcept + { + JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); + JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); + JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); + JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = detail::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = detail::parser_callback_t; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + binary | empty array + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + - **binary**: @ref binary_t / `std::vector` may be used, + unfortunately because string literals cannot be distinguished from binary + character arrays by the C++ type system, all types compatible with `const + char*` will be directed to the string constructor instead. This is both + for backwards compatibility, and due to the fact that a binary type is not + a standard JSON type. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template < typename CompatibleType, + typename U = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + basic_json(CompatibleType && val) noexcept(noexcept( + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value&& !std::is_same::value, int > = 0 > + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + using other_binary_t = typename BasicJsonType::binary_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::binary: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); + }); + + // adjust type if type deduction is not wanted + if (!type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create a binary array (without subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = init; + return res; + } + + /*! + @brief explicitly create a binary array (with subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + @param[in] subtype subtype to use in MessagePack and BSON + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(init, subtype); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = std::move(init); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(std::move(init), subtype); + return res; + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See https://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template < class InputIT, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type = 0 > + basic_json(InputIT first, InputIT last) + { + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::binary: + { + m_value = *first.m_object->m_value.binary; + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + template, + std::is_same>::value, int> = 0 > + basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + case value_t::binary: + { + m_value = *other.m_value.binary; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + basic_json& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() noexcept + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] error_handler how to react on decoding errors; there are three + possible values: `strict` (throws and exception in case a decoding error + occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded and @a error_handler is set to strict + + @note Binary values are serialized as object containing two keys: + - "bytes": an array of bytes as integers + - "subtype": the subtype as integer or "null" if the binary has no subtype + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0; error + handlers added in version 3.4.0; serialization of binary values added + in version 3.8.0. + */ + string_t dump(const int indent = -1, + const char indent_char = ' ', + const bool ensure_ascii = false, + const error_handler_t error_handler = error_handler_t::strict) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char, error_handler); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + binary | value_t::binary + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + @sa @ref is_binary() -- returns whether JSON value is a binary array + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() || is_string() || is_boolean() || is_number() || is_binary(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() || is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() || is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer || m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is a binary array + + This function returns true if and only if the JSON value is a binary array. + + @return `true` if type is binary array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_binary()` for all JSON + types.,is_binary} + + @since version 3.8.0 + */ + constexpr bool is_binary() const noexcept + { + return m_type == value_t::binary; + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_HEDLEY_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (binary) + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /// get a pointer to the value (binary) + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_HEDLEY_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.2.0 + */ + template < typename BasicJsonType, detail::enable_if_t < + !std::is_same::value&& + detail::is_basic_json::value, int > = 0 > + BasicJsonType get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && + detail::has_from_json::value && + !detail::has_non_default_from_json::value, + int > = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t, + detail::enable_if_t < !std::is_same::value && + detail::has_non_default_from_json::value, + int > = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer::from_json(*this, v); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + + @tparam ValueType the input parameter type. + + @return the input parameter, allowing chaining calls. + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get_to} + + @since version 3.3.0 + */ + template < typename ValueType, + detail::enable_if_t < + !detail::is_basic_json::value&& + detail::has_from_json::value, + int > = 0 > + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + // specialization to allow to call get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + + template < + typename T, std::size_t N, + typename Array = T (&)[N], + detail::enable_if_t < + detail::has_from_json::value, int > = 0 > + Array get_to(T (&v)[N]) const + noexcept(noexcept(JSONSerializer::from_json( + std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template < typename PointerType, typename std::enable_if < + std::is_pointer::value&& + std::is_const::type>::value, int >::type = 0 > + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template < typename ReferenceType, typename std::enable_if < + std::is_reference::value&& + std::is_const::type>::value, int >::type = 0 > + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + !std::is_pointer::value&& + !std::is_same>::value&& + !std::is_same::value&& + !detail::is_basic_json::value + && !std::is_same>::value +#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) + && !std::is_same::value +#endif + && detail::is_detected::value + , int >::type = 0 > + JSON_EXPLICIT operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /*! + @return reference to the binary value + + @throw type_error.302 if the value is not binary + + @sa @ref is_binary() to check if the value is binary + + @since version 3.8.0 + */ + binary_t& get_binary() + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @copydoc get_binary() + const binary_t& get_binary() const + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); + } + + return *get_ptr(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a key + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + // using std::is_convertible in a std::enable_if will fail when using explicit conversions + template < class ValueType, typename std::enable_if < + detail::is_getable::value + && !std::is_same::value, int >::type = 0 > + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return it->template get(); + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a ptr + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this).template get(); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + JSON_HEDLEY_NON_NULL(3) + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + if (JSON_HEDLEY_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @sa @ref contains(KeyT&&) const -- checks whether a key exists + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /*! + @brief check the existence of an element in a JSON object + + Check whether an element exists in a JSON object with key equivalent to + @a key. If the element is not found or the JSON value is not an object, + false is returned. + + @note This method always returns false when executed on a JSON type + that is not an object. + + @param[in] key key value to check its existence. + + @return true if an element with specified @a key exists. If no such + element with such key is found or the JSON value is not an object, + false is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains} + + @sa @ref find(KeyT&&) -- returns an iterator to an object element + @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer + + @since version 3.6.0 + */ + template < typename KeyT, typename std::enable_if < + !std::is_same::type, json_pointer>::value, int >::type = 0 > + bool contains(KeyT && key) const + { + return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); + } + + /*! + @brief check the existence of an element in a JSON object given a JSON pointer + + Check whether the given JSON pointer @a ptr can be resolved in the current + JSON value. + + @note This method can be executed on any JSON value type. + + @param[in] ptr JSON pointer to check its existence. + + @return true if the JSON pointer can be resolved to a stored value, false + otherwise. + + @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} + + @sa @ref contains(KeyT &&) const -- checks the existence of a key + + @since version 3.7.0 + */ + bool contains(const json_pointer& ptr) const + { + return ptr.contains(this); + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto& el : j_object.items()) + { + std::cout << "key: " << el.key() << ", value:" << el.value() << '\n'; + } + @endcode + + The `items()` function also allows to use + [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding) + (C++17): + + @code{cpp} + for (auto& [key, val] : j_object.items()) + { + std::cout << "key: " << key << ", value:" << val << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @warning Using `items()` on temporary objects is dangerous. Make sure the + object's lifetime exeeds the iteration. See + for more + information. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.1.0, structured bindings support since 3.5.0. + */ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + binary | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + binary | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + binary | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + binary | An empty byte vector + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::binary: + { + m_value.binary->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // if val is moved from, basic_json move constructor marks it null so we do not call the destructor + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() && init.size() == 2 && (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return reference to the inserted element + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8, returns reference since 3.7.0 + */ + template + reference emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) +#ifdef JSON_HAS_CPP_17 + return m_value.array->emplace_back(std::forward(args)...); +#else + m_value.array->emplace_back(std::forward(args)...); + return m_value.array->back(); +#endif + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + JSON_ASSERT(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, cnt, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + return insert_iterator(pos, ilist.begin(), ilist.end()); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object() + || !last.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value from @a left with those of @a right. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. implemented as a friend function callable via ADL. + + @param[in,out] left JSON value to exchange the contents with + @param[in,out] right JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other binary to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__binary_t} + + @since version 3.8.0 + */ + void swap(binary_t& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @copydoc swap(binary_t) + void swap(typename binary_t::container_type& other) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note that two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + Or you can self-defined operator equal function like this: + @code {.cpp} + bool my_equal(const_reference lhs, const_reference rhs) { + const auto lhs_type lhs.type(); + const auto rhs_type rhs.type(); + if (lhs_type == rhs_type) { + switch(lhs_type) + // self_defined case + case value_t::number_float: + return std::abs(lhs - rhs) <= std::numeric_limits::epsilon(); + // other cases remain the same with the original + ... + } + ... + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return *lhs.m_value.array == *rhs.m_value.array; + + case value_t::object: + return *lhs.m_value.object == *rhs.m_value.object; + + case value_t::null: + return true; + + case value_t::string: + return *lhs.m_value.string == *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean == rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer == rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float == rhs.m_value.number_float; + + case value_t::binary: + return *lhs.m_value.binary == *rhs.m_value.binary; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs == basic_json(rhs); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) == rhs; + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs != basic_json(rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) != rhs; + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + // note parentheses are necessary, see + // https://github.com/nlohmann/json/issues/1530 + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object) < (*rhs.m_value.object); + + case value_t::null: + return false; + + case value_t::string: + return (*lhs.m_value.string) < (*rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean) < (rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer) < (rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float) < (rhs.m_value.number_float); + + case value_t::binary: + return (*lhs.m_value.binary) < (*rhs.m_value.binary); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs < basic_json(rhs); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) < rhs; + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return !(rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs <= basic_json(rhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) <= rhs; + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs > basic_json(rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) > rhs; + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return lhs >= basic_json(rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) >= rhs; + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = o.width() > 0; + const auto indentation = pretty_print ? o.width() : 0; + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb or reading from the input @a i has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to + ignore comments. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(InputType&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + + @param[in] first iterator to start of character range + @param[in] last iterator to end of character range + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType first, + IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) + static basic_json parse(detail::span_input_adapter&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief check if the input is valid JSON + + Unlike the @ref parse(InputType&&, const parser_callback_t,const bool) + function, this function neither throws an exception in case of invalid JSON + input (i.e., a parse error) nor creates diagnostic information. + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return Whether the input read from @a i is valid JSON. + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `accept()` function reading + from a string.,accept__string} + */ + template + static bool accept(InputType&& i, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + } + + template + static bool accept(IteratorType first, IteratorType last, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + static bool accept(detail::span_input_adapter&& i, + const bool ignore_comments = false) + { + return parser(i.get(), nullptr, false, ignore_comments).accept(true); + } + + /*! + @brief generate SAX events + + The SAX event lister must follow the interface of @ref json_sax. + + This function reads from a compatible input. Examples are: + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in,out] sax SAX event listener + @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON) + @param[in] strict whether the input has to be consumed completely + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default); only applies to the JSON file format. + + @return return value of the last processed SAX event + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the SAX consumer @a sax has + a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `sax_parse()` function + reading from string and processing the events with a user-defined SAX + event consumer.,sax_parse} + + @since version 3.2.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(InputType&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::forward(i)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = i.get(); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + binary | `"binary"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + JSON_HEDLEY_RETURNS_NON_NULL + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::binary: + return "binary"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value representable by a float* | Single-Precision Float | 0xFA + number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + binary | *size*: 0..23 | byte string | 0x40..0x57 + binary | *size*: 23..255 | byte string (1 byte follow) | 0x58 + binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59 + binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A + binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - byte strings terminated by "break" (0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half-precision floats (0xF9) + - break (0xFF) + + @param[in] j JSON value to serialize + @return CBOR serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; compact representation of floating-point numbers + since version 3.8.0 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value representable by a float* | float 32 | 0xCA + number_float | *any value NOT representable by a float* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + binary | *size*: 0..255 | bin 8 | 0xC4 + binary | *size*: 256..65535 | bin 16 | 0xC5 + binary | *size*: 65536..4294967295 | bin 32 | 0xC6 + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - byte strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack for the analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @note If the JSON data contains the binary type, the value stored is a list + of integers, as suggested by the UBJSON documentation. In particular, + this means that serialization and the deserialization of a JSON + containing binary values into UBJSON and back will result in a + different JSON object. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + + /*! + @brief Serializes the given JSON object `j` to BSON and returns a vector + containing the corresponding BSON-representation. + + BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are + stored as a single entity (a so-called document). + + The library uses the following mapping from JSON values types to BSON types: + + JSON value type | value/range | BSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | 0x0A + boolean | `true`, `false` | boolean | 0x08 + number_integer | -9223372036854775808..-2147483649 | int64 | 0x12 + number_integer | -2147483648..2147483647 | int32 | 0x10 + number_integer | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 0..2147483647 | int32 | 0x10 + number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 9223372036854775808..18446744073709551615| -- | -- + number_float | *any value* | double | 0x01 + string | *any value* | string | 0x02 + array | *any value* | document | 0x04 + object | *any value* | document | 0x03 + binary | *any value* | binary | 0x05 + + @warning The mapping is **incomplete**, since only JSON-objects (and things + contained therein) can be serialized to BSON. + Also, integers larger than 9223372036854775807 cannot be serialized to BSON, + and the keys may not contain U+0000, since they are serialized a + zero-terminated c-strings. + + @throw out_of_range.407 if `j.is_number_unsigned() && j.get() > 9223372036854775807` + @throw out_of_range.409 if a key in `j` contains a NULL (U+0000) + @throw type_error.317 if `!j.is_object()` + + @pre The input `j` is required to be an object: `j.is_object() == true`. + + @note Any BSON output created via @ref to_bson can be successfully parsed + by @ref from_bson. + + @param[in] j JSON value to serialize + @return BSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in BSON format.,to_bson} + + @sa http://bsonspec.org/spec.html + @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the + analogous deserialization + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + @sa @ref to_cbor(const basic_json&) for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + */ + static std::vector to_bson(const basic_json& j) + { + std::vector result; + to_bson(j, result); + return result; + } + + /*! + @brief Serializes the given JSON object `j` to BSON and forwards the + corresponding BSON-representation to the given output_adapter `o`. + @param j The JSON object to convert to BSON. + @param o The output adapter that receives the binary BSON representation. + @pre The input `j` shall be an object: `j.is_object() == true` + @sa @ref to_bson(const basic_json&) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + /*! + @copydoc to_bson(const basic_json&, detail::output_adapter) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Byte string | binary | 0x40..0x57 + Byte string | binary | 0x58 + Byte string | binary | 0x59 + Byte string | binary | 0x5A + Byte string | binary | 0x5B + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Null | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] tag_handler how to treat CBOR tags (optional, error by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0; added @a tag_handler parameter since 3.9.0. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); + } + + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + bin 8 | binary | 0xC4 + bin 16 | binary | 0xC5 + bin 32 | binary | 0xC6 + ext 8 | binary | 0xC7 + ext 16 | binary | 0xC8 + ext 32 | binary | 0xC9 + fixext 1 | binary | 0xD4 + fixext 2 | binary | 0xD5 + fixext 4 | binary | 0xD6 + fixext 8 | binary | 0xD7 + fixext 16 | binary | 0xD8 + negative fixint | number_integer | 0xE0-0xFF + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for + the related UBJSON format + @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for + the related BSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H' + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for + the related MessagePack format + @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for + the related BSON format + + @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief Create a JSON value from an input in BSON format + + Deserializes a given input @a i to a JSON value using the BSON (Binary JSON) + serialization format. + + The library maps BSON record types to JSON value types as follows: + + BSON type | BSON marker byte | JSON value type + --------------- | ---------------- | --------------------------- + double | 0x01 | number_float + string | 0x02 | string + document | 0x03 | object + array | 0x04 | array + binary | 0x05 | still unsupported + undefined | 0x06 | still unsupported + ObjectId | 0x07 | still unsupported + boolean | 0x08 | boolean + UTC Date-Time | 0x09 | still unsupported + null | 0x0A | null + Regular Expr. | 0x0B | still unsupported + DB Pointer | 0x0C | still unsupported + JavaScript Code | 0x0D | still unsupported + Symbol | 0x0E | still unsupported + JavaScript Code | 0x0F | still unsupported + int32 | 0x10 | number_integer + Timestamp | 0x11 | still unsupported + 128-bit decimal float | 0x13 | still unsupported + Max Key | 0x7F | still unsupported + Min Key | 0xFF | still unsupported + + @warning The mapping is **incomplete**. The unsupported mappings + are indicated in the table above. + + @param[in] i an input in BSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.114 if an unsupported BSON record type is encountered + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + BSON format to a JSON value.,from_bson} + + @sa http://bsonspec.org/spec.html + @sa @ref to_bson(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for + the related MessagePack format + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the + related UBJSON format + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_bson(detail::input_adapter&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.empty()) + { + result = val; + return; + } + + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + break; + } + + // if there exists a parent it cannot be primitive + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_HEDLEY_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(json_pointer::array_index(last_path)); + } + }; + + // type check: top level value must be an array + if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_HEDLEY_UNLIKELY(!val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const auto from_path = get_value("move", "from", true).template get(); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const auto from_path = get_value("copy", "from", true).template get(); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_HEDLEY_UNLIKELY(!success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + default: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + return result; + } + + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() && i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/-"}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + + return result; + } + + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] apply_patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ + void merge_patch(const basic_json& apply_patch) + { + if (apply_patch.is_object()) + { + if (!is_object()) + { + *this = object(); + } + for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = apply_patch; + } + } + + /// @} +}; + +/*! +@brief user-defined to_string function for JSON values + +This function implements a user-defined to_string for JSON objects. + +@param[in] j a JSON object +@return a std::string object +*/ + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) +{ + return j.dump(); +} +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + return nlohmann::detail::hash(j); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less<::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value&& + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +#endif + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT + +// #include +#undef JSON_HEDLEY_ALWAYS_INLINE +#undef JSON_HEDLEY_ARM_VERSION +#undef JSON_HEDLEY_ARM_VERSION_CHECK +#undef JSON_HEDLEY_ARRAY_PARAM +#undef JSON_HEDLEY_ASSUME +#undef JSON_HEDLEY_BEGIN_C_DECLS +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#undef JSON_HEDLEY_CLANG_HAS_FEATURE +#undef JSON_HEDLEY_CLANG_HAS_WARNING +#undef JSON_HEDLEY_COMPCERT_VERSION +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#undef JSON_HEDLEY_CONCAT +#undef JSON_HEDLEY_CONCAT3 +#undef JSON_HEDLEY_CONCAT3_EX +#undef JSON_HEDLEY_CONCAT_EX +#undef JSON_HEDLEY_CONST +#undef JSON_HEDLEY_CONSTEXPR +#undef JSON_HEDLEY_CONST_CAST +#undef JSON_HEDLEY_CPP_CAST +#undef JSON_HEDLEY_CRAY_VERSION +#undef JSON_HEDLEY_CRAY_VERSION_CHECK +#undef JSON_HEDLEY_C_DECL +#undef JSON_HEDLEY_DEPRECATED +#undef JSON_HEDLEY_DEPRECATED_FOR +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef JSON_HEDLEY_DIAGNOSTIC_POP +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#undef JSON_HEDLEY_DMC_VERSION +#undef JSON_HEDLEY_DMC_VERSION_CHECK +#undef JSON_HEDLEY_EMPTY_BASES +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef JSON_HEDLEY_END_C_DECLS +#undef JSON_HEDLEY_FLAGS +#undef JSON_HEDLEY_FLAGS_CAST +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_BUILTIN +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_EXTENSION +#undef JSON_HEDLEY_GCC_HAS_FEATURE +#undef JSON_HEDLEY_GCC_HAS_WARNING +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef JSON_HEDLEY_GCC_VERSION +#undef JSON_HEDLEY_GCC_VERSION_CHECK +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#undef JSON_HEDLEY_GNUC_HAS_FEATURE +#undef JSON_HEDLEY_GNUC_HAS_WARNING +#undef JSON_HEDLEY_GNUC_VERSION +#undef JSON_HEDLEY_GNUC_VERSION_CHECK +#undef JSON_HEDLEY_HAS_ATTRIBUTE +#undef JSON_HEDLEY_HAS_BUILTIN +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_HAS_EXTENSION +#undef JSON_HEDLEY_HAS_FEATURE +#undef JSON_HEDLEY_HAS_WARNING +#undef JSON_HEDLEY_IAR_VERSION +#undef JSON_HEDLEY_IAR_VERSION_CHECK +#undef JSON_HEDLEY_IBM_VERSION +#undef JSON_HEDLEY_IBM_VERSION_CHECK +#undef JSON_HEDLEY_IMPORT +#undef JSON_HEDLEY_INLINE +#undef JSON_HEDLEY_INTEL_VERSION +#undef JSON_HEDLEY_INTEL_VERSION_CHECK +#undef JSON_HEDLEY_IS_CONSTANT +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#undef JSON_HEDLEY_LIKELY +#undef JSON_HEDLEY_MALLOC +#undef JSON_HEDLEY_MESSAGE +#undef JSON_HEDLEY_MSVC_VERSION +#undef JSON_HEDLEY_MSVC_VERSION_CHECK +#undef JSON_HEDLEY_NEVER_INLINE +#undef JSON_HEDLEY_NON_NULL +#undef JSON_HEDLEY_NO_ESCAPE +#undef JSON_HEDLEY_NO_RETURN +#undef JSON_HEDLEY_NO_THROW +#undef JSON_HEDLEY_NULL +#undef JSON_HEDLEY_PELLES_VERSION +#undef JSON_HEDLEY_PELLES_VERSION_CHECK +#undef JSON_HEDLEY_PGI_VERSION +#undef JSON_HEDLEY_PGI_VERSION_CHECK +#undef JSON_HEDLEY_PREDICT +#undef JSON_HEDLEY_PRINTF_FORMAT +#undef JSON_HEDLEY_PRIVATE +#undef JSON_HEDLEY_PUBLIC +#undef JSON_HEDLEY_PURE +#undef JSON_HEDLEY_REINTERPRET_CAST +#undef JSON_HEDLEY_REQUIRE +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#undef JSON_HEDLEY_REQUIRE_MSG +#undef JSON_HEDLEY_RESTRICT +#undef JSON_HEDLEY_RETURNS_NON_NULL +#undef JSON_HEDLEY_SENTINEL +#undef JSON_HEDLEY_STATIC_ASSERT +#undef JSON_HEDLEY_STATIC_CAST +#undef JSON_HEDLEY_STRINGIFY +#undef JSON_HEDLEY_STRINGIFY_EX +#undef JSON_HEDLEY_SUNPRO_VERSION +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#undef JSON_HEDLEY_TINYC_VERSION +#undef JSON_HEDLEY_TINYC_VERSION_CHECK +#undef JSON_HEDLEY_TI_ARMCL_VERSION +#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL2000_VERSION +#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL430_VERSION +#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL6X_VERSION +#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL7X_VERSION +#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CLPRU_VERSION +#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#undef JSON_HEDLEY_TI_VERSION +#undef JSON_HEDLEY_TI_VERSION_CHECK +#undef JSON_HEDLEY_UNAVAILABLE +#undef JSON_HEDLEY_UNLIKELY +#undef JSON_HEDLEY_UNPREDICTABLE +#undef JSON_HEDLEY_UNREACHABLE +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#undef JSON_HEDLEY_VERSION +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#undef JSON_HEDLEY_VERSION_DECODE_MINOR +#undef JSON_HEDLEY_VERSION_DECODE_REVISION +#undef JSON_HEDLEY_VERSION_ENCODE +#undef JSON_HEDLEY_WARNING +#undef JSON_HEDLEY_WARN_UNUSED_RESULT +#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#undef JSON_HEDLEY_FALL_THROUGH + + + +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/demboyz/base/jsonfile.cpp b/demboyz/base/jsonfile.cpp deleted file mode 100644 index 0ce640f..0000000 --- a/demboyz/base/jsonfile.cpp +++ /dev/null @@ -1,470 +0,0 @@ - -#include "jsonfile.h" -#include -#include - -#define CBASE64_IMPLEMENTATION -#include "cbase64/cbase64.h" - -#define RIGHT_TO_LEFT_BITS - -namespace base -{ - JsonWriterFile::JsonWriterFile(FILE* fp, char* buffer, std::size_t length): - m_fileStream(fp, buffer, length), - m_writer(m_fileStream), - m_fp(fp) - { - } - - JsonWriterFile::~JsonWriterFile() - { - Flush(); - } - - FILE* JsonWriterFile::GetFp() const - { - return m_fp; - } - - void JsonWriterFile::Flush() - { - m_fileStream.Flush(); - fflush(m_fp); - } - - void JsonWriterFile::Reset() - { - m_writer.Reset(m_fileStream); - } - - bool JsonWriterFile::IsComplete() const - { - return m_writer.IsComplete(); - } - - void JsonWriterFile::StartObject(const char* name /*= nullptr*/) - { - auto& writer = m_writer; - if (name) - { - writer.String(name); - } - writer.StartObject(); - } - - void JsonWriterFile::EndObject() - { - m_writer.EndObject(); - } - - void JsonWriterFile::StartArray(const char* name /*= nullptr*/) - { - auto& writer = m_writer; - if (name) - { - writer.String(name); - } - writer.StartArray(); - } - - void JsonWriterFile::EndArray() - { - m_writer.EndArray(); - } - - void JsonWriterFile::WriteNull(const char* name) - { - auto& writer = m_writer; - writer.String(name); - writer.Null(); - } - - void JsonWriterFile::WriteBool(const char* name, bool value) - { - auto& writer = m_writer; - writer.String(name); - writer.Bool(value); - } - - void JsonWriterFile::WriteChar(const char* name, char value) - { - auto& writer = m_writer; - writer.String(name); - - char temp[2] = { value, '\0' }; - writer.String(temp); - } - - void JsonWriterFile::WriteInt32(const char* name, std::int32_t value) - { - auto& writer = m_writer; - writer.String(name); - writer.Int(value); - } - - void JsonWriterFile::WriteInt32(const char* name, std::int32_t value, bool writeCondition) - { - auto& writer = m_writer; - writer.String(name); - if (writeCondition) - { - writer.Int(value); - } - else - { - writer.Null(); - } - } - - void JsonWriterFile::WriteInt64(const char* name, std::int64_t value) - { - auto& writer = m_writer; - writer.String(name); - writer.Int64(value); - } - - void JsonWriterFile::WriteUInt32(const char* name, std::uint32_t value) - { - auto& writer = m_writer; - writer.String(name); - writer.Uint(value); - } - - void JsonWriterFile::WriteUInt32(const char* name, std::uint32_t value, bool writeCondition) - { - auto& writer = m_writer; - writer.String(name); - if (writeCondition) - { - writer.Uint(value); - } - else - { - writer.Null(); - } - } - - void JsonWriterFile::WriteUint64(const char* name, std::uint64_t value) - { - auto& writer = m_writer; - writer.String(name); - writer.Uint64(value); - } - - void JsonWriterFile::WriteString(const char* name, const char* value) - { - auto& writer = m_writer; - writer.String(name); - writer.String(value); - } - - void JsonWriterFile::WriteString(const char* name, const char* value, std::uint32_t length) - { - auto& writer = m_writer; - writer.String(name); - writer.String(value, length); - } - - void JsonWriterFile::WriteString(const char* name, const std::string& value) - { - auto& writer = m_writer; - writer.String(name); - writer.String(value.c_str(), value.length()); - } - - void JsonWriterFile::WriteFloat(const char* name, const double value) - { - auto& writer = m_writer; - writer.String(name); - writer.Double(value); - } - - void JsonWriterFile::WriteBits(const char* name, const unsigned char* data, std::size_t numBits) - { - auto& writer = m_writer; - writer.String(name); - - cbase64_encodestate state; - cbase64_init_encodestate(&state); - - const std::size_t numBytes = ((numBits + 7) >> 3); - - char* const encoded = (char*)malloc(cbase64_calc_encoded_length(numBytes)); - char* encodedCurOut = encoded; - - const std::size_t numBytesWithoutBits = (numBits >> 3); - const std::size_t numTrailingBits = (numBits & 7); - - encodedCurOut += cbase64_encode_block(data, numBytesWithoutBits, encodedCurOut, &state); - if (numTrailingBits > 0) - { -#ifdef LEFT_TO_RIGHT_BITS - const unsigned char lastByteClean = data[numBytesWithoutBits] & (0xFF >> numTrailingBits); -#else // RIGHT_TO_LEFT_BITS - const unsigned char lastByteClean = data[numBytesWithoutBits] & ~(0xFF << numTrailingBits); -#endif - encodedCurOut += cbase64_encode_block(&lastByteClean, 1, encodedCurOut, &state); - } - encodedCurOut += cbase64_encode_blockend(encodedCurOut, &state); - - writer.String(encoded, encodedCurOut - encoded); - free(encoded); - return; - } - - void JsonWriterFile::WriteBytes(const char* name, const unsigned char* data, std::size_t numBytes) - { - JsonWriterFile::WriteBits(name, data, numBytes * 8); - } - - JsonReaderObject::JsonReaderIterator::JsonReaderIterator(JsonValue* value, bool& hasReadError): - m_value(value), - m_hasReadError(hasReadError) - { - } - - JsonReaderObject JsonReaderIterator::operator*() const - { - return JsonReaderObject(*m_value, m_hasReadError); - } - - JsonReaderIterator& JsonReaderIterator::operator++() - { - ++m_value; - return *this; - } - - bool JsonReaderIterator::operator==(const JsonReaderIterator& other) const - { - return m_value == other.m_value; - } - - bool JsonReaderIterator::operator!=(const JsonReaderIterator& other) const - { - return m_value != other.m_value; - } - - JsonReaderObject::JsonReaderArray::JsonReaderArray(JsonValue& value, bool& parseError): - m_value(value), - m_hasReadError(parseError) - { - } - - bool JsonReaderArray::HasReadError() const - { - return m_hasReadError; - } - - std::size_t JsonReaderArray::size() const - { - return m_value.Size(); - } - - JsonReaderIterator JsonReaderArray::begin() - { - return JsonReaderIterator(m_value.Begin(), m_hasReadError); - } - - JsonReaderIterator JsonReaderArray::end() - { - return JsonReaderIterator(m_value.End(), m_hasReadError); - } - - JsonReaderObject::JsonReaderObject(JsonValue& value, bool& parseError): - m_value(value), - m_hasReadError(parseError) - { - } - - bool JsonReaderObject::HasReadError() const - { - return m_hasReadError; - } - - JsonReaderObject JsonReaderObject::ReadObject(const char* name) const - { - JsonValue& value = m_value[name]; - m_hasReadError |= !value.IsObject(); - return JsonReaderObject(value, m_hasReadError); - } - - JsonReaderArray JsonReaderObject::ReadArray(const char* name) const - { - JsonValue& value = m_value[name]; - m_hasReadError |= !value.IsArray(); - return JsonReaderArray(value, m_hasReadError); - } - - bool JsonReaderObject::ReadBool(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsBool()) - { - m_hasReadError = true; - return false; - } - return val.GetBool(); - } - - char JsonReaderObject::ReadChar(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsString() || val.GetStringLength() != 1) - { - m_hasReadError = true; - return false; - } - return *val.GetString(); - } - - std::int32_t JsonReaderObject::ReadInt32(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsInt()) - { - m_hasReadError = true; - return 0; - } - return val.GetInt(); - } - - std::int64_t JsonReaderObject::ReadInt64(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsInt64()) - { - m_hasReadError = true; - return 0; - } - return val.GetInt64(); - } - - std::uint32_t JsonReaderObject::ReadUInt32(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsUint()) - { - m_hasReadError = true; - return 0; - } - return val.GetUint(); - } - - std::uint64_t JsonReaderObject::ReadUint64(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsUint64()) - { - m_hasReadError = true; - return 0; - } - return val.GetUint64(); - } - - std::uint32_t JsonReaderObject::ReadString(const char* name, char* dest, std::uint32_t maxLength) - { - const auto& val = m_value[name]; - if (!val.IsString()) - { - m_hasReadError = true; - return 0; - } - strncpy(dest, val.GetString(), maxLength - 1); - dest[maxLength - 1] = '\0'; - return std::min(maxLength - 1, val.GetStringLength()); - } - - float JsonReaderObject::ReadFloat(const char* name) - { - const auto& val = m_value[name]; - if (!val.IsDouble()) - { - m_hasReadError = true; - return 0.0f; - } - return val.GetDouble(); - } - - std::size_t JsonReaderObject::ReadBits(const char* name, unsigned char* dest, std::size_t numBits) - { - const auto& val = m_value[name]; - if (!val.IsString()) - { - m_hasReadError = true; - return 0; - } - - const char* const encodedBits = val.GetString(); - const std::size_t numEncodedBytes = val.GetStringLength(); - const std::size_t numDecodedBytes = cbase64_calc_decoded_length(encodedBits, numEncodedBytes); - if (!dest || (numDecodedBytes == 0)) - { - return numDecodedBytes * 8; - } - - const std::size_t numBytes = ((numBits + 7) >> 3); - if ((numDecodedBytes == 0) || (numBytes < numDecodedBytes)) - { - return 0; - } - - unsigned char* lastByte = &dest[numDecodedBytes - 1]; - unsigned char restoreBits = *lastByte; - - cbase64_decodestate state; - cbase64_init_decodestate(&state); - const size_t numWritten = cbase64_decode_block(encodedBits, numEncodedBytes, dest, &state); - assert(numWritten == numDecodedBytes); - - const std::size_t numTrailingBits = (numBits & 7); - if (numTrailingBits > 0) - { - // clean up end of decoded, clean up start of restoreBits - // then combine -#ifdef LEFT_TO_RIGHT_BITS - *lastByte = (*lastByte & ~(0xFF >> numTrailingBits)) | - (restoreBits & (0xFF >> numTrailingBits)); -#else // RIGHT_TO_LEFT_BITS - *lastByte = (*lastByte & ~(0xFF << numTrailingBits)) | - (restoreBits & (0xFF << numTrailingBits)); -#endif - } - return numBits; - } - - std::size_t JsonReaderObject::ReadBytes(const char* name, unsigned char* dest, std::size_t numBytes) - { - const std::size_t numBitsRead = ReadBits(name, dest, numBytes * 8); - assert((numBitsRead & 7) == 0); - return (numBitsRead / 8); - } - - JsonReaderFile::JsonReaderFile(FILE* fp, char* buffer, std::size_t length): - m_fileStream(fp, buffer, length), - m_document() - { - } - - JsonReaderObject JsonReaderFile::ParseObject() - { - const int flags = rapidjson::kParseValidateEncodingFlag | - rapidjson::kParseStopWhenDoneFlag; - - auto& document = m_document; - document.ParseStream(m_fileStream); - m_hasParseError = document.HasParseError(); - m_hasReadError = false; - return JsonReaderObject(document, m_hasReadError); - } - - bool JsonReaderFile::HasParseError() const - { - return m_hasParseError; - } - - bool JsonReaderFile::HasReadError() const - { - return m_hasReadError; - } -} diff --git a/demboyz/base/jsonfile.h b/demboyz/base/jsonfile.h deleted file mode 100644 index 0991c7a..0000000 --- a/demboyz/base/jsonfile.h +++ /dev/null @@ -1,147 +0,0 @@ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace base -{ - class JsonWriterFile - { - public: - JsonWriterFile(FILE* fp, char* buffer, std::size_t length); - ~JsonWriterFile(); - - FILE* GetFp() const; - void Flush(); - void Reset(); - bool IsComplete() const; - - void StartObject(const char* name = nullptr); - void EndObject(); - - void StartArray(const char* name = nullptr); - void EndArray(); - - void WriteNull(const char* name); - void WriteBool(const char* name, bool value); - void WriteChar(const char* name, char value); - void WriteInt32(const char* name, std::int32_t value); - void WriteInt32(const char* name, std::int32_t value, bool writeCondition); - void WriteInt64(const char* name, std::int64_t value); - void WriteUInt32(const char* name, std::uint32_t value); - void WriteUInt32(const char* name, std::uint32_t value, bool writeCondition); - void WriteUint64(const char* name, std::uint64_t value); - void WriteString(const char* name, const char* value); - void WriteString(const char* name, const char* value, std::uint32_t length); - void WriteString(const char* name, const std::string& value); - void WriteFloat(const char* name, const double value); - - void WriteBits(const char* name, const unsigned char* data, std::size_t numBits); - void WriteBytes(const char* name, const unsigned char* data, std::size_t numBytes); - - private: - rapidjson::FileWriteStream m_fileStream; - rapidjson::PrettyWriter> m_writer; - FILE* m_fp; - }; - - class JsonReaderObject - { - public: - using JsonValue = rapidjson::GenericValue>; - - class JsonReaderIterator - { - public: - explicit JsonReaderIterator(JsonValue* value, bool& hasReadError); - - JsonReaderObject operator*() const; - JsonReaderIterator& operator++(); - bool operator==(const JsonReaderIterator& other) const; - bool operator!=(const JsonReaderIterator& other) const; - - private: - JsonValue* m_value; - bool& m_hasReadError; - }; - - class JsonReaderArray - { - public: - explicit JsonReaderArray(JsonValue& value, bool& parseError); - - bool HasReadError() const; - - std::size_t size() const; - JsonReaderIterator begin(); - JsonReaderIterator end(); - - template - void TransformTo(Container& c, Fn fn) - { - c.resize(m_value.Size()); - std::size_t index = 0; - for (base::JsonReaderObject obj : *this) - { - fn(obj, c[index++]); - } - } - - private: - JsonValue& m_value; - bool& m_hasReadError; - }; - - public: - explicit JsonReaderObject(JsonValue& value, bool& parseError); - - bool HasReadError() const; - - JsonReaderObject ReadObject(const char* name) const; - JsonReaderArray ReadArray(const char* name) const; - - bool ReadBool(const char* name); - char ReadChar(const char* name); - std::int32_t ReadInt32(const char* name); - std::int64_t ReadInt64(const char* name); - std::uint32_t ReadUInt32(const char* name); - std::uint64_t ReadUint64(const char* name); - std::uint32_t ReadString(const char* name, char* dest, std::uint32_t maxLength); - //std::string ReadString(const char* name, std::uint32_t maxLength); - float ReadFloat(const char* name); - - std::size_t ReadBits(const char* name, unsigned char* dest, std::size_t numBits); - std::size_t ReadBytes(const char* name, unsigned char* dest, std::size_t numBytes); - - private: - JsonValue& m_value; - bool& m_hasReadError; - }; - - using JsonReaderIterator = JsonReaderObject::JsonReaderIterator; - using JsonReaderArray = JsonReaderObject::JsonReaderArray; - - class JsonReaderFile - { - public: - JsonReaderFile(FILE* fp, char* buffer, std::size_t length); - - JsonReaderObject ParseObject(); - - bool HasParseError() const; - bool HasReadError() const; - - private: - rapidjson::FileReadStream m_fileStream; - rapidjson::GenericDocument> m_document; - bool m_hasParseError; - bool m_hasReadError; - }; -} diff --git a/demboyz/base/steamid.h b/demboyz/base/steamid.h new file mode 100644 index 0000000..4e35961 --- /dev/null +++ b/demboyz/base/steamid.h @@ -0,0 +1,457 @@ +/*! + * SteamID Parser + * + * Copyright 2014 Mukunda Johnson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once +#ifndef _STEAMID_ +#define _STEAMID_ + +#include +#include + +/** --------------------------------------------------------------------------- + * SteamID + * + * Contains a User Steam ID. + * + * @author Mukunda Johnson + */ +class SteamID { + +public: + enum class Formats { + AUTO = 0, // Auto-detect format --- this also supports + // other unlisted formats such as + // full profile URLs. + STEAMID32 = 1, // Classic STEAM_x:y:zzzzzz | x = 0/1 + STEAMID64 = 2, // SteamID64: 7656119xxxxxxxxxx + STEAMID3 = 3, // SteamID3 format: [U:1:xxxxxx] + S32 = 4, // Raw 32-bit SIGNED format. + // this is a raw steamid index that overflows + // into negative bitspace. + // This is the format that SourceMod returns + // with GetSteamAccountID, and will always + // fit into a 32-bit signed variable. (e.g. + // a 32-bit PHP integer). + RAW = 5, // Raw index. like 64-bit minus the base value. + + }; + + // 64-bit type. + using bigint = long long; + using uint = unsigned int; + + // base constant of 64-bit Steam IDs + static const bigint STEAMID64_BASE = 76561197960265728L; + + // max allowed value. (sanity check) + // 2^36; update this in approx 2,400,000 years + static const bigint MAX_VALUE = 68719476736L; + + /** ----------------------------------------------------------------------- + * Parse a Steam ID. + * + * @param input Input to parse. + * + * @param format Input formatting, see Format constants. + * Defaults to Format::AUTO which detects the format. + * + * @param detect_raw Detect and parse RAW values. (only used with + * Format::AUTO. e.g "123" will resolve to the + * SteamID with the raw value 123. + * Default option set with ParseRawDefault. + * + * @returns SteamID instance or an empty SteamID if the parsing fails. + */ + static SteamID Parse( const std::string &input, + Formats format = Formats::AUTO, + int detect_raw = ParseRawDefault(-1) ) { + + if( input.empty() ) return SteamID(); // no input... + + try { + switch( format ) { + + //----------------------------------------------------------------- + case Formats::STEAMID32: { + + // regex is slow as fuck for some reason. + if( input.size() < 11 || input[0] != 'S' || input[1] != 'T' + || input[2] != 'E' || input[3] != 'A' || input[4] != 'M' + || input[5] != '_' || !Is01(input,6) || input[7] != ':' + || !Is01(input,8) || input[9] != ':' ) return SteamID(); + + // STEAM_X:Y:Z' +// static const std::regex r( +// R"--(^STEAM_[0-1]:[0-1]:[0-9]+$)--", +// rc::icase | rc::optimize ); +// +// if( !std::regex_match( input, r ) ) return SteamID(); + + bigint z = std::stoll( input.substr( 10 ) ); + z = (z << 1) + (input[8] - '0'); + + SteamID result(z); + //result.Cache( Format::STEAMID32, input ); + return result; + + //----------------------------------------------------------------- + } case Formats::STEAMID64: { + + // allow digits only + if( !IsDigits( input ) ) return SteamID(); + + // convert to raw (subtract base) + SteamID result( std::stoll( input ) - STEAMID64_BASE ); + //result.Cache( Format::STEAMID64, input ); + return result; + + //----------------------------------------------------------------- + } case Formats::STEAMID3: { + + // [U:1:xxxxxx] + if( input.size() < 7 || input[0] != '[' || input[1] != 'U' + || input[2] != ':' || input[3] != '1' || input[4] != ':' + || input[input.size()-1] != ']' + || !IsDigits( input, 5, input.size() - 1 - 5 ) ) { + + return SteamID(); + } + + // slow. +// static const std::regex r( R"--(^\[U:1:[0-9]+\]$)--", +// rc::optimize ); +// if( !std::regex_match( input, r ) ) return SteamID(); + + SteamID result( std::stoll( + input.substr( 5, input.size() - 1 - 5 ))); + + //result.Cache( Format::STEAMID3, input ); + return result; + + //----------------------------------------------------------------- + } case Formats::S32: { + + // signed digits + if( !IsDigits( input, input[0] == '-' ? 1:0 ) ) { + return SteamID(); + } + + bigint a = std::stoll( input ); + if( a < 0 ) a += 4294967296L; + + SteamID result( a ); + //result.Cache( Format::S32, input ); + return result; + + //----------------------------------------------------------------- + } case Formats::RAW: { + + // validate digits only + if( !IsDigits( input ) ) return SteamID(); + + return SteamID( std::stoll( input )); + } + + case Formats::AUTO: { + break; + }} + } catch( std::out_of_range& ) { + + // integer conversion out of range... + return SteamID(); + } + // Auto detect format: + + std::string cleaned = TrimString(input); + SteamID result; + result = Parse( cleaned, Formats::STEAMID32 ); + if( *result ) return result; + result = Parse( cleaned, Formats::STEAMID64 ); + if( *result ) return result; + result = Parse( cleaned, Formats::STEAMID3 ); + if( *result ) return result; + + result = TryConvertProfileURL( cleaned ); + if( *result ) return result; + + // static const std::regex r_url( + // R"--(^(?:https?:\/\/)?(?:www.)?steamcommunity.com\/profiles\/([0-9]+)$)--", + // rc::icase | rc::optimize ); + + // std::smatch matches; + // if( std::regex_match( cleaned, matches, r_url ) ) { + // result = Parse( matches[1], Formats::STEAMID64 ); + // if( *result ) return result; + // } + + if( detect_raw ) { + result = Parse( input, Formats::S32 ); + if( *result ) return result; + result = Parse( input, Formats::RAW ); + if( *result ) return result; + } + + // unknown stem + return SteamID(); + } + + /** ----------------------------------------------------------------------- + * Format this SteamID to a string. + * + * @param format Output format. See Format constants. + * @returns Formatted Steam ID, or an empty string if an invalid + * format is given or the desired format cannot + * contain the SteamID. + */ + std::string Format( Formats format ) const { + + switch( format ) { + case Formats::STEAMID32: { + bigint z = m_value >> 1; + int y = m_value & 1; + return std::string("STEAM_1:") + std::to_string(y) + + ":" + std::to_string(z); + + } case Formats::STEAMID64: { + return std::to_string( m_value + STEAMID64_BASE ); + + } case Formats::STEAMID3: { + return std::string( "[U:1:" ) + + std::to_string(m_value) + ']'; + + } case Formats::S32: { + if( m_value >= 4294967296L ) { + return ""; // too large for s32. + } + + if( m_value >= 2147483648L ) { + return std::to_string( m_value - 4294967296L ); + } + + // --> + } case Formats::RAW: { + return std::to_string( m_value ); + } + + case Formats::AUTO: { + break; + }} + + return ""; + } + + /** ----------------------------------------------------------------------- + * Set the default setting for detect_raw for Parse() + * + * @param detect_raw Default detect_raw value, see Parse function. + * @returns Current or updated setting. + */ + static bool ParseRawDefault( int detect_raw = -1 ) { + static int option = false; + if( detect_raw == -1 ) return !!option; + option = !!detect_raw; + return !!option; + } + + /** ----------------------------------------------------------------------- + * Overload for Format. + */ + std::string operator[]( Formats format ) const { + return Format( format ); + } + + /** ----------------------------------------------------------------------- + * Get raw value. 0 = empty + */ + bigint Value() const { + return m_value; + } + + /** ----------------------------------------------------------------------- + * Get raw value. 0 = empty + */ + bigint operator*() const { + return m_value; + } + + /** ----------------------------------------------------------------------- + * Returns true if this SteamID is empty/invalid. + */ + bool operator!() { + return m_value == 0; + } + + /** ----------------------------------------------------------------------- + * Returns true if this SteamID is empty/invalid. + */ + bool Empty() const { + return m_value == 0; + } + + /** ----------------------------------------------------------------------- + * Get 64-bit Steam ID. + */ + bigint To64() { + return m_value + STEAMID64_BASE; + } + + /** ----------------------------------------------------------------------- + * Get raw value, same as operator*. + */ + bigint ToRaw() { + return m_value; + } + + /** ----------------------------------------------------------------------- + * Get 32-bit value cast to signed. + */ + int ToS32() { + if( m_value > 0xFFFFFFFF ) { + return 0; + } + return (int)m_value; + } + + /** ----------------------------------------------------------------------- + * Parsing shortcut. + */ + SteamID( const std::string &input, Formats format = Formats::AUTO, + int detect_raw = ParseRawDefault() ) + : SteamID( Parse( input, format, detect_raw )) { + } + + /** ----------------------------------------------------------------------- + * Construct a Steam ID. + * + * @param raw RAW value of Steam ID. + */ + SteamID( bigint raw ) + : m_value( (raw > 0 && raw <= MAX_VALUE) ? raw : 0 ) { + } + + /** ----------------------------------------------------------------------- + * An empty steam id. + */ + SteamID() : m_value(0) { + } + + SteamID( const SteamID& o ) = default; + SteamID( SteamID&& o ) { + m_value = o.m_value; + } + SteamID& operator=( const SteamID& o ) = default; + SteamID& operator=( SteamID&& o ) { + m_value = o.m_value; + return *this; + } + +private: + + bigint m_value; // RAW Steam ID value. + + //------------------------------------------------------------------------- + static bool IsDigits( const std::string &str, size_t start = 0, + size_t length = 9000 ) { + + for( size_t i = start; i != (start+length) && str[i]; i++ ) { + if( str[i] < '0' || str[i] > '9' ) return false; + } + return true; + } + + //------------------------------------------------------------------------- + static bool Is01( const std::string &str, size_t index ) { + return str[index] == '0' || str[index] == '1'; + } + + //------------------------------------------------------------------------- + static std::string TrimString( const std::string &input ) { + + int start = 0, end = (int)input.size()-1; + if( end < 0 ) return ""; + + while( std::isspace( input[start] )) { + start++; + if( start == (int)input.size() ) return ""; + } + + while( std::isspace( input[end] )) { + end--; + } + + return input.substr( start, 1+end-start ); + } + + //------------------------------------------------------------------------- + static SteamID TryConvertProfileURL( std::string &str ) { + if( str[0] != 'h' && str[0] != 'w' && str[0] != 's' ) return SteamID(); + + int lastslash = str.find_last_of( '/' ); + if( lastslash == (int)std::string::npos ) return SteamID(); + if( lastslash == (int)str.size()-1 ) { + str.pop_back(); + lastslash = str.find_last_of( '/' ); + if( lastslash == (int)std::string::npos ) return SteamID(); + } + + if( CheckProfilePrefix( str, lastslash ) ) { + return Parse( str.substr( lastslash+1 ) ); + } + return SteamID(); + } + + static bool CheckProfilePrefix( std::string &str, int end ) { + // possible prefixes: + // 0123456789012345678901234567890123456789 + // https://www.steamcommunity.com/profiles/ + // http://www.steamcommunity.com/profiles/ + // https://steamcommunity.com/profiles/ + // http://steamcommunity.com/profiles/ + // www.steamcommunity.com/profiles/ + // steamcommunity.com/profiles/ + + if( end == 39 ) { + return str.compare( 0, 1+end, + "https://www.steamcommunity.com/profiles/" ) == 0; + } else if( end == 38 ) { + return str.compare( 0, 1+end, + "http://www.steamcommunity.com/profiles/" ) == 0; + } else if( end == 35 ) { + return str.compare( 0, 1+end, + "https://steamcommunity.com/profiles/" ) == 0; + } else if( end == 34 ) { + return str.compare( 0, 1+end, + "http://steamcommunity.com/profiles/" ) == 0; + } else if( end == 31 ) { + return str.compare( 0, 1+end, + "www.steamcommunity.com/profiles/" ) == 0; + } else if( end == 27 ) { + return str.compare( 0, 1+end, + "steamcommunity.com/profiles/" ) == 0; + } + return false; + } +}; + +#endif diff --git a/demboyz/demboyz.cpp b/demboyz/demboyz.cpp index 13f0897..3957c44 100644 --- a/demboyz/demboyz.cpp +++ b/demboyz/demboyz.cpp @@ -1,76 +1,20 @@ -#include "io/idemowriter.h" #include "io/demoreader.h" -#include "json_checker/JSON_checker.h" +#include "game/sourcecontext.h" #include #include #include - -std::string GetExtension(const std::string& filename) -{ - size_t index = filename.find_last_of("."); - if (index != std::string::npos) - { - return filename.substr(index + 1); - } - return std::string(); -} - -enum class FileType -{ - None, - Dem, - Json, - ConLog -}; - -FileType GetFileType(const std::string& filename) -{ - std::string ext = GetExtension(filename); - if (ext == "dem") - { - return FileType::Dem; - } - if (ext == "json") - { - return FileType::Json; - } - if (ext == "con") - { - return FileType::ConLog; - } - return FileType::None; -} +#include int main(const int argc, const char* argv[]) { - if (argc != 3) + if (argc != 2) { - fprintf(stderr, "Usage: %s .dem/json .dem/json/con\n", argv[0]); - return -1; - } - - std::string inputFile(argv[1]); - std::string outputFile(argv[2]); - if (inputFile == outputFile) - { - fprintf(stderr, "Error: Input and output file cannot be the same!\n"); - return -1; - } - - FileType inputType = GetFileType(inputFile); - FileType outputType = GetFileType(outputFile); - if (inputType == FileType::None) - { - fprintf(stderr, "Error: Bad type for input file\n"); - return -1; - } - if (outputType == FileType::None) - { - fprintf(stderr, "Error: Bad type for output file\n"); + fprintf(stderr, "Usage: %s .dem\n", argv[0]); return -1; } + std::filesystem::path inputFile(argv[1]); FILE* inputFp = fopen(inputFile.c_str(), "rb"); if (!inputFp) { @@ -78,66 +22,18 @@ int main(const int argc, const char* argv[]) return -1; } - FILE* outputFp = fopen(outputFile.c_str(), "wb"); - if (!outputFp) - { - fprintf(stderr, "Error: Could not open input file\n"); - fclose(inputFp); + std::filesystem::path outputDir = inputFile.filename().replace_extension(); + std::filesystem::path outputDirVoice = outputDir.string() + "/voice"; + std::filesystem::create_directory(outputDir); + std::filesystem::create_directory(outputDirVoice); + + SourceGameContext context = SourceGameContext(outputDir, outputDirVoice); + if (!context.init()) return -1; - } - IDemoWriter* writer = nullptr; - if (outputType == FileType::Dem) - { - writer = IDemoWriter::CreateDemoWriter(outputFp); - } - else if (outputType == FileType::Json) - { - writer = IDemoWriter::CreateJsonWriter(outputFp); - } - else if (outputType == FileType::ConLog) - { - writer = IDemoWriter::CreateConLogWriter(outputFp); - } - else - { - assert(false); - } - - if (inputType == FileType::Dem) - { - DemoReader::ProcessDem(inputFp, writer); - } - else if (inputType == FileType::Json) - { - DemoReader::ProcessJson(inputFp, writer); - } - else - { - assert(false); - } - IDemoWriter::FreeDemoWriter(writer); + bool error = DemoReader::ProcessDem(inputFp, &context); fclose(inputFp); - fclose(outputFp); - /*if (outputType == FileType::Json) - { - FILE* outputFp = fopen(outputFile.c_str(), "rb"); - JSON_checker jc = new_JSON_checker(20); - int next_char = 0; - while ((next_char = fgetc(outputFp)) > 0) - { - if (!JSON_checker_char(jc, next_char)) - { - fprintf(stderr, "JSON_checker_char: syntax error\n"); - } - } - if (!JSON_checker_done(jc)) - { - fprintf(stderr, "JSON_checker_end: syntax error\n"); - } - fclose(outputFp); - }*/ - return 0; + return error; } diff --git a/demboyz/demmessages/dem_consolecmd.cpp b/demboyz/demmessages/dem_consolecmd.cpp index 96fdee8..c0962e8 100644 --- a/demboyz/demmessages/dem_consolecmd.cpp +++ b/demboyz/demmessages/dem_consolecmd.cpp @@ -1,7 +1,6 @@ #include "dem_consolecmd.h" #include "demofile/demofile.h" -#include "base/jsonfile.h" namespace DemHandlers { @@ -12,31 +11,4 @@ namespace DemHandlers data->command.assign(command); return demofile.IsOk(); } - - bool Dem_ConsoleCmd_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_ConsoleCmd* data) - { - const uint8_t* command = reinterpret_cast(data->command.data()); - demofile.WriteRawData(command, data->command.length() + 1); - return demofile.IsOk(); - } - - bool Dem_ConsoleCmd_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_ConsoleCmd* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - char command[DemMsg::Dem_ConsoleCmd::COMMAND_MAX_LENGTH]; - reader.ReadString("command", command, sizeof(command)); - data->command.assign(command); - return !reader.HasReadError(); - } - - bool Dem_ConsoleCmd_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_ConsoleCmd* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteString("command", data->command); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } } diff --git a/demboyz/demmessages/dem_datatables.cpp b/demboyz/demmessages/dem_datatables.cpp index de57b13..dd1ee53 100644 --- a/demboyz/demmessages/dem_datatables.cpp +++ b/demboyz/demmessages/dem_datatables.cpp @@ -1,38 +1,74 @@ #include "dem_datatables.h" #include "demofile/demofile.h" -#include "demofile/demojson.h" +#include "sourcesdk/bitbuf.h" +#include namespace DemHandlers { bool Dem_DataTables_FileRead_Internal(FileRead& demofile, DemMsg::Dem_DataTables* data) { - data->data = demofile.ReadRawData(DemMsg::Dem_DataTables::DATA_MAX_LENGTH); + Array buffer = demofile.ReadRawData(DemMsg::Dem_DataTables::DATA_MAX_LENGTH); + bf_read bitbuf(buffer.begin(), buffer.length()); + + char strBuf[1024]; + while (bitbuf.ReadOneBit() != 0) + { + DemMsg::Dem_DataTables::SendTable sendTable; + + sendTable.needsDecoder = bitbuf.ReadOneBit() != 0; + bitbuf.ReadString(strBuf, sizeof(strBuf)); + sendTable.name.assign(strBuf); + + sendTable.numProps = bitbuf.ReadUBitLong(PROPINFOBITS_NUMPROPS); + + for (int i = 0; i < sendTable.numProps; i++) + { + DemMsg::Dem_DataTables::SendProp prop; + + prop.type = bitbuf.ReadUBitLong(PROPINFOBITS_TYPE); + + bitbuf.ReadString(strBuf, sizeof(strBuf)); + prop.name.assign(strBuf); + + prop.flags = bitbuf.ReadUBitLong(PROPINFOBITS_FLAGS); // demoprotocol 2: 11 + + if (prop.type == DPT_DataTable || prop.flags & SPROP_EXCLUDE) + { + bitbuf.ReadString(strBuf, sizeof(strBuf)); + prop.exclude.assign(strBuf); + } + else if (prop.type == DPT_Array) + { + prop.elements = bitbuf.ReadUBitLong(PROPINFOBITS_NUMELEMENTS); + } + else + { + prop.lowValue = bitbuf.ReadBitFloat(); + prop.highValue = bitbuf.ReadBitFloat(); + prop.bits = bitbuf.ReadUBitLong(PROPINFOBITS_NUMBITS); + } + + sendTable.props.push_back(prop); + } + + data->sendtables.push_back(sendTable); + } + + int numClasses = bitbuf.ReadShort(); + data->classes.reset(numClasses); + for (int i = 0; i < numClasses; i++) + { + int classID = bitbuf.ReadShort(); + DemMsg::Dem_DataTables::DataClass &dataClass = data->classes[classID]; + + bitbuf.ReadString(strBuf, sizeof(strBuf)); + dataClass.className.assign(strBuf); + + bitbuf.ReadString(strBuf, sizeof(strBuf)); + dataClass.datatableName.assign(strBuf); + } + return demofile.IsOk(); } - - bool Dem_DataTables_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_DataTables* data) - { - demofile.WriteRawData(data->data.begin(), data->data.length()); - return demofile.IsOk(); - } - - bool Dem_DataTables_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_DataTables* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - data->data.reset(reader.ReadBytes("data", nullptr, 0)); - reader.ReadBytes("data", data->data.begin(), DemMsg::Dem_DataTables::DATA_MAX_LENGTH); - return !reader.HasReadError(); - } - - bool Dem_DataTables_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_DataTables* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBytes("data", data->data.begin(), data->data.length()); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } } diff --git a/demboyz/demmessages/dem_datatables.h b/demboyz/demmessages/dem_datatables.h index e394496..c7636a6 100644 --- a/demboyz/demmessages/dem_datatables.h +++ b/demboyz/demmessages/dem_datatables.h @@ -3,13 +3,114 @@ #include "demhandlers.h" #include "base/array.h" +#include +#include + +#define PROPINFOBITS_NUMPROPS 10 +#define PROPINFOBITS_NUMPROPS 10 +#define PROPINFOBITS_TYPE 5 +#define PROPINFOBITS_FLAGS SPROP_NUMFLAGBITS_NETWORKED +#define PROPINFOBITS_STRINGBUFFERLEN 10 +#define PROPINFOBITS_NUMBITS 7 +#define PROPINFOBITS_RIGHTSHIFT 6 +#define PROPINFOBITS_NUMELEMENTS 10 // For arrays. + + +// SendProp::m_Flags. +#define SPROP_UNSIGNED (1<<0) // Unsigned integer data. + +#define SPROP_COORD (1<<1) // If this is set, the float/vector is treated like a world coordinate. + // Note that the bit count is ignored in this case. + +#define SPROP_NOSCALE (1<<2) // For floating point, don't scale into range, just take value as is. + +#define SPROP_ROUNDDOWN (1<<3) // For floating point, limit high value to range minus one bit unit + +#define SPROP_ROUNDUP (1<<4) // For floating point, limit low value to range minus one bit unit + +#define SPROP_NORMAL (1<<5) // If this is set, the vector is treated like a normal (only valid for vectors) + +#define SPROP_EXCLUDE (1<<6) // This is an exclude prop (not excludED, but it points at another prop to be excluded). + +#define SPROP_XYZE (1<<7) // Use XYZ/Exponent encoding for vectors. + +#define SPROP_INSIDEARRAY (1<<8) // This tells us that the property is inside an array, so it shouldn't be put into the + // flattened property list. Its array will point at it when it needs to. + +#define SPROP_PROXY_ALWAYS_YES (1<<9) // Set for datatable props using one of the default datatable proxies like + // SendProxy_DataTableToDataTable that always send the data to all clients. + +#define SPROP_CHANGES_OFTEN (1<<10) // this is an often changed field, moved to head of sendtable so it gets a small index + +#define SPROP_IS_A_VECTOR_ELEM (1<<11) // Set automatically if SPROP_VECTORELEM is used. + +#define SPROP_COLLAPSIBLE (1<<12) // Set automatically if it's a datatable with an offset of 0 that doesn't change the pointer + // (ie: for all automatically-chained base classes). + // In this case, it can get rid of this SendPropDataTable altogether and spare the + // trouble of walking the hierarchy more than necessary. + +#define SPROP_COORD_MP (1<<13) // Like SPROP_COORD, but special handling for multiplayer games +#define SPROP_COORD_MP_LOWPRECISION (1<<14) // Like SPROP_COORD, but special handling for multiplayer games where the fractional component only gets a 3 bits instead of 5 +#define SPROP_COORD_MP_INTEGRAL (1<<15) // SPROP_COORD_MP, but coordinates are rounded to integral boundaries + +#define SPROP_VARINT SPROP_NORMAL // reuse existing flag so we don't break demo. note you want to include SPROP_UNSIGNED if needed, its more efficient + +#define SPROP_NUMFLAGBITS_NETWORKED 16 + +// This is server side only, it's used to mark properties whose SendProxy_* functions encode against gpGlobals->tickcount (the only ones that currently do this are +// m_flAnimTime and m_flSimulationTime. MODs shouldn't need to mess with this probably +#define SPROP_ENCODED_AGAINST_TICKCOUNT (1<<16) + +// See SPROP_NUMFLAGBITS_NETWORKED for the ones which are networked +#define SPROP_NUMFLAGBITS 17 + + +enum +{ + DPT_Int=0, + DPT_Float, + DPT_Vector, + DPT_VectorXY, + DPT_String, + DPT_Array, + DPT_DataTable, + DPT_Int64, + DPT_NUMSendPropTypes +}; namespace DemMsg { struct Dem_DataTables { static const int DATA_MAX_LENGTH = 256 * 1024; - Array data; + + struct SendProp + { + std::string name; + std::string exclude; + int type; + int flags; + int elements; + int lowValue; + int highValue; + int bits; + }; + + struct SendTable + { + bool needsDecoder; + std::string name; + int numProps; + std::vector props; + }; + std::vector sendtables; + + struct DataClass + { + std::string className; + std::string datatableName; + }; + Array classes; }; } diff --git a/demboyz/demmessages/dem_packet.cpp b/demboyz/demmessages/dem_packet.cpp index e6b74d7..c8d876e 100644 --- a/demboyz/demmessages/dem_packet.cpp +++ b/demboyz/demmessages/dem_packet.cpp @@ -1,7 +1,6 @@ #include "dem_packet.h" #include "demofile/demofile.h" -#include "demofile/demojson.h" #include "netmessages/nethandlers.h" namespace DemHandlers @@ -12,31 +11,4 @@ namespace DemHandlers demofile.ReadSequenceInfo(data->sequenceNum1, data->sequenceNum2); return demofile.IsOk(); } - - bool Dem_Packet_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_Packet* data) - { - demofile.WriteCmdInfo(data->cmdInfo); - demofile.WriteSequenceInfo(data->sequenceNum1, data->sequenceNum2); - return demofile.IsOk(); - } - - bool Dem_Packet_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_Packet* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - bool readError = DemoJsonReader::ReadCmdInfo(reader, data->cmdInfo); - readError |= DemoJsonReader::ReadSequenceInfo(reader, data->sequenceNum1, data->sequenceNum2); - return !readError && !reader.HasReadError(); - } - - bool Dem_Packet_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_Packet* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - DemoJsonWriter::WriteCmdInfo(jsonbuf, data->cmdInfo); - DemoJsonWriter::WriteSequenceInfo(jsonbuf, data->sequenceNum1, data->sequenceNum2); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } } diff --git a/demboyz/demmessages/dem_stop.cpp b/demboyz/demmessages/dem_stop.cpp index 2fa47b9..6032041 100644 --- a/demboyz/demmessages/dem_stop.cpp +++ b/demboyz/demmessages/dem_stop.cpp @@ -7,19 +7,4 @@ namespace DemHandlers { return true; } - - bool Dem_Stop_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_Stop* data) - { - return true; - } - - bool Dem_Stop_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_Stop* data) - { - return true; - } - - bool Dem_Stop_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_Stop* data) - { - return true; - } } diff --git a/demboyz/demmessages/dem_stringtables.cpp b/demboyz/demmessages/dem_stringtables.cpp index 602fccb..d412724 100644 --- a/demboyz/demmessages/dem_stringtables.cpp +++ b/demboyz/demmessages/dem_stringtables.cpp @@ -3,17 +3,13 @@ #include "demofile/demofile.h" #include "netmessages/netcontants.h" #include "sourcesdk/bitbuf.h" -#include "base/jsonfile.h" -#include static void StringTableEntry_BitRead(bf_read& bitbuf, DemMsg::Dem_StringTables::StringTableEntry* data) { using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - { - char entryName[StringTableEntry::ENTRYNAME_MAX_LENGTH]; - bitbuf.ReadString(entryName, sizeof(entryName)); - data->entryName.assign(entryName); - } + + char entryName[StringTableEntry::ENTRYNAME_MAX_LENGTH]; + bitbuf.ReadString(entryName, sizeof(entryName)); if (bitbuf.ReadOneBit() != 0) { @@ -27,46 +23,14 @@ static void StringTableEntry_BitRead(bf_read& bitbuf, DemMsg::Dem_StringTables:: } } -static void StringTableEntry_BitWrite(bf_write& bitbuf, DemMsg::Dem_StringTables::StringTableEntry* data) -{ - bitbuf.WriteString(data->entryName.c_str()); - const int32_t numDataBytes = data->data.length(); - - bitbuf.WriteOneBit(numDataBytes > 0); - if (numDataBytes > 0) - { - bitbuf.WriteWord(numDataBytes); - bitbuf.WriteBytes(data->data.begin(), numDataBytes); - } -} - -static void StringTableEntry_JsonRead(base::JsonReaderObject& jsonbuf, DemMsg::Dem_StringTables::StringTableEntry* data) -{ - using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - { - char entryName[StringTableEntry::ENTRYNAME_MAX_LENGTH]; - jsonbuf.ReadString("name", entryName, sizeof(entryName)); - data->entryName.assign(entryName); - } - data->data.reset(jsonbuf.ReadBytes("data", nullptr, 0)); - jsonbuf.ReadBytes("data", data->data.begin(), data->data.length()); -} - -static void StringTableEntry_JsonWrite(DemHandlers::JsonWrite& jsonbuf, const DemMsg::Dem_StringTables::StringTableEntry* data) -{ - jsonbuf.WriteString("name", data->entryName); - jsonbuf.WriteBytes("data", data->data.begin(), data->data.length()); -} - static void StringTable_BitRead(bf_read& bitbuf, DemMsg::Dem_StringTables::StringTable* data) { using StringTable = DemMsg::Dem_StringTables::StringTable; using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - { - char tableName[StringTable::TABLENAME_MAX_LENGTH]; - bitbuf.ReadString(tableName, sizeof(tableName)); - data->tableName.assign(tableName); - } + + char tableName[StringTable::TABLENAME_MAX_LENGTH]; + bitbuf.ReadString(tableName, sizeof(tableName)); + data->tableName.assign(tableName); data->entries.reset(bitbuf.ReadWord()); for (StringTableEntry& entry : data->entries) @@ -87,78 +51,6 @@ static void StringTable_BitRead(bf_read& bitbuf, DemMsg::Dem_StringTables::Strin } } -static void StringTable_BitWrite(bf_write& bitbuf, DemMsg::Dem_StringTables::StringTable* data) -{ - using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - bitbuf.WriteString(data->tableName.c_str()); - - bitbuf.WriteWord(data->entries.length()); - for (StringTableEntry& entry : data->entries) - { - StringTableEntry_BitWrite(bitbuf, &entry); - } - - const int32_t numEntriesClientSide = data->entriesClientSide.length(); - bitbuf.WriteOneBit(numEntriesClientSide > 0); - if (numEntriesClientSide > 0) - { - bitbuf.WriteWord(numEntriesClientSide); - for (StringTableEntry& entry : data->entriesClientSide) - { - StringTableEntry_BitWrite(bitbuf, &entry); - } - } -} - -static void StringTable_JsonRead(base::JsonReaderObject& jsonbuf, DemMsg::Dem_StringTables::StringTable* data) -{ - using StringTable = DemMsg::Dem_StringTables::StringTable; - using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - { - char tableName[StringTable::TABLENAME_MAX_LENGTH]; - jsonbuf.ReadString("tableName", tableName, sizeof(tableName)); - data->tableName.assign(tableName); - } - - { - base::JsonReaderArray entries = jsonbuf.ReadArray("entries"); - entries.TransformTo(data->entries, [](base::JsonReaderObject& obj, StringTableEntry& entry) - { - StringTableEntry_JsonRead(obj, &entry); - }); - } - { - base::JsonReaderArray entriesClientSide = jsonbuf.ReadArray("entriesClientSide"); - entriesClientSide.TransformTo(data->entriesClientSide, [](base::JsonReaderObject& obj, StringTableEntry& entry) - { - StringTableEntry_JsonRead(obj, &entry); - }); - } -} - -static void StringTable_JsonWrite(DemHandlers::JsonWrite& jsonbuf, const DemMsg::Dem_StringTables::StringTable* data) -{ - using StringTableEntry = DemMsg::Dem_StringTables::StringTableEntry; - jsonbuf.WriteString("tableName", data->tableName); - jsonbuf.StartArray("entries"); - for (const StringTableEntry& entry : data->entries) - { - jsonbuf.StartObject(); - StringTableEntry_JsonWrite(jsonbuf, &entry); - jsonbuf.EndObject(); - } - jsonbuf.EndArray(); - - jsonbuf.StartArray("entriesClientSide"); - for (const StringTableEntry& entry : data->entriesClientSide) - { - jsonbuf.StartObject(); - StringTableEntry_JsonWrite(jsonbuf, &entry); - jsonbuf.EndObject(); - } - jsonbuf.EndArray(); -} - namespace DemHandlers { bool Dem_StringTables_FileRead_Internal(FileRead& demofile, DemMsg::Dem_StringTables* data) @@ -184,66 +76,4 @@ namespace DemHandlers } return !bitbuf.IsOverflowed(); } - - bool Dem_StringTables_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_StringTables* data) - { - using StringTable = DemMsg::Dem_StringTables::StringTable; - - std::unique_ptr buffer(new uint8_t[MAX_STRINGTABLE_DATA]); - bf_write bitbuf(buffer.get(), MAX_STRINGTABLE_DATA); - - bitbuf.WriteByte(data->stringtables.length()); - for (StringTable& table : data->stringtables) - { - StringTable_BitWrite(bitbuf, &table); - } - if (data->numTrailingBits > 0) - { - bitbuf.WriteUBitLong(data->trailingBitsValue, data->numTrailingBits); - } - demofile.WriteRawData(bitbuf.GetBasePointer(), bitbuf.GetNumBytesWritten()); - return !bitbuf.IsOverflowed(); - } - - bool Dem_StringTables_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_StringTables* data) - { - using StringTable = DemMsg::Dem_StringTables::StringTable; - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - data->stringtables.reset(reader.ReadInt32("numStringTables")); - data->numTrailingBits = reader.ReadUInt32("numTrailingBits"); - data->trailingBitsValue = reader.ReadUInt32("trailingBitsValue"); - } - { - for (StringTable& table : data->stringtables) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - StringTable_JsonRead(reader, &table); - } - } - return true; - } - - bool Dem_StringTables_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_StringTables* data) - { - using StringTable = DemMsg::Dem_StringTables::StringTable; - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("numStringTables", data->stringtables.length()); - jsonbuf.WriteUInt32("numTrailingBits", data->numTrailingBits); - jsonbuf.WriteUInt32("trailingBitsValue", data->trailingBitsValue, (data->numTrailingBits > 0)); - jsonbuf.EndObject(); - - for (const StringTable& table : data->stringtables) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - StringTable_JsonWrite(jsonbuf, &table); - jsonbuf.EndObject(); - } - return jsonbuf.IsComplete(); - } } diff --git a/demboyz/demmessages/dem_synctick.cpp b/demboyz/demmessages/dem_synctick.cpp index 326130f..29877e0 100644 --- a/demboyz/demmessages/dem_synctick.cpp +++ b/demboyz/demmessages/dem_synctick.cpp @@ -7,19 +7,4 @@ namespace DemHandlers { return true; } - - bool Dem_SyncTick_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_SyncTick* data) - { - return true; - } - - bool Dem_SyncTick_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_SyncTick* data) - { - return true; - } - - bool Dem_SyncTick_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_SyncTick* data) - { - return true; - } } diff --git a/demboyz/demmessages/dem_unknown.cpp b/demboyz/demmessages/dem_unknown.cpp index 325b896..3e869fe 100644 --- a/demboyz/demmessages/dem_unknown.cpp +++ b/demboyz/demmessages/dem_unknown.cpp @@ -7,19 +7,4 @@ namespace DemHandlers { return true; } - - bool Dem_Unknown_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_Unknown* data) - { - return true; - } - - bool Dem_Unknown_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_Unknown* data) - { - return true; - } - - bool Dem_Unknown_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_Unknown* data) - { - return true; - } } diff --git a/demboyz/demmessages/dem_usercmd.cpp b/demboyz/demmessages/dem_usercmd.cpp index 28083e1..099c03a 100644 --- a/demboyz/demmessages/dem_usercmd.cpp +++ b/demboyz/demmessages/dem_usercmd.cpp @@ -1,7 +1,6 @@ #include "dem_usercmd.h" #include "demofile/demofile.h" -#include "demofile/demojson.h" namespace DemHandlers { @@ -10,30 +9,4 @@ namespace DemHandlers data->commandData = demofile.ReadUserCmd(data->commandNum, DemMsg::Dem_UserCmd::COMMANDDATA_MAX_LENGTH); return demofile.IsOk(); } - - bool Dem_UserCmd_FileWrite_Internal(FileWrite& demofile, DemMsg::Dem_UserCmd* data) - { - demofile.WriteUserCmd(data->commandNum, data->commandData.begin(), data->commandData.length()); - return demofile.IsOk(); - } - - bool Dem_UserCmd_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::Dem_UserCmd* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - DemoJsonReader::ReadUserCmd(reader, data->commandNum, - data->commandData, DemMsg::Dem_UserCmd::COMMANDDATA_MAX_LENGTH); - return !reader.HasReadError(); - } - - bool Dem_UserCmd_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::Dem_UserCmd* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - DemoJsonWriter::WriteUserCmd(jsonbuf, data->commandNum, - data->commandData.begin(), data->commandData.length()); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } } diff --git a/demboyz/demmessages/demhandlers.cpp b/demboyz/demmessages/demhandlers.cpp index 79d622e..561a46c 100644 --- a/demboyz/demmessages/demhandlers.cpp +++ b/demboyz/demmessages/demhandlers.cpp @@ -51,9 +51,6 @@ void DemHandlers::DestroyDemMsgStructs(DemDataStructArray& demDataStructs) } typedef bool (*DemMsgFileReadFn)(DemHandlers::FileRead& demofile, void* data); -typedef bool (*DemMsgFileWriteFn)(DemHandlers::FileWrite& demofile, void* data); -typedef bool (*DemMsgJsonReadFn)(DemHandlers::JsonRead& jsonbuf, void* data); -typedef bool (*DemMsgJsonWriteFn)(DemHandlers::JsonWrite& jsonbuf, void* data); bool DemHandlers::DemMsg_FileRead(uint32_t type, FileRead& demofile, void* data) { @@ -64,33 +61,3 @@ bool DemHandlers::DemMsg_FileRead(uint32_t type, FileRead& demofile, void* data) } return demHandlers[type](demofile, data); } - -bool DemHandlers::DemMsg_FileWrite(uint32_t type, FileWrite& demofile, void* data) -{ - static const DemMsgFileWriteFn demHandlers[] = DECLARE_DEM_HANDLER_ARRAY(FileWrite); - if (type >= (sizeof(demHandlers) / sizeof(DemMsgFileWriteFn))) - { - return false; - } - return demHandlers[type](demofile, data); -} - -bool DemHandlers::DemMsg_JsonRead(uint32_t type, JsonRead& jsonbuf, void* data) -{ - static const DemMsgJsonReadFn demHandlers[] = DECLARE_DEM_HANDLER_ARRAY(JsonRead); - if (type >= (sizeof(demHandlers) / sizeof(DemMsgJsonReadFn))) - { - return false; - } - return demHandlers[type](jsonbuf, data); -} - -bool DemHandlers::DemMsg_JsonWrite(uint32_t type, JsonWrite& jsonbuf, void* data) -{ - static const DemMsgJsonWriteFn demHandlers[] = DECLARE_DEM_HANDLER_ARRAY(JsonWrite); - if (type >= (sizeof(demHandlers) / sizeof(DemMsgJsonWriteFn))) - { - return false; - } - return demHandlers[type](jsonbuf, data); -} diff --git a/demboyz/demmessages/demhandlers.h b/demboyz/demmessages/demhandlers.h index a6fd5b1..c6a0841 100644 --- a/demboyz/demmessages/demhandlers.h +++ b/demboyz/demmessages/demhandlers.h @@ -5,48 +5,20 @@ #include #include "demmessages.h" -namespace base -{ - class JsonReaderFile; - class JsonWriterFile; -} - class DemoFileReader; -class DemoFileWriter; -class DemoFileReader2; -class DemoFileWriter2; - namespace DemHandlers { using FileRead = DemoFileReader; - using FileWrite = DemoFileWriter; - using JsonRead = base::JsonReaderFile; - using JsonWrite = base::JsonWriterFile; } #define DECLARE_DEM_HANDLERS(msgname) \ namespace DemHandlers \ { \ bool msgname##_FileRead_Internal(FileRead& demofile, DemMsg::msgname* data); \ - bool msgname##_FileWrite_Internal(FileWrite& demofile, DemMsg::msgname* data); \ - bool msgname##_JsonRead_Internal(JsonRead& jsonbuf, DemMsg::msgname* data); \ - bool msgname##_JsonWrite_Internal(JsonWrite& jsonbuf, DemMsg::msgname* data); \ inline bool msgname##_FileRead(FileRead& demofile, void* data) \ { \ return msgname##_FileRead_Internal(demofile, reinterpret_cast(data)); \ } \ - inline bool msgname##_FileWrite(FileWrite& demofile, void* data) \ - { \ - return msgname##_FileWrite_Internal(demofile, reinterpret_cast(data)); \ - } \ - inline bool msgname##_JsonRead(JsonRead& jsonbuf, void* data) \ - { \ - return msgname##_JsonRead_Internal(jsonbuf, reinterpret_cast(data)); \ - } \ - inline bool msgname##_JsonWrite(JsonWrite& jsonbuf, void* data) \ - { \ - return msgname##_JsonWrite_Internal(jsonbuf, reinterpret_cast(data)); \ - } \ } namespace DemHandlers @@ -56,7 +28,4 @@ namespace DemHandlers void DestroyDemMsgStructs(DemDataStructArray& demDataStructs); bool DemMsg_FileRead(uint32_t type, FileRead& demofile, void* data); - bool DemMsg_FileWrite(uint32_t type, FileWrite& demofile, void* data); - bool DemMsg_JsonRead(uint32_t type, JsonRead& jsonbuf, void* data); - bool DemMsg_JsonWrite(uint32_t type, JsonWrite& jsonbuf, void* data); } diff --git a/demboyz/demofile/demofile.cpp b/demboyz/demofile/demofile.cpp index ce60ae2..4a0b76e 100644 --- a/demboyz/demofile/demofile.cpp +++ b/demboyz/demofile/demofile.cpp @@ -6,6 +6,14 @@ // DemoFileReader +size_t myfread ( void * ptr, size_t size, size_t count, FILE * stream ) +{ + size_t ret = fread(ptr, size, count, stream); + if (ret != count) + throw("fread error"); + return ret; +} + DemoFileReader::DemoFileReader(FILE* fp): m_demoFp(fp) { @@ -18,7 +26,7 @@ bool DemoFileReader::IsOk() const void DemoFileReader::ReadDemoHeader(demoheader_t& header) { - fread(&header, sizeof(demoheader_t), 1, m_demoFp); + myfread(&header, sizeof(demoheader_t), 1, m_demoFp); } int32_t DemoFileReader::ReadRawData(uint8_t* buffer, int32_t maxLength) @@ -26,7 +34,7 @@ int32_t DemoFileReader::ReadRawData(uint8_t* buffer, int32_t maxLength) FILE* fp = m_demoFp; int32_t size; - fread(&size, sizeof(int32_t), 1, fp); + myfread(&size, sizeof(int32_t), 1, fp); if (buffer && (maxLength < size)) { @@ -35,7 +43,7 @@ int32_t DemoFileReader::ReadRawData(uint8_t* buffer, int32_t maxLength) if (buffer) { - fread(buffer, 1, size, fp); + myfread(buffer, 1, size, fp); } else { @@ -49,104 +57,51 @@ Array DemoFileReader::ReadRawData(int32_t maxLength) FILE* fp = m_demoFp; int32_t size; - fread(&size, sizeof(int32_t), 1, fp); + myfread(&size, sizeof(int32_t), 1, fp); Array data; if (maxLength < size) { - return std::move(data); + return data; } data.reset(size); - fread(data.begin(), 1, size, fp); - return std::move(data); + myfread(data.begin(), 1, size, fp); + return data; } void DemoFileReader::ReadSequenceInfo(int32_t& seqNum1, int32_t& seqNum2) { FILE* fp = m_demoFp; - fread(&seqNum1, sizeof(int32_t), 1, fp); - fread(&seqNum2, sizeof(int32_t), 1, fp); + myfread(&seqNum1, sizeof(int32_t), 1, fp); + myfread(&seqNum2, sizeof(int32_t), 1, fp); } void DemoFileReader::ReadCmdInfo(democmdinfo_t& info) { - fread(&info, sizeof(democmdinfo_t), 1, m_demoFp); + myfread(&info, sizeof(democmdinfo_t), 1, m_demoFp); } void DemoFileReader::ReadCmdHeader(unsigned char& cmd, int32_t& tick) { FILE* fp = m_demoFp; - fread(&cmd, 1, sizeof(unsigned char), fp); - fread(&tick, 1, sizeof(int32_t), fp); + myfread(&cmd, 1, sizeof(unsigned char), fp); if (cmd > dem_lastcmd) { cmd = dem_stop; } + if (cmd != dem_stop) + myfread(&tick, 1, sizeof(int32_t), fp); } int32_t DemoFileReader::ReadUserCmd(int32_t& cmdNum, uint8_t* buffer, int32_t maxLength) { - fread(&cmdNum, sizeof(int32_t), 1, m_demoFp); + myfread(&cmdNum, sizeof(int32_t), 1, m_demoFp); return ReadRawData(buffer, maxLength); } Array DemoFileReader::ReadUserCmd(int32_t& cmdNum, int32_t maxLength) { - fread(&cmdNum, sizeof(int32_t), 1, m_demoFp); + myfread(&cmdNum, sizeof(int32_t), 1, m_demoFp); return ReadRawData(maxLength); } - -// DemoFileWriter - -DemoFileWriter::DemoFileWriter(FILE* fp) : - m_demoFp(fp) -{ -} - -FILE* DemoFileWriter::GetFp() const -{ - return m_demoFp; -} - -bool DemoFileWriter::IsOk() const -{ - return ferror(m_demoFp) == 0; -} - -void DemoFileWriter::WriteDemoHeader(const demoheader_t& header) -{ - fwrite(&header, sizeof(demoheader_t), 1, m_demoFp); -} - -void DemoFileWriter::WriteRawData(const uint8_t* buffer, int32_t length) -{ - FILE* fp = m_demoFp; - fwrite(&length, sizeof(int32_t), 1, fp); - fwrite(buffer, length, 1, fp); -} - -void DemoFileWriter::WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2) -{ - FILE* fp = m_demoFp; - fwrite(&seqNum1, sizeof(int32_t), 1, fp); - fwrite(&seqNum2, sizeof(int32_t), 1, fp); -} - -void DemoFileWriter::WriteCmdInfo(const democmdinfo_t& info) -{ - fwrite(&info, sizeof(democmdinfo_t), 1, m_demoFp); -} - -void DemoFileWriter::WriteCmdHeader(unsigned char cmd, int32_t tick) -{ - FILE* fp = m_demoFp; - fwrite(&cmd, sizeof(unsigned char), 1, fp); - fwrite(&tick, sizeof(int32_t), 1, fp); -} - -void DemoFileWriter::WriteUserCmd(int32_t cmdNum, const uint8_t* buffer, int32_t length) -{ - fwrite(&cmdNum, sizeof(int32_t), 1, m_demoFp); - WriteRawData(buffer, length); -} diff --git a/demboyz/demofile/demofile.h b/demboyz/demofile/demofile.h index daeb602..a2e7c06 100644 --- a/demboyz/demofile/demofile.h +++ b/demboyz/demofile/demofile.h @@ -26,21 +26,3 @@ public: private: FILE* m_demoFp; }; - -class DemoFileWriter -{ -public: - DemoFileWriter(FILE* fp); - - FILE* GetFp() const; - bool IsOk() const; - void WriteDemoHeader(const demoheader_t& header); - void WriteRawData(const uint8_t* buffer, int32_t length); - void WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2); - void WriteCmdInfo(const democmdinfo_t& info); - void WriteCmdHeader(unsigned char cmd, int32_t tick); - void WriteUserCmd(int32_t cmdNum, const uint8_t* buffer, int32_t length); - -private: - FILE* m_demoFp; -}; diff --git a/demboyz/demofile/demojson.cpp b/demboyz/demofile/demojson.cpp deleted file mode 100644 index 731030b..0000000 --- a/demboyz/demofile/demojson.cpp +++ /dev/null @@ -1,161 +0,0 @@ - -#include "demojson.h" -#include "demofile/demotypes.h" -#include - -bool DemoJsonReader::ReadDemoHeader(base::JsonReaderObject& reader, demoheader_t& header) -{ - base::JsonReaderObject object = reader.ReadObject("demoheader"); - object.ReadString("demofilestamp", header.demofilestamp, sizeof(header.demofilestamp)); - header.demoprotocol = object.ReadInt32("demoprotocol"); - header.networkprotocol = object.ReadInt32("networkprotocol"); - object.ReadString("servername", header.servername, sizeof(header.servername)); - object.ReadString("clientname", header.clientname, sizeof(header.clientname)); - object.ReadString("mapname", header.mapname, sizeof(header.mapname)); - object.ReadString("gamedirectory", header.gamedirectory, sizeof(header.gamedirectory)); - header.playback_time = object.ReadFloat("playback_time"); - header.playback_ticks = object.ReadInt32("playback_ticks"); - header.playback_frames = object.ReadInt32("playback_frames"); - header.signonlength = object.ReadInt32("signonlength"); - return !reader.HasReadError() && !object.HasReadError(); -} - -bool DemoJsonReader::ReadSequenceInfo(base::JsonReaderObject& reader, - int32_t& seqNum1, int32_t& seqNum2) -{ - seqNum1 = reader.ReadInt32("sequenceNum1"); - seqNum2 = reader.ReadInt32("sequenceNum2"); - return !reader.HasReadError(); -} - -bool DemoJsonReader::ReadCmdInfo(base::JsonReaderObject& reader, democmdinfo_t& info) -{ - democmdinfo_t::Split_t& split = info.u[0]; - base::JsonReaderObject object = reader.ReadObject("democmdinfo"); - split.flags = object.ReadInt32("flags"); - bool readError = ReadVector(object, "viewOrigin", split.viewOrigin); - readError |= ReadAngle(object, "viewAngles", split.viewAngles); - readError |= ReadAngle(object, "localViewAngles", split.localViewAngles); - readError |= ReadVector(object, "viewOrigin2", split.viewOrigin2); - readError |= ReadAngle(object, "viewAngles2", split.viewAngles2); - readError |= ReadAngle(object, "localViewAngles2", split.localViewAngles2); - return !readError && !reader.HasReadError() && !object.HasReadError(); -} - -bool DemoJsonReader::ReadCmdHeader(base::JsonReaderObject& reader, unsigned char& cmd, int32_t& tick) -{ - cmd = reader.ReadUInt32("cmd"); - tick = reader.ReadInt32("tick"); - return !reader.HasReadError(); -} - -bool DemoJsonReader::ReadUserCmd(base::JsonReaderObject& reader, int32_t& cmdNum, - uint8_t* buffer, int32_t length, int32_t& bytesRead) -{ - base::JsonReaderObject object = reader.ReadObject("usercmd"); - cmdNum = object.ReadInt32("cmd"); - bytesRead = object.ReadBytes("data", buffer, length); - return !object.HasReadError(); -} - -bool DemoJsonReader::ReadUserCmd(base::JsonReaderObject& reader, int32_t cmdNum, - Array& dest, int32_t maxLength) -{ - base::JsonReaderObject object = reader.ReadObject("usercmd"); - cmdNum = object.ReadInt32("cmd"); - - const int32_t numBytes = object.ReadBytes("data", nullptr, 0); - dest.reset(std::min(maxLength, numBytes)); - object.ReadBytes("data", dest.begin(), dest.length()); - return !object.HasReadError(); -} - -bool DemoJsonReader::ReadVector(base::JsonReaderObject& reader, const char* name, Vector& vec) -{ - base::JsonReaderObject object = reader.ReadObject(name); - vec.x = object.ReadFloat("x"); - vec.y = object.ReadFloat("y"); - vec.z = object.ReadFloat("z"); - return !reader.HasReadError() && !object.HasReadError(); -} - -bool DemoJsonReader::ReadAngle(base::JsonReaderObject& reader, const char* name, QAngle& angles) -{ - base::JsonReaderObject object = reader.ReadObject(name); - angles.x = object.ReadFloat("pitch"); - angles.y = object.ReadFloat("yaw"); - angles.z = object.ReadFloat("roll"); - return !reader.HasReadError() && !object.HasReadError(); -} - -void DemoJsonWriter::WriteDemoHeader(base::JsonWriterFile& writer, const demoheader_t& header) -{ - writer.StartObject("demoheader"); - writer.WriteString("demofilestamp", header.demofilestamp); - writer.WriteInt32("demoprotocol", header.demoprotocol); - writer.WriteInt32("networkprotocol", header.networkprotocol); - writer.WriteString("servername", header.servername); - writer.WriteString("clientname", header.clientname); - writer.WriteString("mapname", header.mapname); - writer.WriteString("gamedirectory", header.gamedirectory); - writer.WriteFloat("playback_time", header.playback_time); - writer.WriteInt32("playback_ticks", header.playback_ticks); - writer.WriteInt32("playback_frames", header.playback_frames); - writer.WriteInt32("signonlength", header.signonlength); - writer.EndObject(); -} - -void DemoJsonWriter::WriteSequenceInfo(base::JsonWriterFile& writer, - int32_t seqNum1, int32_t seqNum2) -{ - writer.WriteInt32("sequenceNum1", seqNum1); - writer.WriteInt32("sequenceNum2", seqNum2); -} - -void DemoJsonWriter::WriteCmdInfo(base::JsonWriterFile& writer, - const democmdinfo_t& info) -{ - const democmdinfo_t::Split_t& split = info.u[0]; - writer.StartObject("democmdinfo"); - writer.WriteInt32("flags", split.flags); - WriteVector(writer, "viewOrigin", split.viewOrigin); - WriteAngle(writer, "viewAngles", split.viewAngles); - WriteAngle(writer, "localViewAngles", split.localViewAngles); - WriteVector(writer, "viewOrigin2", split.viewOrigin2); - WriteAngle(writer, "viewAngles2", split.viewAngles2); - WriteAngle(writer, "localViewAngles2", split.localViewAngles2); - writer.EndObject(); -} - -void DemoJsonWriter::WriteCmdHeader(base::JsonWriterFile& writer, unsigned char cmd, int32_t tick) -{ - writer.WriteUInt32("cmd", cmd); - writer.WriteInt32("tick", tick); -} - -void DemoJsonWriter::WriteUserCmd(base::JsonWriterFile& writer, - int32_t cmdNum, const uint8_t* buffer, int32_t length) -{ - writer.StartObject("usercmd"); - writer.WriteInt32("cmd", cmdNum); - writer.WriteBytes("data", buffer, length); - writer.EndObject(); -} - -void DemoJsonWriter::WriteVector(base::JsonWriterFile& writer, const char* name, const Vector& vec) -{ - writer.StartObject(name); - writer.WriteFloat("x", vec.x); - writer.WriteFloat("y", vec.y); - writer.WriteFloat("z", vec.z); - writer.EndObject(); -} - -void DemoJsonWriter::WriteAngle(base::JsonWriterFile& writer, const char* name, const QAngle& angles) -{ - writer.StartObject(name); - writer.WriteFloat("pitch", angles.x); - writer.WriteFloat("yaw", angles.y); - writer.WriteFloat("roll", angles.z); - writer.EndObject(); -} diff --git a/demboyz/demofile/demojson.h b/demboyz/demofile/demojson.h deleted file mode 100644 index fe86218..0000000 --- a/demboyz/demofile/demojson.h +++ /dev/null @@ -1,36 +0,0 @@ - -#pragma once - -#include "base/array.h" -#include "base/jsonfile.h" -#include -#include - -struct demoheader_t; -struct democmdinfo_t; -class Vector; -class QAngle; - -namespace DemoJsonReader -{ - bool ReadDemoHeader(base::JsonReaderObject& reader, demoheader_t& header); - bool ReadSequenceInfo(base::JsonReaderObject& reader, int32_t& seqNum1, int32_t& seqNum2); - bool ReadCmdInfo(base::JsonReaderObject& reader, democmdinfo_t& info); - bool ReadCmdHeader(base::JsonReaderObject& reader, unsigned char& cmd, int32_t& tick); - bool ReadUserCmd(base::JsonReaderObject& reader, int32_t& cmdNum, - uint8_t* buffer, int32_t length, int32_t& bytesRead); - bool ReadUserCmd(base::JsonReaderObject& reader, int32_t cmdNum, Array& dest, int32_t maxLength); - bool ReadVector(base::JsonReaderObject& reader, const char* name, Vector& vec); - bool ReadAngle(base::JsonReaderObject& reader, const char* name, QAngle& angle); -} - -namespace DemoJsonWriter -{ - void WriteDemoHeader(base::JsonWriterFile& writer, const demoheader_t& header); - void WriteSequenceInfo(base::JsonWriterFile& writer, int32_t seqNum1, int32_t seqNum2); - void WriteCmdInfo(base::JsonWriterFile& writer, const democmdinfo_t& info); - void WriteCmdHeader(base::JsonWriterFile& writer, unsigned char cmd, int32_t tick); - void WriteUserCmd(base::JsonWriterFile& writer, int32_t cmdNum, const uint8_t* buffer, int32_t length); - void WriteVector(base::JsonWriterFile& writer, const char* name, const Vector& vec); - void WriteAngle(base::JsonWriterFile& writer, const char* name, const QAngle& angle); -} diff --git a/demboyz/game/gameevents.cpp b/demboyz/game/gameevents.cpp index 85e884d..3fca682 100644 --- a/demboyz/game/gameevents.cpp +++ b/demboyz/game/gameevents.cpp @@ -2,12 +2,12 @@ #include "gameevents.h" #include "base/bitfile.h" #include +#include namespace GameEvents { - EventDataMap ParseEventData(bf_read& bitbuf, const EventDescriptor& desc, std::vector& stringMem) + EventDataMap ParseEventData(bf_read& bitbuf, const EventDescriptor& desc) { - stringMem.reserve(stringMem.size() + MAX_EVENT_BYTES); EventDataMap data; char tempStr[MAX_EVENT_BYTES]; for (const EventValue& value : desc.values) @@ -18,13 +18,9 @@ namespace GameEvents { case EventValueType::String: { - int length = 0; - const bool ok = bitbuf.ReadString(tempStr, sizeof(tempStr), false, &length); + const bool ok = bitbuf.ReadString(tempStr, sizeof(tempStr), false); assert(ok); - length += 1; // for null terminator - - eventData.strOffset = stringMem.size(); - stringMem.insert(stringMem.end(), tempStr, tempStr + length + 1); + eventData.strValue.assign(tempStr); break; } case EventValueType::Float: @@ -61,51 +57,41 @@ namespace GameEvents return data; } - void PrintEventData(bf_read& bitbuf, const EventDescriptor& desc) + void PrintEvent(const char* name, EventDataMap& data) { - char tempStr[MAX_EVENT_BYTES]; - printf("%s:\n", desc.name); - for (const EventValue& value : desc.values) + std::cout << "[EVENT] " << name << "\n"; + for (const auto& d : data) { - printf(" %s: ", value.name); - switch(value.type) + std::cout << "\t" << d.first << ": "; + switch(d.second.type) { - case EventValueType::String: + case GameEvents::EventValueType::String: { - const bool ok = bitbuf.ReadString(tempStr, sizeof(tempStr), false, nullptr); - assert(ok); - printf("%s\n", tempStr); - break; - } - case EventValueType::Float: + std::cout << d.second.strValue << "\n"; + } break; + case GameEvents::EventValueType::Float: { - printf("%f\n", bitbuf.ReadFloat()); - break; - } - case EventValueType::Long: + std::cout << d.second.flValue << "\n"; + } break; + case GameEvents::EventValueType::Long: { - printf("%i\n", bitbuf.ReadSBitLong(32)); - break; - } - case EventValueType::Short: + std::cout << d.second.i32Value << "\n"; + } break; + case GameEvents::EventValueType::Short: { - printf("%i\n", bitbuf.ReadSBitLong(16)); - break; - } - case EventValueType::Byte: + std::cout << d.second.i16Value << "\n"; + } break; + case GameEvents::EventValueType::Byte: { - printf("%u\n", bitbuf.ReadUBitLong(8)); - break; - } - case EventValueType::Bool: + std::cout << d.second.u8Value << "\n"; + } break; + case GameEvents::EventValueType::Bool: { - printf("%s\n", (bitbuf.ReadOneBit() != 0) ? "true" : "false"); - break; - } - case EventValueType::Local: + std::cout << d.second.bValue << "\n"; + } break; default: - assert(false); - break; + { + } break; } } } diff --git a/demboyz/game/gameevents.h b/demboyz/game/gameevents.h index 4df4695..06e7d16 100644 --- a/demboyz/game/gameevents.h +++ b/demboyz/game/gameevents.h @@ -8,8 +8,6 @@ #include #include -//#define WIP_GAMEEVENTS - class bf_read; namespace GameEvents @@ -43,16 +41,16 @@ namespace GameEvents EventValueType type; union { - ptrdiff_t strOffset; float flValue; int32_t i32Value; int16_t i16Value; uint8_t u8Value; bool bValue; }; + std::string strValue; }; using EventDataMap = std::map; - EventDataMap ParseEventData(bf_read& bitbuf, const EventDescriptor& desc, std::vector& stringMem); - void PrintEventData(bf_read& bitbuf, const EventDescriptor& desc); + EventDataMap ParseEventData(bf_read& bitbuf, const EventDescriptor& desc); + void PrintEvent(const char* name, EventDataMap& data); } diff --git a/demboyz/game/logic.cpp b/demboyz/game/logic.cpp new file mode 100644 index 0000000..be2a1fe --- /dev/null +++ b/demboyz/game/logic.cpp @@ -0,0 +1,196 @@ + +#include "logic.h" +#include "netmessages/svc_serverinfo.h" +#include +#include + + +Logic::Logic(SourceGameContext* context): + context(context) +{ + //memset(clients, 0, sizeof(clients)); + data = json({ + {"header", {}}, + {"serverinfo", {}}, + {"players", {}}, + {"chat", {}} + }); +} + +Logic::~Logic() +{ +} + +void Logic::Start() +{ + data["demoheader"] = json({ + {"demofilestamp", context->header.demofilestamp}, + {"demoprotocol", context->header.demoprotocol}, + {"networkprotocol", context->header.networkprotocol}, + {"servername", context->header.servername}, + {"clientname", context->header.clientname}, + {"mapname", context->header.mapname}, + {"gamedirectory", context->header.gamedirectory}, + {"playback_time", context->header.playback_time}, + {"playback_ticks", context->header.playback_ticks}, + {"playback_frames", context->header.playback_frames}, + {"signonlength", context->header.signonlength} + }); + + // std::cout << data.dump(2, ' ', false, json::error_handler_t::replace) << "\n"; +} + +void Logic::Finish(bool dirty) +{ + // disconnect all remaining clients + for (int client = 0; client < MAX_PLAYERS; client++) + { + if (clients[client].connected == -1) + continue; + + OnClientDisconnected(client, "#demoend"); + } + + // fix header if demo is corrupt + data["demoheader"]["dirty"] = dirty; + if (dirty) + { + data["demoheader"]["playback_ticks"] = curTick; + data["demoheader"]["playback_time"] = curTick * context->fTickRate; + data["demoheader"]["playback_frames"] = context->curFrame; + } + + std::string out = data.dump(2, ' ', false, json::error_handler_t::replace); + out.append("\n"); + fwrite(out.c_str(), out.size(), 1, context->outputFp); +} + +void Logic::OnServerInfo(NetMsg::SVC_ServerInfo* serverInfo) +{ + char mapMD5[32+1]; + for (int i = 0; i < 16; ++i) + { + mapMD5[(i * 2)] = "0123456789ABCDEF"[serverInfo->mapMD5[i] / 16]; + mapMD5[(i * 2) + 1] = "0123456789ABCDEF"[serverInfo->mapMD5[i] % 16]; + } + mapMD5[32] = 0; + + json info = { + {"protocol", serverInfo->protocol}, + {"serverCount", serverInfo->serverCount}, + {"isHLTV", serverInfo->isHLTV}, + {"isDedicated", serverInfo->isDedicated}, + {"clientCRC", serverInfo->clientCRC}, + {"maxClasses", serverInfo->maxClasses}, + {"mapCRC", serverInfo->mapCRC}, + {"mapMD5", mapMD5}, + {"playerSlot", serverInfo->playerSlot}, + {"maxClients", serverInfo->maxClients}, + {"tickInterval", serverInfo->tickInterval}, + {"os", serverInfo->os}, + {"gameDir", serverInfo->gameDir}, + {"mapName", serverInfo->mapName}, + {"skyName", serverInfo->skyName}, + {"hostName", serverInfo->hostName}, + {"isReplay", serverInfo->isReplay} + }; + data["serverinfo"] = info; + + // std::cout << info.dump(2, ' ', false, json::error_handler_t::replace) << "\n"; +} + +void Logic::OnClientConnected(int client) +{ + assert(clients[client].connected == -1); + + const auto& info = context->players[client].info; + auto& player = data["players"][info.guid]; + + if (player.is_null()) + { + player = json({ + {"names", {}}, + {"sprays", {}}, + {"disconnect_reasons", {}}, + {"playtime", 0}, + {"voicetime", 0.0f} + }); + } + + clients[client].connected = curTick; + + OnClientSettingsChanged(client); +} + +void Logic::OnClientDisconnected(int client, const char* reason) +{ + assert(clients[client].connected != -1); + + const auto& info = context->players[client].info; + auto& player = data["players"][info.guid]; + + // cumulative play time + unsigned int playtime = curTick - clients[client].connected; + playtime += player["playtime"].get(); + player["playtime"] = playtime; + + // cumulative voice chat time + float voicetime = clients[client].voiceTime; + voicetime += player["voicetime"].get(); + player["voicetime"] = voicetime; + + player["disconnect_reasons"] += reason; + + clients[client].connected = -1; +} + +void Logic::OnClientSettingsChanged(int client) +{ + assert(clients[client].connected != -1); + + const auto& info = context->players[client].info; + auto& player = data["players"][info.guid]; + + // list of names + if (std::find(player["names"].begin(), player["names"].end(), info.name) == player["names"].end()) + player["names"].push_back(info.name); + + // list of spray hashes + if (info.customFiles[0]) + { + char logohex[16]; + sprintf(logohex, "%08x", info.customFiles[0]); + if (std::find(player["sprays"].begin(), player["sprays"].end(), logohex) == player["sprays"].end()) + player["sprays"].push_back(logohex); + } +} + +void Logic::OnClientChat(int client, bool bWantsToChat, const char* msgName, const char* msgSender, const char* msgText) +{ + const auto& info = context->players[client].info; + json chat = { + {"tick", curTick}, + {"steamid", info.guid}, + {"msgName", msgName}, + {"msgSender", msgSender}, + {"msgText", msgText} + }; + + data["chat"] += chat; +} + +void Logic::OnClientVoiceChat(int client, float length) +{ + assert(clients[client].connected != -1); + + clients[client].voiceTime += length; +} + +void Logic::OnVoiceCodec(const char* codec, int quality, int sampleRate) +{ + data["voice_init"] = json({ + {"codec", codec}, + {"quality", quality}, + {"sampleRate", sampleRate} + }); +} \ No newline at end of file diff --git a/demboyz/game/logic.h b/demboyz/game/logic.h new file mode 100644 index 0000000..3c78043 --- /dev/null +++ b/demboyz/game/logic.h @@ -0,0 +1,39 @@ + +#pragma once + +#include "base/json.hpp" +#include "game/sourcecontext.h" + +using nlohmann::json; + +namespace NetMsg +{ + struct SVC_ServerInfo; +} + +struct Logic +{ + Logic(SourceGameContext* context); + ~Logic(); + + void Start(); + void Finish(bool dirty); + + struct + { + int32_t connected = -1; + float voiceTime = 0.0f; + } clients[MAX_PLAYERS]; + + void OnServerInfo(NetMsg::SVC_ServerInfo* serverInfo); + void OnClientConnected(int client); + void OnClientDisconnected(int client, const char* reason); + void OnClientSettingsChanged(int client); + void OnClientChat(int client, bool bWantsToChat, const char* msgName, const char* msgSender, const char* msgText); + void OnClientVoiceChat(int client, float length); + void OnVoiceCodec(const char* codec, int quality, int sampleRate); + + int32_t curTick = 0; + SourceGameContext* context = nullptr; + json data; +}; diff --git a/demboyz/game/sourcecontext.cpp b/demboyz/game/sourcecontext.cpp index fb4737a..ae69698 100644 --- a/demboyz/game/sourcecontext.cpp +++ b/demboyz/game/sourcecontext.cpp @@ -1,16 +1,177 @@ #include "sourcecontext.h" +#include "netmessages/netmath.h" #include "netmessages/svc_gameeventlist.h" +#include "netmessages/usermessages.h" +#include "netmessages/svc_usermessage.h" +#include "netmessages/svc_serverinfo.h" +#include "sourcesdk/bitbuf.h" +#include "game/gameevents.h" +#include "game/logic.h" +#include "io/voicewriter/voicedatawriter.h" +#include -SourceGameContext::SourceGameContext(): - protocol(0), - gameEventList(nullptr) +#include "netmessages/svc_voiceinit.h" +#include "netmessages/svc_voicedata.h" + +SourceGameContext::SourceGameContext(std::string outputDir, std::string outputDirVoice): + outputDir(outputDir), + outputDirVoice(outputDirVoice) { + stringTables = new StringTableContainer(this); + memset(players, 0, sizeof(players)); } SourceGameContext::~SourceGameContext() { + delete logic; + logic = nullptr; + protocol = 0; delete gameEventList; gameEventList = nullptr; + delete stringTables; + stringTables = nullptr; + + fclose(outputFp); +} + +bool SourceGameContext::init() +{ + outputFp = fopen((outputDir + "/out.json").c_str(), "wb"); + if (!outputFp) + { + fprintf(stderr, "Error: Could not open out.json\n"); + return false; + } + + voiceWriter = new VoiceDataWriter(this, outputDirVoice.c_str()); + logic = new Logic(this); + return true; +} + +void SourceGameContext::Start() +{ + logic->Start(); + voiceWriter->Start(); +} + +void SourceGameContext::Finish(bool dirty) +{ + logic->Finish(dirty); + voiceWriter->Finish(); +} + +void SourceGameContext::StartCommandPacket(const CommandPacket& packet) +{ + curFrame += (packet.cmd == dem_packet); + + if(curTick == -1 && packet.tick > 0) + return; + + curTick = packet.tick; + logic->curTick = curTick; + + voiceWriter->StartCommandPacket(packet); +} + +void SourceGameContext::EndCommandPacket(const PacketTrailingBits& trailingBits) +{ + if(curTick == -1) + return; + + voiceWriter->EndCommandPacket(trailingBits); +} + +void SourceGameContext::OnNetPacket(NetPacket& packet) +{ + if(packet.type == NetMsg::svc_ServerInfo) + { + NetMsg::SVC_ServerInfo* serverInfo = static_cast(packet.data); + fTickInterval = serverInfo->tickInterval; + fTickRate = 1.f / fTickInterval; + logic->OnServerInfo(serverInfo); + } + + else if(packet.type == NetMsg::svc_UserMessage) + { + NetMsg::SVC_UserMessage* umsg = static_cast(packet.data); + + bf_read msg(umsg->data.get(), math::BitsToBytes(umsg->dataLengthInBits)); + + if(umsg->msgType == UserMsg::SayText2) + { + int client = msg.ReadByte(); + bool bWantsToChat = msg.ReadByte(); + + char msgName[2048] = {0}; + char msgSender[2048] = {0}; + char msgText[2048] = {0}; + + msg.ReadString(msgName, sizeof(msgName)); + msg.ReadString(msgSender, sizeof(msgSender)); + msg.ReadString(msgText, sizeof(msgText)); + + logic->OnClientChat(client, bWantsToChat, msgName, msgSender, msgText); + } + } + + else if(packet.type == NetMsg::svc_VoiceInit || packet.type == NetMsg::svc_VoiceData) + { + voiceWriter->OnNetPacket(packet); + } + +} + +void SourceGameContext::OnGameEvent(const char *name, GameEvents::EventDataMap &data) +{ + // GameEvents::PrintEvent(name, data); + + if (strcmp(name, "player_disconnect") == 0) + { + int userid = data["userid"].i16Value; + for (int client = 0; client < MAX_PLAYERS; client++) + { + auto& p = players[client]; + if (!p.connected || p.info.userID != userid) + continue; + + p.connected = false; + logic->OnClientDisconnected(client, data["reason"].strValue.c_str()); + } + } +} + +void SourceGameContext::OnStringtable(StringTable* table) +{ + if (table->tableName == "userinfo") + { + table->callback = std::bind(&SourceGameContext::UserInfoChanged, this, std::placeholders::_1, std::placeholders::_2); + } +} + +void SourceGameContext::UserInfoChanged(int tableIdx, int entryIdx) +{ + StringTableEntry &entry = stringTables->tables[tableIdx].entries[entryIdx]; + + int client = std::stoi(entry.string); + player_info_t *info = (player_info_t *)entry.data.data(); + + if (entry.data.size() != sizeof(player_info_t)) + { + memset(&players[client].info, 0, sizeof(player_info_t)); + players[client].connected = false; + return; + } + + memcpy(&players[client].info, info, sizeof(player_info_t)); + + if (!players[client].connected) + logic->OnClientConnected(client); + else + logic->OnClientSettingsChanged(client); + + players[client].connected = true; + + //std::cout << client << " (" << info->userID << "): N:" << info->name << " G:" << info->guid << " F:" << info->friendsID << "\n"; } diff --git a/demboyz/game/sourcecontext.h b/demboyz/game/sourcecontext.h index 8140af0..0834bc2 100644 --- a/demboyz/game/sourcecontext.h +++ b/demboyz/game/sourcecontext.h @@ -1,18 +1,111 @@ #pragma once +#include "stringtables.h" +#include "game/gameevents.h" +#include "demofile/demotypes.h" #include namespace NetMsg { struct SVC_GameEventList; } +struct Logic; +class VoiceDataWriter; + +struct CommandPacket +{ + unsigned char cmd; + int32_t tick; + + void* data; +}; + +struct NetPacket +{ + int32_t type; + void* data; +}; + +struct PacketTrailingBits +{ + uint32_t numTrailingBits; + uint32_t value; +}; + +#define MAX_PLAYERS 65 +#define MAX_PLAYER_NAME_LENGTH 32 +#define SIGNED_GUID_LEN 32 +#define MAX_CUSTOM_FILES 4 + +// Engine player info, no game related infos here +// If you change this, change the two byteswap defintions: +// cdll_client_int.cpp and cdll_engine_int.cpp +typedef struct player_info_s +{ + // scoreboard information + char name[MAX_PLAYER_NAME_LENGTH]; + // local server user ID, unique while server is running + int userID; + // global unique player identifer + char guid[SIGNED_GUID_LEN + 1]; + // friends identification number + uint32_t friendsID; + // friends name + char friendsName[MAX_PLAYER_NAME_LENGTH]; + // true, if player is a bot controlled by game.dll + bool fakeplayer; + // true if player is the HLTV proxy + bool ishltv; +#if defined( REPLAY_ENABLED ) + // true if player is the Replay proxy + bool isreplay; +#endif + // custom files CRC for this player + uint32_t customFiles[MAX_CUSTOM_FILES]; + // this counter increases each time the server downloaded a new file + unsigned char filesDownloaded; +} player_info_t; struct SourceGameContext { - SourceGameContext(); + SourceGameContext(std::string outputDir, std::string outputDirVoice); ~SourceGameContext(); + bool init(); + void Start(); + void Finish(bool dirty); + + void StartCommandPacket(const CommandPacket& packet); + void EndCommandPacket(const PacketTrailingBits& trailingBits); + bool IgnoreNetPacketType(int32_t type); + + void OnNetPacket(NetPacket& packet); + void OnGameEvent(const char *name, GameEvents::EventDataMap &data); + void OnStringtable(StringTable* table); + void UserInfoChanged(int tableIdx, int entryIdx); + + std::string outputDir; + std::string outputDirVoice; + + FILE* outputFp; + Logic* logic; + + demoheader_t header; int16_t protocol; - NetMsg::SVC_GameEventList* gameEventList; + NetMsg::SVC_GameEventList* gameEventList = nullptr; + StringTableContainer* stringTables = nullptr; + VoiceDataWriter* voiceWriter = nullptr; + + int32_t curTick = -1; + int32_t curFrame = -1; + + float fTickInterval = -1.f; + float fTickRate = -1.f; + + struct + { + bool connected; + player_info_t info; + } players[MAX_PLAYERS]; }; diff --git a/demboyz/game/stringtables.cpp b/demboyz/game/stringtables.cpp new file mode 100644 index 0000000..a770947 --- /dev/null +++ b/demboyz/game/stringtables.cpp @@ -0,0 +1,174 @@ + +#include "base/bitfile.h" +#include "stringtables.h" +#include "game/sourcecontext.h" +#include + +static size_t strlcpy(char * dst, const char * src, size_t maxlen) { + const size_t srclen = strlen(src); + if (srclen + 1 < maxlen) { + memcpy(dst, src, srclen + 1); + } else if (maxlen != 0) { + memcpy(dst, src, maxlen - 1); + dst[maxlen-1] = '\0'; + } + return srclen; +} + +StringTableContainer::StringTableContainer(SourceGameContext *context): + context(context) +{ +} + +StringTable *StringTableContainer::GetStringTable(const char *name, bool create) +{ + StringTable *table = nullptr; + for (auto& t : tables) + { + if (t.tableName.compare(name) == 0) + { + table = &t; + break; + } + } + if (!table && create) + { + StringTable ttable; + tables.emplace_back(ttable); + table = &tables.back(); + table->id = tables.size() - 1; + table->tableName.assign(name); + table->entries.clear(); + context->OnStringtable(table); + } + return table; +} + +void StringTableContainer::DumpAll() +{ + for (auto& t : tables) + { + std::cout << "[STRINGTABLE] " << t.tableName << " (" << t.entries.size() << ")\n"; + int idx = 0; + for (auto& e : t.entries) + { + std::cout << idx++ << ":\t" << e.string << " (" << e.data << ")\n"; + } + std::cout << "\n"; + } +} + +StringTableEntry *StringTable::FindEntry(const char *string) +{ + for (auto& e : entries) + { + if (e.string.compare(string) == 0) + return &e; + } + return nullptr; +} + +#define SUBSTRING_BITS 5 +struct StringHistoryEntry +{ + char string[(1 << SUBSTRING_BITS)]; +}; + +void StringTable::AddEntry(StringTableEntry *entry) +{ + StringTableEntry *e = FindEntry(entry->string.c_str()); + if (!e) + { + entries.emplace_back(*entry); + return; + } + + e->string.assign(entry->string); + e->data.assign(entry->data); +} + +void StringTable::ParseUpdate(bf_read& bitbuf, int numEntries, SourceGameContext& context) +{ + std::vector history; + int entryIndex = -1; + for (int i = 0; i < numEntries; ++i) + { + entryIndex++; + + if (bitbuf.ReadOneBit() == 0) + { + entryIndex = bitbuf.ReadUBitLong(entryBits); + } + + const char *pEntry = NULL; + char entry[1024+1]; + char substr[1024]; + if (bitbuf.ReadOneBit() != 0) + { + bool substringcheck = bitbuf.ReadOneBit() != 0; + if (substringcheck) + { + int index = bitbuf.ReadUBitLong(5); + int bytestocopy = bitbuf.ReadUBitLong(SUBSTRING_BITS); + strlcpy(entry, history.at(index).string, MIN((int)sizeof(StringHistoryEntry::string), bytestocopy + 1)); + bitbuf.ReadString(substr, sizeof(substr)); + strncat(entry, substr, sizeof(entry) - 1); + } + else + { + bitbuf.ReadString(entry, sizeof(entry)); + } + pEntry = entry; + } + + const int MAX_USERDATA_BITS = 14; + unsigned char tempbuf[(1 << MAX_USERDATA_BITS)] = { 0 }; + const void *pUserData = NULL; + int nUserDataBytes = 0; + if (bitbuf.ReadOneBit() != 0) + { + if (isUserDataFixedSize) + { + bitbuf.ReadBits(tempbuf, userDataSizeBits); + } + else + { + nUserDataBytes = bitbuf.ReadUBitLong(MAX_USERDATA_BITS); + bitbuf.ReadBytes(tempbuf, nUserDataBytes); + } + pUserData = tempbuf; + } + + if (pEntry == NULL) + { + pEntry = ""; + } + + if (entryIndex >= (int)entries.size()) + { + StringTableEntry entry = {}; + entry.string.assign(pEntry); + entries.emplace_back(entry); +} + else + { + pEntry = entries[entryIndex].string.c_str(); + } + + assert(entryIndex < (int)entries.size()); + + entries[entryIndex].data.assign((const char *)pUserData, nUserDataBytes); + + if (callback) + callback(id, entryIndex); + + if (history.size() > 31) + { + history.erase(history.begin()); + } + + StringHistoryEntry she; + strlcpy(she.string, pEntry, sizeof(she.string)); + history.emplace_back(she); + } +} \ No newline at end of file diff --git a/demboyz/game/stringtables.h b/demboyz/game/stringtables.h new file mode 100644 index 0000000..05ade75 --- /dev/null +++ b/demboyz/game/stringtables.h @@ -0,0 +1,48 @@ + +#pragma once + +#include +#include +#include +#include + +class bf_read; +class SourceGameContext; + +struct StringTableEntry +{ + std::string string; + std::string data; +}; + +struct StringTable +{ + int id; + std::string tableName; + uint16_t maxEntries; + bool isUserDataFixedSize; + uint16_t userDataSize; + uint8_t userDataSizeBits; + int entryBits; + + void ParseUpdate(bf_read& bitbuf, int numEntries, SourceGameContext& context); + + void AddEntry(StringTableEntry *entry); + StringTableEntry *FindEntry(const char *string); + + std::vector entries; + std::function callback; +}; + +struct StringTableContainer +{ + StringTableContainer(SourceGameContext *context); + + StringTable *GetStringTable(const char *name, bool create); + + void DumpAll(); + + SourceGameContext *context; + std::vector tables; +}; + diff --git a/demboyz/io/conlogwriter.cpp b/demboyz/io/conlogwriter.cpp deleted file mode 100644 index b2546f1..0000000 --- a/demboyz/io/conlogwriter.cpp +++ /dev/null @@ -1,60 +0,0 @@ - -#include "idemowriter.h" -#include "netmessages/nethandlers.h" -#include "demofile/demotypes.h" -#include - -class ConLogWriter: public IDemoWriter -{ -public: - ConLogWriter(FILE* outputFp); - - virtual void StartWriting(demoheader_t& header) override final; - virtual void EndWriting() override final; - - virtual void StartCommandPacket(const CommandPacket& packet) override final; - virtual void EndCommandPacket(const PacketTrailingBits& trailingBits) override final; - - virtual void WriteNetPacket(NetPacket& packet, SourceGameContext& context) override final; - -private: - FILE* m_outputFp; -}; - -IDemoWriter* IDemoWriter::CreateConLogWriter(void* outputFp) -{ - return new ConLogWriter(reinterpret_cast(outputFp)); -} - -ConLogWriter::ConLogWriter(FILE* outputFp): - m_outputFp(outputFp) -{ -} - -void ConLogWriter::StartWriting(demoheader_t& header) -{ -} - -void ConLogWriter::EndWriting() -{ - fflush(m_outputFp); -} - -void ConLogWriter::StartCommandPacket(const CommandPacket& packet) -{ -} - -void ConLogWriter::EndCommandPacket(const PacketTrailingBits& trailingBits) -{ -} - -void ConLogWriter::WriteNetPacket(NetPacket& packet, SourceGameContext& context) -{ - std::ostringstream ss; - NetHandlers::NetMsg_ToString(packet.type, ss, packet.data); - if (ss.tellp() > 0) - { - ss << "\n"; - fputs(ss.str().c_str(), m_outputFp); - } -} diff --git a/demboyz/io/demoreader.cpp b/demboyz/io/demoreader.cpp new file mode 100644 index 0000000..c3b0b0c --- /dev/null +++ b/demboyz/io/demoreader.cpp @@ -0,0 +1,107 @@ +#include "demoreader.h" +#include "demofile/demofile.h" +#include "demofile/demotypes.h" + +#include "game/sourcecontext.h" +#include "netmessages/nethandlers.h" +#include "netmessages/netcontants.h" +#include "demmessages/demhandlers.h" +#include "demmessages/dem_stringtables.h" +#include "sourcesdk/bitbuf.h" +#include + +PacketTrailingBits ParsePacket(uint8_t* packet, size_t length, + SourceGameContext& context, + const NetHandlers::NetDataStructArray& netDataStructs) +{ + assert(length <= NET_MAX_PAYLOAD); + bf_read bitbuf(packet, length); + NetPacket netPacket; + while (bitbuf.GetNumBitsLeft() >= NETMSG_TYPE_BITS) + { + netPacket.type = bitbuf.ReadUBitLong(NETMSG_TYPE_BITS); + netPacket.data = netDataStructs[netPacket.type]; + NetHandlers::NetMsg_BitRead(netPacket.type, bitbuf, context, netPacket.data); + context.OnNetPacket(netPacket); + } + + PacketTrailingBits trailingBits; + trailingBits.numTrailingBits = bitbuf.GetNumBitsLeft(); + if (trailingBits.numTrailingBits) + { + trailingBits.value = bitbuf.ReadUBitLong(trailingBits.numTrailingBits); + } + else + { + trailingBits.value = 0; + } + return trailingBits; +} + +bool DemoReader::ProcessDem(std::FILE* inputFp, SourceGameContext* context) +{ + NetHandlers::NetDataStructArray netDataStructs; + DemHandlers::DemDataStructArray demDataStructs; + NetHandlers::CreateNetMsgStructs(netDataStructs); + DemHandlers::CreateDemMsgStructs(demDataStructs); + + DemoFileReader reader(inputFp); + { + reader.ReadDemoHeader(context->header); + context->protocol = context->header.networkprotocol; + context->Start(); + } + + bool dirty = false; + try + { + CommandPacket packet; + do + { + reader.ReadCmdHeader(packet.cmd, packet.tick); + packet.data = demDataStructs[packet.cmd]; + DemHandlers::DemMsg_FileRead(packet.cmd, reader, packet.data); + + PacketTrailingBits trailingBits = PacketTrailingBits(); + context->StartCommandPacket(packet); + + if (packet.cmd == dem_packet || packet.cmd == dem_signon) + { + Array buffer = reader.ReadRawData(NET_MAX_PAYLOAD); + trailingBits = ParsePacket(buffer.begin(), buffer.length(), *context, netDataStructs); + } + + else if (packet.cmd == dem_stringtables) + { + DemMsg::Dem_StringTables *stringTables = (DemMsg::Dem_StringTables *)packet.data; + for (const auto& s : stringTables->stringtables) + { + StringTable *table = context->stringTables->GetStringTable(s.tableName.c_str(), false); + if (!table) + continue; + for (const auto& e : s.entries) + { + StringTableEntry entry; + entry.string.assign(e.entryName); + entry.data.assign(e.data.begin(), e.data.end()); + table->AddEntry(&entry); + } + } + } + + context->EndCommandPacket(trailingBits); + } while (packet.cmd != dem_stop); + } + catch(const char *e) + { + dirty = true; + fprintf(stderr, "Error: %s\n", e); + } + + context->Finish(dirty); + + DemHandlers::DestroyDemMsgStructs(demDataStructs); + NetHandlers::DestroyNetMsgStructs(netDataStructs); + + return !dirty; +} diff --git a/demboyz/io/demoreader.h b/demboyz/io/demoreader.h index 3de4bb9..f6eddbc 100644 --- a/demboyz/io/demoreader.h +++ b/demboyz/io/demoreader.h @@ -1,12 +1,9 @@ - #pragma once +#include "game/sourcecontext.h" #include -class IDemoWriter; - namespace DemoReader { - void ProcessDem(std::FILE* inputFp, IDemoWriter* writer); - void ProcessJson(std::FILE* inputFp, IDemoWriter* writer); + bool ProcessDem(std::FILE* inputFp, SourceGameContext* context); } diff --git a/demboyz/io/demowriter.cpp b/demboyz/io/demowriter.cpp deleted file mode 100644 index e9be07d..0000000 --- a/demboyz/io/demowriter.cpp +++ /dev/null @@ -1,108 +0,0 @@ - -#include "idemowriter.h" -#include "demofile/demotypes.h" -#include "demofile/demofile.h" -#include "netmessages/nethandlers.h" -#include "netmessages/netcontants.h" -#include "demmessages/demhandlers.h" -#include "sourcesdk/bitbuf.h" -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#endif -#include - -int truncate(FILE* fp, int relative_offset) -{ - fflush(fp); -#ifdef _WIN32 - const int fd = _fileno(fp); -#else - const int fd = fileno(fp); -#endif - struct stat statbuf; - fstat(fd, &statbuf); -#ifdef _WIN32 - return _chsize_s(fd, statbuf.st_size + relative_offset); -#else - return ftruncate(fd, statbuf.st_size + relative_offset); -#endif -} - -class DemoWriter: public IDemoWriter -{ -public: - DemoWriter(FILE* outputFp); - - virtual void StartWriting(demoheader_t& header) override final; - virtual void EndWriting() override final; - - virtual void StartCommandPacket(const CommandPacket& packet) override final; - virtual void EndCommandPacket(const PacketTrailingBits& trailingBits) override final; - - virtual void WriteNetPacket(NetPacket& packet, SourceGameContext& context) override final; - -private: - DemoFileWriter m_writer; - bf_write m_cmdPacketBuf; - std::unique_ptr m_packetBuffer; -}; - -IDemoWriter* IDemoWriter::CreateDemoWriter(void* outputFp) -{ - return new DemoWriter(reinterpret_cast(outputFp)); -} - -DemoWriter::DemoWriter(FILE* outputFp): - m_writer(outputFp), - m_cmdPacketBuf(), - m_packetBuffer(new uint8_t[NET_MAX_PAYLOAD]) -{ - m_cmdPacketBuf.StartWriting(m_packetBuffer.get(), NET_MAX_PAYLOAD); -} - -void DemoWriter::StartWriting(demoheader_t& header) -{ - m_writer.WriteDemoHeader(header); -} - -void DemoWriter::EndWriting() -{ - // stv demos have a byte chopped off of the end - // i dunno why, just doit - truncate(m_writer.GetFp(), -1); -} - -void DemoWriter::StartCommandPacket(const CommandPacket& packet) -{ - m_writer.WriteCmdHeader(packet.cmd, packet.tick); - DemHandlers::DemMsg_FileWrite(packet.cmd, m_writer, packet.data); - m_cmdPacketBuf.Reset(); -} - -void DemoWriter::EndCommandPacket(const PacketTrailingBits& trailingBits) -{ - if (trailingBits.numTrailingBits > 0) - { - m_cmdPacketBuf.WriteUBitLong(trailingBits.value, trailingBits.numTrailingBits); - } - const int numBitsToWrite = m_cmdPacketBuf.GetNumBitsWritten() % 8; - if (numBitsToWrite != 0) - { - assert(false); - } - if (m_cmdPacketBuf.GetNumBytesWritten() > 0) - { - m_writer.WriteRawData(m_cmdPacketBuf.GetBasePointer(), m_cmdPacketBuf.GetNumBytesWritten()); - } -} - -void DemoWriter::WriteNetPacket(NetPacket& packet, SourceGameContext& context) -{ - m_cmdPacketBuf.WriteUBitLong(packet.type, NETMSG_TYPE_BITS); - NetHandlers::NetMsg_BitWrite(packet.type, m_cmdPacketBuf, context, packet.data); -} diff --git a/demboyz/io/demreader.cpp b/demboyz/io/demreader.cpp deleted file mode 100644 index 45255e5..0000000 --- a/demboyz/io/demreader.cpp +++ /dev/null @@ -1,81 +0,0 @@ - -#include "demoreader.h" -#include "idemowriter.h" -#include "demofile/demofile.h" -#include "demofile/demotypes.h" - -#include "game/sourcecontext.h" -#include "netmessages/nethandlers.h" -#include "netmessages/netcontants.h" -#include "demmessages/demhandlers.h" -#include "sourcesdk/bitbuf.h" -#include - -PacketTrailingBits ParsePacket(uint8_t* packet, size_t length, - SourceGameContext& context, IDemoWriter* writer, - const NetHandlers::NetDataStructArray& netDataStructs) -{ - assert(length <= NET_MAX_PAYLOAD); - bf_read bitbuf(packet, length); - NetPacket netPacket; - while (bitbuf.GetNumBitsLeft() >= NETMSG_TYPE_BITS) - { - netPacket.type = bitbuf.ReadUBitLong(NETMSG_TYPE_BITS); - netPacket.data = netDataStructs[netPacket.type]; - NetHandlers::NetMsg_BitRead(netPacket.type, bitbuf, context, netPacket.data); - writer->WriteNetPacket(netPacket, context); - } - - PacketTrailingBits trailingBits; - trailingBits.numTrailingBits = bitbuf.GetNumBitsLeft(); - if (trailingBits.numTrailingBits) - { - trailingBits.value = bitbuf.ReadUBitLong(trailingBits.numTrailingBits); - } - else - { - trailingBits.value = 0; - } - return trailingBits; -} - -void DemoReader::ProcessDem(std::FILE* inputFp, IDemoWriter* writer) -{ - NetHandlers::NetDataStructArray netDataStructs; - DemHandlers::DemDataStructArray demDataStructs; - NetHandlers::CreateNetMsgStructs(netDataStructs); - DemHandlers::CreateDemMsgStructs(demDataStructs); - - SourceGameContext context = SourceGameContext(); - DemoFileReader reader(inputFp); - { - demoheader_t header; - reader.ReadDemoHeader(header); - writer->StartWriting(header); - context.protocol = header.networkprotocol; - } - - CommandPacket packet; - int frame = -1; - do - { - size_t rawDataSize = 0; - reader.ReadCmdHeader(packet.cmd, packet.tick); - packet.data = demDataStructs[packet.cmd]; - DemHandlers::DemMsg_FileRead(packet.cmd, reader, packet.data); - - PacketTrailingBits trailingBits = PacketTrailingBits(); - writer->StartCommandPacket(packet); - frame += (packet.cmd == dem_packet); - if (packet.cmd == dem_packet || packet.cmd == dem_signon) - { - Array buffer = reader.ReadRawData(NET_MAX_PAYLOAD); - trailingBits = ParsePacket(buffer.begin(), buffer.length(), context, writer, netDataStructs); - } - writer->EndCommandPacket(trailingBits); - } while (packet.cmd != dem_stop); - writer->EndWriting(); - - DemHandlers::DestroyDemMsgStructs(demDataStructs); - NetHandlers::DestroyNetMsgStructs(netDataStructs); -} diff --git a/demboyz/io/idemowriter.h b/demboyz/io/idemowriter.h deleted file mode 100644 index d38bb82..0000000 --- a/demboyz/io/idemowriter.h +++ /dev/null @@ -1,55 +0,0 @@ - -#pragma once - -#include - -struct democmdinfo_t; -struct demoheader_t; -struct CommandPacket; -struct NetPacket; -struct SourceGameContext; - -struct CommandPacket -{ - unsigned char cmd; - int32_t tick; - - void* data; -}; - -struct NetPacket -{ - int32_t type; - void* data; -}; - -struct PacketTrailingBits -{ - uint32_t numTrailingBits; - uint32_t value; -}; - -class IDemoWriter -{ -public: - virtual ~IDemoWriter() {} - - virtual void StartWriting(demoheader_t& header) = 0; - virtual void EndWriting() = 0; - - virtual void StartCommandPacket(const CommandPacket& packet) = 0; - virtual void EndCommandPacket(const PacketTrailingBits& trailingBits) = 0; - - virtual void WriteNetPacket(NetPacket& packet, SourceGameContext& context) = 0; - -public: - static IDemoWriter* CreateJsonWriter(void* outputFp); - static IDemoWriter* CreateDemoWriter(void* outputFp); - static IDemoWriter* CreateConLogWriter(void* outputFp); - static IDemoWriter* CreateVoiceDataWriter(const char* outputPath); - - static void FreeDemoWriter(IDemoWriter* writer) - { - delete writer; - } -}; diff --git a/demboyz/io/jsonreader.cpp b/demboyz/io/jsonreader.cpp deleted file mode 100644 index fa2da22..0000000 --- a/demboyz/io/jsonreader.cpp +++ /dev/null @@ -1,92 +0,0 @@ - -#include "demoreader.h" -#include "demofile/demotypes.h" -#include "demofile/demojson.h" -#include "base/jsonfile.h" -#include "io/idemowriter.h" - -#include "game/sourcecontext.h" -#include "netmessages/nethandlers.h" -#include "demmessages/demhandlers.h" - -int32_t ReadNetpacket(base::JsonReaderFile& jsonReader, PacketTrailingBits& trailingBits) -{ - base::JsonReaderObject reader = jsonReader.ParseObject(); - assert(!reader.HasReadError()); - const int32_t type = reader.ReadInt32("netpacket"); - if (type < 0) - { - base::JsonReaderObject reader = jsonReader.ParseObject(); - assert(!reader.HasReadError()); - trailingBits.numTrailingBits = reader.ReadInt32("numTrailingBits"); - trailingBits.value = reader.ReadInt32("trailingBitsValue"); - } - return type; -} - -PacketTrailingBits ParsePacket(base::JsonReaderFile& jsonReader, - SourceGameContext& context, IDemoWriter* writer, - const NetHandlers::NetDataStructArray& netDataStructs) -{ - PacketTrailingBits trailingBits = PacketTrailingBits(); - NetPacket netPacket = NetPacket(); - while ((netPacket.type = ReadNetpacket(jsonReader, trailingBits)) >= 0) - { - netPacket.data = netDataStructs[netPacket.type]; - NetHandlers::NetMsg_JsonRead(netPacket.type, jsonReader, context, netPacket.data); - writer->WriteNetPacket(netPacket, context); - } - return trailingBits; -} - -void DemoReader::ProcessJson(std::FILE* inputFp, IDemoWriter* writer) -{ - NetHandlers::NetDataStructArray netDataStructs; - DemHandlers::DemDataStructArray demDataStructs; - NetHandlers::CreateNetMsgStructs(netDataStructs); - DemHandlers::CreateDemMsgStructs(demDataStructs); - - SourceGameContext context = SourceGameContext(); - char buffer[4096]; - base::JsonReaderFile jsonReader(inputFp, buffer, sizeof(buffer)); - { - base::JsonReaderObject reader = jsonReader.ParseObject(); - assert(!reader.HasReadError()); - - demoheader_t header; - if (!DemoJsonReader::ReadDemoHeader(reader, header)) - { - return; - } - writer->StartWriting(header); - context.protocol = header.networkprotocol; - } - - CommandPacket packet; - do - { - { - base::JsonReaderObject reader = jsonReader.ParseObject(); - if (reader.HasReadError()) - { - assert(!reader.HasReadError()); - } - - DemoJsonReader::ReadCmdHeader(reader, packet.cmd, packet.tick); - } - packet.data = demDataStructs[packet.cmd]; - DemHandlers::DemMsg_JsonRead(packet.cmd, jsonReader, packet.data); - - PacketTrailingBits trailingBits = PacketTrailingBits(); - writer->StartCommandPacket(packet); - if (packet.cmd == dem_packet || packet.cmd == dem_signon) - { - trailingBits = ParsePacket(jsonReader, context, writer, netDataStructs); - } - writer->EndCommandPacket(trailingBits); - } while (packet.cmd != dem_stop); - writer->EndWriting(); - - DemHandlers::DestroyDemMsgStructs(demDataStructs); - NetHandlers::DestroyNetMsgStructs(netDataStructs); -} diff --git a/demboyz/io/jsonwriter.cpp b/demboyz/io/jsonwriter.cpp deleted file mode 100644 index 8ebe968..0000000 --- a/demboyz/io/jsonwriter.cpp +++ /dev/null @@ -1,104 +0,0 @@ - -#include "idemowriter.h" -#include "demofile/demojson.h" -#include "demofile/demotypes.h" -#include "base/jsonfile.h" -#include "demmessages/demhandlers.h" -#include "netmessages/nethandlers.h" -#include -#include - -class JsonWriter: public IDemoWriter -{ -public: - JsonWriter(FILE* outputFp); - - virtual void StartWriting(demoheader_t& header) override final; - virtual void EndWriting() override final; - - virtual void StartCommandPacket(const CommandPacket& packet) override final; - virtual void EndCommandPacket(const PacketTrailingBits& trailingBits) override final; - - virtual void WriteNetPacket(NetPacket& packet, SourceGameContext& context) override final; - -private: - base::JsonWriterFile m_jsonFile; - bool m_writingNetPackets; - char m_buffer[4096]; -}; - -IDemoWriter* IDemoWriter::CreateJsonWriter(void* outputFp) -{ - return new JsonWriter(reinterpret_cast(outputFp)); -} - -JsonWriter::JsonWriter(FILE* outputFp): - m_jsonFile(outputFp, m_buffer, sizeof(m_buffer)), - m_writingNetPackets(false) -{ -} - -void JsonWriter::StartWriting(demoheader_t& header) -{ - auto& jsonFile = m_jsonFile; - jsonFile.Reset(); - jsonFile.StartObject(); - DemoJsonWriter::WriteDemoHeader(jsonFile, header); - jsonFile.EndObject(); -} - -void JsonWriter::EndWriting() -{ - auto& jsonFile = m_jsonFile; - jsonFile.Flush(); - assert(jsonFile.IsComplete()); -} - -void JsonWriter::StartCommandPacket(const CommandPacket& packet) -{ - auto& jsonFile = m_jsonFile; - jsonFile.Reset(); - jsonFile.StartObject(); - DemoJsonWriter::WriteCmdHeader(jsonFile, packet.cmd, packet.tick); - jsonFile.EndObject(); - - DemHandlers::DemMsg_JsonWrite(packet.cmd, jsonFile, packet.data); - assert(jsonFile.IsComplete()); - - if (packet.cmd == dem_packet || packet.cmd == dem_signon) - { - m_writingNetPackets = true; - } -} - -void JsonWriter::EndCommandPacket(const PacketTrailingBits& trailingBits) -{ - if (m_writingNetPackets) - { - m_writingNetPackets = false; - auto& jsonFile = m_jsonFile; - jsonFile.Reset(); - jsonFile.StartObject(); - jsonFile.WriteInt32("netpacket", -1); - jsonFile.EndObject(); - - jsonFile.Reset(); - jsonFile.StartObject(); - jsonFile.WriteInt32("numTrailingBits", trailingBits.numTrailingBits); - jsonFile.WriteInt32("trailingBitsValue", trailingBits.value, (trailingBits.numTrailingBits > 0)); - jsonFile.EndObject(); - assert(jsonFile.IsComplete()); - } -} - -void JsonWriter::WriteNetPacket(NetPacket& packet, SourceGameContext& context) -{ - auto& jsonFile = m_jsonFile; - jsonFile.Reset(); - jsonFile.StartObject(); - jsonFile.WriteInt32("netpacket", packet.type); - jsonFile.EndObject(); - - NetHandlers::NetMsg_JsonWrite(packet.type, jsonFile, context, packet.data); - assert(jsonFile.IsComplete()); -} diff --git a/demboyz/io/voicewriter/opusfilewriter.h b/demboyz/io/voicewriter/opusfilewriter.h new file mode 100644 index 0000000..ac106f5 --- /dev/null +++ b/demboyz/io/voicewriter/opusfilewriter.h @@ -0,0 +1,81 @@ + +#pragma once + +#include +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +class OpusFileWriter +{ +public: + OpusFileWriter() + { + } + + ~OpusFileWriter() + { + assert(!m_Enc); + } + + void Init(const char* file, uint32_t sampleRate) + { + assert(!m_Enc); + m_Samples = 0; + + m_Comments = ope_comments_create(); + + int error; + m_Enc = ope_encoder_create_file(file, m_Comments, sampleRate, 1, 0, &error); + assert(error == 0); + + ope_encoder_ctl(m_Enc, OPUS_SET_DTX(1)); + } + + void Close() + { + if(!m_Enc) + return; + + ope_encoder_drain(m_Enc); + ope_encoder_destroy(m_Enc); + ope_comments_destroy(m_Comments); + m_Enc = nullptr; + m_Comments = nullptr; + } + + void WriteSamples(const int16_t* samples, uint32_t numSamples) + { + if(!m_Enc) + return; + + ope_encoder_write(m_Enc, samples, numSamples); + m_Samples += numSamples; + } + + void PadSilence(uint32_t numSamples) + { + if(!m_Enc || m_Samples >= numSamples) + return; + + static const int16_t silence[128] = {0}; + uint32_t pad = numSamples - m_Samples; + while(pad > 0) + { + const int samples = MIN(sizeof(silence) / bytesPerSample, pad); + ope_encoder_write(m_Enc, silence, samples); + pad -= samples; + } + m_Samples = numSamples; + } + +private: + OggOpusComments *m_Comments = nullptr; + OggOpusEnc *m_Enc = nullptr; + uint32_t m_Samples = 0; + + static const uint32_t bytesPerSample = 2; +}; diff --git a/demboyz/io/voicewriter/voicedatawriter.cpp b/demboyz/io/voicewriter/voicedatawriter.cpp index 7613fda..9987d97 100644 --- a/demboyz/io/voicewriter/voicedatawriter.cpp +++ b/demboyz/io/voicewriter/voicedatawriter.cpp @@ -1,27 +1,17 @@ - -#include "../idemowriter.h" #include "netmessages/netmessages.h" #include "netmessages/svc_voiceinit.h" #include "netmessages/svc_voicedata.h" -#include "celt/celt.h" +#include +#include #include -#include "wavfilewriter.h" - -#ifdef _WIN32 -//#define USE_VAUDIO_CELT -#endif - -#define MAX_PLAYERS 33 - -#ifdef USE_VAUDIO_CELT -#define VC_EXTRALEAN -#define WIN32_LEAN_AND_MEAN -#include -#endif +#include "base/CRC.h" +#include "game/logic.h" +#include "voicedatawriter.h" +#include struct CeltConfig { @@ -39,198 +29,141 @@ static CeltConfig sCeltConfigs[] = { 44100, 1024, 128 } // vaudio_celt_high }; -#ifdef USE_VAUDIO_CELT - -class IVoiceCodec +bool CeltVoiceDecoder::DoInit(CELTMode* celtMode, uint32_t frameSizeSamples, uint32_t encodedFrameSizeBytes) { -protected: - virtual ~IVoiceCodec() {} - -public: - // Initialize the object. The uncompressed format is always 8-bit signed mono. - virtual bool Init( int quality ) = 0; - - // Use this to delete the object. - virtual void Release() = 0; - - // Compress the voice data. - // pUncompressed - 16-bit signed mono voice data. - // maxCompressedBytes - The length of the pCompressed buffer. Don't exceed this. - // bFinal - Set to true on the last call to Compress (the user stopped talking). - // Some codecs like big block sizes and will hang onto data you give them in Compress calls. - // When you call with bFinal, the codec will give you compressed data no matter what. - // Return the number of bytes you filled into pCompressed. - virtual int Compress(const char *pUncompressed, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) = 0; - - // Decompress voice data. pUncompressed is 16-bit signed mono. - virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) = 0; - - // Some codecs maintain state between Compress and Decompress calls. This should clear that state. - virtual bool ResetState() = 0; -}; - -typedef void* (CreateInterfaceFn)(const char *pName, int *pReturnCode); -static HINSTANCE celtDll; -static CreateInterfaceFn* createInterfaceFunc; - -#else - -class CeltVoiceDecoder -{ -public: - bool DoInit(CELTMode* celtMode, uint32_t frameSizeSamples, uint32_t encodedFrameSizeBytes) + if(m_celtDecoder) { - if(m_celtDecoder) - { - return false; - } - - int error = CELT_OK; - m_celtDecoder = celt_decoder_create_custom(celtMode, sCeltChannels, &error); - assert(error == CELT_OK); - assert(m_celtDecoder); - - m_frameSizeSamples = frameSizeSamples; - m_encodedFrameSizeBytes = encodedFrameSizeBytes; - return true; + return false; } - void Destroy() - { - celt_decoder_destroy(m_celtDecoder); - m_celtDecoder = NULL; - } + int error = CELT_OK; + m_celtDecoder = celt_decoder_create_custom(celtMode, sCeltChannels, &error); + assert(error == CELT_OK); + assert(m_celtDecoder); - void Reset() - { - } - - int Decompress( - const uint8_t* compressedData, - int compressedBytes, - int16_t* uncompressedData, - int maxUncompressedSamples) - { - int curCompressedByte = 0; - int curDecompressedSample = 0; - - const uint32_t encodedframeSizeBytes = m_encodedFrameSizeBytes; - const uint32_t frameSizeSamples = m_frameSizeSamples; - while( - ((compressedBytes - curCompressedByte) >= encodedframeSizeBytes) && - ((maxUncompressedSamples - curDecompressedSample) >= frameSizeSamples)) - { - DecodeFrame(&compressedData[curCompressedByte], &uncompressedData[curDecompressedSample]); - curCompressedByte += encodedframeSizeBytes; - curDecompressedSample += frameSizeSamples; - } - return curDecompressedSample; - } - -private: - void DecodeFrame(const uint8_t* compressedData, int16_t* uncompressedData) - { - int error = celt_decode(m_celtDecoder, compressedData, m_encodedFrameSizeBytes, uncompressedData, m_frameSizeSamples); - assert(error >= CELT_OK); - } - -private: - static const int sCeltChannels = 1; - -private: - CELTDecoder* m_celtDecoder = NULL; - uint32_t m_frameSizeSamples = 0; - uint32_t m_encodedFrameSizeBytes = 0; -}; - -#endif // USE_VAUDIO_CELT - -class VoiceDataWriter: public IDemoWriter -{ -public: - VoiceDataWriter(const char* outputPath); - - virtual void StartWriting(demoheader_t& header) override final; - virtual void EndWriting() override final; - - virtual void StartCommandPacket(const CommandPacket& packet) override final; - virtual void EndCommandPacket(const PacketTrailingBits& trailingBits) override final; - - virtual void WriteNetPacket(NetPacket& packet, SourceGameContext& context) override final; - -private: - struct PlayerVoiceState - { -#ifdef USE_VAUDIO_CELT - IVoiceCodec* celtDecoder = nullptr; -#else - CeltVoiceDecoder decoder; -#endif - WaveFileWriter wavWriter; - int32_t lastVoiceDataTick = -1; - }; - -private: - CELTMode* m_celtMode; - PlayerVoiceState m_playerVoiceStates[MAX_PLAYERS]; - - int32_t m_curTick; - const char* m_outputPath; - - int16_t m_decodeBuffer[8192]; - - static const int sQuality = 3; -}; - -IDemoWriter* IDemoWriter::CreateVoiceDataWriter(const char* outputPath) -{ - return new VoiceDataWriter(outputPath); + m_frameSizeSamples = frameSizeSamples; + m_encodedFrameSizeBytes = encodedFrameSizeBytes; + return true; } -VoiceDataWriter::VoiceDataWriter(const char* outputPath): - m_celtMode(nullptr), - m_playerVoiceStates(), - m_curTick(-1), +void CeltVoiceDecoder::Destroy() +{ + celt_decoder_destroy(m_celtDecoder); + m_celtDecoder = NULL; +} + +void CeltVoiceDecoder::Reset() +{ +} + +int CeltVoiceDecoder::Decompress( + const uint8_t* compressedData, + uint32_t compressedBytes, + int16_t* uncompressedData, + uint32_t maxUncompressedSamples) +{ + uint32_t curCompressedByte = 0; + uint32_t curDecompressedSample = 0; + + const uint32_t encodedframeSizeBytes = m_encodedFrameSizeBytes; + const uint32_t frameSizeSamples = m_frameSizeSamples; + while( + ((compressedBytes - curCompressedByte) >= encodedframeSizeBytes) && + ((maxUncompressedSamples - curDecompressedSample) >= frameSizeSamples)) + { + DecodeFrame(&compressedData[curCompressedByte], &uncompressedData[curDecompressedSample]); + curCompressedByte += encodedframeSizeBytes; + curDecompressedSample += frameSizeSamples; + } + return curDecompressedSample; +} + +void CeltVoiceDecoder::DecodeFrame(const uint8_t* compressedData, int16_t* uncompressedData) +{ + int error = celt_decode(m_celtDecoder, compressedData, m_encodedFrameSizeBytes, uncompressedData, m_frameSizeSamples); + assert(error >= CELT_OK); +} + + +bool SilkVoiceDecoder::DoInit(int32_t sampleRate) +{ + m_Silk_DecoderControl.API_sampleRate = sampleRate; + if(m_Silk_DecoderState) + { + return false; + } + + int decoderSize; + SKP_Silk_SDK_Get_Decoder_Size(&decoderSize); + + m_Silk_DecoderState = malloc(decoderSize); + assert(m_Silk_DecoderState != NULL); + + int retEnc = SKP_Silk_SDK_InitDecoder(m_Silk_DecoderState); + assert(retEnc == SKP_SILK_NO_ERROR); + + return true; +} + +void SilkVoiceDecoder::Destroy() +{ + if(m_Silk_DecoderState) + free(m_Silk_DecoderState); + m_Silk_DecoderState = NULL; +} + +void SilkVoiceDecoder::Reset() +{ + SKP_Silk_SDK_InitDecoder(m_Silk_DecoderState); +} + +int SilkVoiceDecoder::Decompress( + const uint8_t* compressedData, + uint32_t compressedBytes, + int16_t* uncompressedData, + uint32_t maxUncompressedSamples) +{ + short nSamplesOut = maxUncompressedSamples; + int decodeRes = SKP_Silk_SDK_Decode(m_Silk_DecoderState, &m_Silk_DecoderControl, 0, compressedData, compressedBytes, uncompressedData, &nSamplesOut); + + if (SKP_SILK_NO_ERROR != decodeRes) + return 0; + return nSamplesOut; +} + + +VoiceDataWriter::VoiceDataWriter(SourceGameContext* context, const char* outputPath): + context(context), m_outputPath(outputPath) { } -void VoiceDataWriter::StartWriting(demoheader_t& header) +void VoiceDataWriter::Start() { -#ifdef USE_VAUDIO_CELT - celtDll = LoadLibrary(TEXT("vaudio_celt.dll")); - createInterfaceFunc = (CreateInterfaceFn*)GetProcAddress(celtDll, "CreateInterface"); -#else int error = CELT_OK; const CeltConfig& config = sCeltConfigs[sQuality]; m_celtMode = celt_mode_create(config.sampleRate, config.frameSizeSamples, &error); assert(error == CELT_OK); assert(m_celtMode); -#endif } -void VoiceDataWriter::EndWriting() +void VoiceDataWriter::Finish() { - for(PlayerVoiceState& state : m_playerVoiceStates) + for(auto& state : m_playerVoiceStates) { -#ifdef USE_VAUDIO_CELT - if(state.celtDecoder) - { - state.celtDecoder->Release(); - } -#else - state.decoder.Destroy(); -#endif - state.wavWriter.Close(); - state.lastVoiceDataTick = -1; + state.second.celt_decoder.Destroy(); + state.second.silk_decoder.Destroy(); + + state.second.fileWriter.PadSilence((m_curTick * state.second.sampleRate) / context->fTickRate); + state.second.fileWriter.Close(); + state.second.lastVoiceDataTick = -1; } -#ifndef USE_VAUDIO_CELT + if(m_celtMode) { celt_mode_destroy(m_celtMode); m_celtMode = nullptr; } -#endif } void VoiceDataWriter::StartCommandPacket(const CommandPacket& packet) @@ -240,53 +173,200 @@ void VoiceDataWriter::StartCommandPacket(const CommandPacket& packet) void VoiceDataWriter::EndCommandPacket(const PacketTrailingBits& trailingBits) { + const int tickMargin = context->fTickRate / 10.0; // 100ms + if (m_curTick <= tickMargin) + return; + + for(auto& state : m_playerVoiceStates) + { + if((m_curTick - state.second.lastVoiceDataTick) > tickMargin) + state.second.fileWriter.PadSilence((m_curTick * state.second.sampleRate) / context->fTickRate); + } } -void VoiceDataWriter::WriteNetPacket(NetPacket& packet, SourceGameContext& context) +int VoiceDataWriter::ParseSteamVoicePacket(uint8_t* bytes, int numBytes, PlayerVoiceState& state) +{ + int numDecompressedSamples = 0; + int pos = 0; + if(numBytes < 4+4+4+1+2) + return -1; + + int dataLen = numBytes - 4; // skip CRC + + uint32_t CRCdemo = *((uint32_t *)&bytes[dataLen]); + uint32_t CRCdata = CRC::Calculate(bytes, dataLen, CRC::CRC_32()); + if(CRCdata != CRCdemo) + return -1; + + //uint32_t iSteamAccountID = *((uint32_t *)&bytes[pos]); + pos += 4; + uint32_t iSteamCommunity = *((uint32_t *)&bytes[pos]); + pos += 4; + + if(iSteamCommunity != 0x1100001) + return -1; + + while (pos < dataLen) + { + uint8_t payloadType = bytes[pos]; + pos++; + + switch(payloadType) + { + case 11: // Sample Rate + { + if(pos + 2 > dataLen) + return numDecompressedSamples; + short rate = *((int16_t *)&bytes[pos]); + pos += 2; + state.silk_decoder.DoInit(rate); + state.sampleRate = rate; + } break; + case 10: // Unknown / Unused + { + if(pos + 2 > dataLen) + return numDecompressedSamples; + //short unk = *((int16_t *)&bytes[pos]); + pos += 2; + } break; + case 1: // Unknown Codec??? + case 2: // Speex Data (Unsupported) + case 3: // Uncompressed Data + case 4: // SILK Data + { + if(pos + 2 > dataLen) + return numDecompressedSamples; + short length = *((int16_t *)&bytes[pos]); + pos += 2; + + if(pos + length > dataLen) + return numDecompressedSamples; + + if(payloadType == 3) + { + memcpy(&m_decodeBuffer[numDecompressedSamples], &bytes[pos], length); + numDecompressedSamples += length / sizeof(int16_t); + } + else if(payloadType == 4) + { + int tpos = pos; + int maxpos = tpos + length; + while(tpos <= (maxpos - 2)) + { + short chunkLength = *((int16_t *)&bytes[tpos]); + tpos += 2; + + if(chunkLength == -1) + { + state.silk_decoder.Reset(); + continue; + } + else if(chunkLength == 0) + { + // DTX (discontinued transmission) + int numEmptySamples = state.sampleRate / 50; + memset(&m_decodeBuffer[numDecompressedSamples], 0, numEmptySamples * sizeof(int16_t)); + numDecompressedSamples += numEmptySamples; + continue; + } + + if(tpos + chunkLength > maxpos) + return numDecompressedSamples; + + int ret = state.silk_decoder.Decompress(&bytes[tpos], chunkLength, &m_decodeBuffer[numDecompressedSamples], + (sizeof(m_decodeBuffer) / sizeof(int16_t)) - numDecompressedSamples); + numDecompressedSamples += ret; + tpos += chunkLength; + } + } + pos += length; + + } break; + case 0: // Silence + { + if(pos + 2 > dataLen) + return numDecompressedSamples; + short numSamples = *((int16_t *)&bytes[pos]); + memset(&m_decodeBuffer[numDecompressedSamples], 0, numSamples * sizeof(int16_t)); + numDecompressedSamples += numSamples; + pos += 2; + } break; + } + } + + return numDecompressedSamples; +} + +void VoiceDataWriter::OnNetPacket(NetPacket& packet) { if(packet.type == NetMsg::svc_VoiceInit) { NetMsg::SVC_VoiceInit* voiceInit = static_cast(packet.data); - assert(!strcmp(voiceInit->voiceCodec, "vaudio_celt")); - assert(voiceInit->quality == NetMsg::SVC_VoiceInit::QUALITY_HAS_SAMPLE_RATE); - assert(voiceInit->sampleRate == sCeltConfigs[sQuality].sampleRate); + if(!strcmp(voiceInit->voiceCodec, "vaudio_celt")) + { + assert(voiceInit->quality == NetMsg::SVC_VoiceInit::QUALITY_HAS_SAMPLE_RATE); + assert(voiceInit->sampleRate == sCeltConfigs[sQuality].sampleRate); + m_Codec = CODEC_CELT; + } + else if(!strcmp(voiceInit->voiceCodec, "vaudio_speex")) + { + m_Codec = CODEC_SPEEX; + } + else //if(!strcmp(voiceInit->voiceCodec, "steam")) + { + m_Codec = CODEC_STEAM; + } + context->logic->OnVoiceCodec(voiceInit->voiceCodec, voiceInit->quality, voiceInit->sampleRate); } else if(packet.type == NetMsg::svc_VoiceData) { NetMsg::SVC_VoiceData* voiceData = static_cast(packet.data); assert(voiceData->fromClientIndex < MAX_PLAYERS); + const char* guid = context->players[voiceData->fromClientIndex].info.guid; - PlayerVoiceState& state = m_playerVoiceStates[voiceData->fromClientIndex]; - - const CeltConfig& config = sCeltConfigs[sQuality]; -#ifdef USE_VAUDIO_CELT - const bool initWavWriter = !state.celtDecoder; - if(!state.celtDecoder) - { - int ret = 0; - state.celtDecoder = static_cast(createInterfaceFunc("vaudio_celt", &ret)); - state.celtDecoder->Init(sQuality); - } -#else - const bool initWavWriter = state.decoder.DoInit(m_celtMode, config.frameSizeSamples, config.encodedFrameSizeBytes); -#endif - if(initWavWriter) - { - std::string name = std::string(m_outputPath) + "/client_" + std::to_string((uint32_t)voiceData->fromClientIndex) + ".wav"; - state.wavWriter.Init(name.c_str(), config.sampleRate); - assert(state.lastVoiceDataTick == -1); - state.lastVoiceDataTick = m_curTick; - } - + uint8_t* bytes = voiceData->data.get(); assert((voiceData->dataLengthInBits % 8) == 0); const int numBytes = voiceData->dataLengthInBits / 8; -#ifdef USE_VAUDIO_CELT - const int numDecompressedSamples = state.celtDecoder->Decompress((const char*)voiceData->data.get(), numBytes, (char*)m_decodeBuffer, 8192*2); -#else - const int numDecompressedSamples = state.decoder.Decompress(voiceData->data.get(), numBytes, m_decodeBuffer, 8192); -#endif - state.wavWriter.WriteSamples(m_decodeBuffer, numDecompressedSamples); + int numDecompressedSamples = 0; + + PlayerVoiceState& state = m_playerVoiceStates[guid]; + + if(m_Codec == CODEC_CELT) + { + const CeltConfig& config = sCeltConfigs[sQuality]; + state.sampleRate = config.sampleRate; + + state.celt_decoder.DoInit(m_celtMode, config.frameSizeSamples, config.encodedFrameSizeBytes); + numDecompressedSamples = state.celt_decoder.Decompress(bytes, numBytes, m_decodeBuffer, sizeof(m_decodeBuffer)); + } + else + { + // Try Steam Voice + if(numBytes >= 15) + { + numDecompressedSamples = ParseSteamVoicePacket(bytes, numBytes, state); + } + + // Would try speex here, if I cared... + if(numDecompressedSamples <= 0) + { + } + } + + if(numDecompressedSamples <= 0) + return; + + if(state.lastVoiceDataTick == -1) + { + std::string name = std::string(m_outputPath) + "/" + std::string(guid) + ".opus"; + state.fileWriter.Init(name.c_str(), state.sampleRate); + state.fileWriter.PadSilence((m_curTick * state.sampleRate) / context->fTickRate); + } + + state.fileWriter.WriteSamples(m_decodeBuffer, numDecompressedSamples); + + context->logic->OnClientVoiceChat(voiceData->fromClientIndex, (float)numDecompressedSamples / (float)state.sampleRate); state.lastVoiceDataTick = m_curTick; } diff --git a/demboyz/io/voicewriter/voicedatawriter.h b/demboyz/io/voicewriter/voicedatawriter.h new file mode 100644 index 0000000..dd597c9 --- /dev/null +++ b/demboyz/io/voicewriter/voicedatawriter.h @@ -0,0 +1,91 @@ +#pragma once + +#include "opusfilewriter.h" +#include "game/sourcecontext.h" +#include + +struct CELTMode; + +enum eCodec +{ + CODEC_NONE = 0, + CODEC_CELT = 1, + CODEC_SPEEX = 2, + CODEC_STEAM = 2 +}; + +class CeltVoiceDecoder +{ +public: + bool DoInit(CELTMode* celtMode, uint32_t frameSizeSamples, uint32_t encodedFrameSizeBytes); + void Destroy(); + void Reset(); + + int Decompress(const uint8_t* compressedData, uint32_t compressedBytes, int16_t* uncompressedData, uint32_t maxUncompressedSamples); + void DecodeFrame(const uint8_t* compressedData, int16_t* uncompressedData); + +private: + static const int sCeltChannels = 1; + +private: + struct CELTDecoder* m_celtDecoder = NULL; + uint32_t m_frameSizeSamples = 0; + uint32_t m_encodedFrameSizeBytes = 0; +}; + +class SilkVoiceDecoder +{ +public: + bool DoInit(int32_t sampleRate); + void Destroy(); + void Reset(); + + int Decompress(const uint8_t* compressedData, uint32_t compressedBytes, int16_t* uncompressedData, uint32_t maxUncompressedSamples); + +private: + static const int sSilkChannels = 1; + +private: + void* m_Silk_DecoderState = NULL; + SKP_SILK_SDK_DecControlStruct m_Silk_DecoderControl; +}; + +class VoiceDataWriter +{ +public: + VoiceDataWriter(SourceGameContext *context, const char* outputPath); + + void Start(); + void Finish(); + + void StartCommandPacket(const CommandPacket& packet); + void EndCommandPacket(const PacketTrailingBits& trailingBits); + + void OnNetPacket(NetPacket& packet); + +private: + struct PlayerVoiceState + { + CeltVoiceDecoder celt_decoder; + SilkVoiceDecoder silk_decoder; + + OpusFileWriter fileWriter; + int32_t lastVoiceDataTick = -1; + int sampleRate = 0; + }; + + int ParseSteamVoicePacket(uint8_t* bytes, int numBytes, PlayerVoiceState& state); + +private: + SourceGameContext *context = nullptr; + CELTMode* m_celtMode = nullptr; + std::map m_playerVoiceStates; + + int32_t m_curTick = -1; + const char* m_outputPath = nullptr; + + int16_t m_decodeBuffer[8192]; + + static const int sQuality = 3; + eCodec m_Codec = CODEC_NONE; +}; diff --git a/demboyz/io/voicewriter/wavfilewriter.h b/demboyz/io/voicewriter/wavfilewriter.h index 14274d5..1b92599 100644 --- a/demboyz/io/voicewriter/wavfilewriter.h +++ b/demboyz/io/voicewriter/wavfilewriter.h @@ -10,7 +10,7 @@ class WaveFileWriter public: WaveFileWriter(): m_file(nullptr), - m_DataBytes(0) + m_Samples(0) { } @@ -25,7 +25,7 @@ public: assert(fp); m_file = fp; - m_DataBytes = 0; + m_Samples = 0; const uint32_t chunkSize = 0; @@ -62,7 +62,7 @@ public: return; } - const uint32_t dataSize = m_DataBytes; + const uint32_t dataSize = m_Samples * bytesPerSample; const uint32_t chunkSize = dataSize + 36; fseek(fp, 4, SEEK_SET); @@ -78,13 +78,29 @@ public: void WriteSamples(const int16_t* samples, uint32_t numSamples) { - const uint32_t bytesPerSample = 2; + if(!m_file) + return; + const size_t elemsWritten = fwrite(samples, bytesPerSample, numSamples, m_file); assert(elemsWritten == numSamples); - m_DataBytes += (elemsWritten * bytesPerSample); + m_Samples += elemsWritten; + } + + void PadSilence(uint32_t numSamples) + { + if(!m_file || m_Samples >= numSamples) + return; + + const uint16_t silence[bytesPerSample] = {0}; + const uint32_t pad = numSamples - m_Samples; + for(uint32_t i = 0; i < pad; i++) + fwrite(silence, bytesPerSample, 1, m_file); + m_Samples += pad; } private: FILE* m_file; - uint32_t m_DataBytes; + uint32_t m_Samples; + + static const uint32_t bytesPerSample = 2; }; diff --git a/demboyz/netmessages/net_disconnect.cpp b/demboyz/netmessages/net_disconnect.cpp index 902462d..55a06f7 100644 --- a/demboyz/netmessages/net_disconnect.cpp +++ b/demboyz/netmessages/net_disconnect.cpp @@ -1,7 +1,6 @@ #include "net_disconnect.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -10,32 +9,4 @@ namespace NetHandlers bitbuf.ReadString(data->message, sizeof(data->message)); return !bitbuf.IsOverflowed(); } - - bool Net_Disconnect_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_Disconnect* data) - { - bitbuf.WriteString(data->message); - return !bitbuf.IsOverflowed(); - } - - bool Net_Disconnect_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_Disconnect* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - reader.ReadString("message", data->message, sizeof(data->message)); - return !reader.HasReadError(); - } - - bool Net_Disconnect_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_Disconnect* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteString("message", data->message); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_Disconnect_ToString_Internal(std::ostringstream& out, NetMsg::Net_Disconnect* data) - { - // nothing - } } diff --git a/demboyz/netmessages/net_file.cpp b/demboyz/netmessages/net_file.cpp index 5863a5a..8f82d99 100644 --- a/demboyz/netmessages/net_file.cpp +++ b/demboyz/netmessages/net_file.cpp @@ -1,7 +1,6 @@ #include "net_file.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -12,38 +11,4 @@ namespace NetHandlers data->isRequest = bitbuf.ReadOneBit() != 0; return !bitbuf.IsOverflowed(); } - - bool Net_File_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_File* data) - { - bitbuf.WriteUBitLong(data->transferID, 32); - bitbuf.WriteString(data->filename); - bitbuf.WriteOneBit(data->isRequest); - return !bitbuf.IsOverflowed(); - } - - bool Net_File_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_File* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->transferID = reader.ReadUInt32("transferId"); - reader.ReadString("filename", data->filename, sizeof(data->filename)); - data->isRequest = reader.ReadBool("isRequest"); - return !reader.HasReadError(); - } - - bool Net_File_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_File* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("transferId", data->transferID); - jsonbuf.WriteString("filename", data->filename); - jsonbuf.WriteBool("isRequest", data->isRequest); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_File_ToString_Internal(std::ostringstream& out, NetMsg::Net_File* data) - { - // nothing - } } diff --git a/demboyz/netmessages/net_nop.cpp b/demboyz/netmessages/net_nop.cpp index fabc98f..b7b8d8f 100644 --- a/demboyz/netmessages/net_nop.cpp +++ b/demboyz/netmessages/net_nop.cpp @@ -1,6 +1,5 @@ #include "net_nop.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -8,23 +7,4 @@ namespace NetHandlers { return true; } - - bool Net_NOP_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_NOP* data) - { - return true; - } - - bool Net_NOP_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_NOP* data) - { - return true; - } - - bool Net_NOP_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_NOP* data) - { - return true; - } - - void Net_NOP_ToString_Internal(std::ostringstream& out, NetMsg::Net_NOP* data) - { - } } diff --git a/demboyz/netmessages/net_setconvar.cpp b/demboyz/netmessages/net_setconvar.cpp index 9edc6e1..03c9fba 100644 --- a/demboyz/netmessages/net_setconvar.cpp +++ b/demboyz/netmessages/net_setconvar.cpp @@ -1,7 +1,6 @@ #include "net_setconvar.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -14,55 +13,8 @@ namespace NetHandlers { bitbuf.ReadString(cvar.name, sizeof(cvar.name)); bitbuf.ReadString(cvar.value, sizeof(cvar.value)); + //printf("%s -> %s\n", cvar.name, cvar.value); } return !bitbuf.IsOverflowed(); } - - bool Net_SetConVar_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_SetConVar* data) - { - bitbuf.WriteByte(data->cvars.size()); - for (const cvar_t& cvar : data->cvars) - { - bitbuf.WriteString(cvar.name); - bitbuf.WriteString(cvar.value); - } - return !bitbuf.IsOverflowed(); - } - - bool Net_SetConVar_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_SetConVar* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - base::JsonReaderArray cvars = reader.ReadArray("cvars"); - cvars.TransformTo(data->cvars, [](base::JsonReaderObject& obj, cvar_t& cvar) - { - obj.ReadString("name", cvar.name, sizeof(cvar.name)); - obj.ReadString("value", cvar.value, sizeof(cvar.value)); - }); - return !reader.HasReadError(); - } - - bool Net_SetConVar_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_SetConVar* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.StartArray("cvars"); - for (const cvar_t& cvar : data->cvars) - { - jsonbuf.StartObject(); - jsonbuf.WriteString("name", cvar.name); - jsonbuf.WriteString("value", cvar.value); - jsonbuf.EndObject(); - } - jsonbuf.EndArray(); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_SetConVar_ToString_Internal(std::ostringstream& out, NetMsg::Net_SetConVar* data) - { - cvar_t cvar = data->cvars[0]; - out << "net_SetConVar: " << data->cvars.size() << " cvars, \"" << cvar.name << "\"=\"" << cvar.value << '"'; - } } diff --git a/demboyz/netmessages/net_signonstate.cpp b/demboyz/netmessages/net_signonstate.cpp index 4080712..9c22fd1 100644 --- a/demboyz/netmessages/net_signonstate.cpp +++ b/demboyz/netmessages/net_signonstate.cpp @@ -1,7 +1,6 @@ #include "net_signonstate.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -12,36 +11,4 @@ namespace NetHandlers //assert(signonState >= SIGNONSTATE_NONE && signonState <= SIGNONSTATE_CHANGELEVEL); return !bitbuf.IsOverflowed(); } - - bool Net_SignonState_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_SignonState* data) - { - bitbuf.WriteByte(data->signonState); - bitbuf.WriteLong(data->spawnCount); - return !bitbuf.IsOverflowed(); - } - - bool Net_SignonState_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_SignonState* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->signonState = reader.ReadUInt32("signonState"); - data->spawnCount = reader.ReadUInt32("spawnCount"); - return !reader.HasReadError(); - } - - bool Net_SignonState_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_SignonState* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("signonState", data->signonState); - jsonbuf.WriteUInt32("spawnCount", data->spawnCount); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_SignonState_ToString_Internal(std::ostringstream& out, NetMsg::Net_SignonState* data) - { - out << "net_SignonState: state " << static_cast(data->signonState) - << ", count " << data->spawnCount; - } } diff --git a/demboyz/netmessages/net_stringcmd.cpp b/demboyz/netmessages/net_stringcmd.cpp index d15d29f..1e4d47b 100644 --- a/demboyz/netmessages/net_stringcmd.cpp +++ b/demboyz/netmessages/net_stringcmd.cpp @@ -1,7 +1,6 @@ #include "net_stringcmd.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -10,32 +9,4 @@ namespace NetHandlers bitbuf.ReadString(data->command, sizeof(data->command)); return !bitbuf.IsOverflowed(); } - - bool Net_StringCmd_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_StringCmd* data) - { - bitbuf.WriteString(data->command); - return !bitbuf.IsOverflowed(); - } - - bool Net_StringCmd_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_StringCmd* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - reader.ReadString("command", data->command, sizeof(data->command)); - return !reader.HasReadError(); - } - - bool Net_StringCmd_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_StringCmd* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteString("command", data->command); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_StringCmd_ToString_Internal(std::ostringstream& out, NetMsg::Net_StringCmd* data) - { - out << "net_StringCmd: \"" << data->command << '"'; - } } diff --git a/demboyz/netmessages/net_tick.cpp b/demboyz/netmessages/net_tick.cpp index 2ceb14c..7fde8d5 100644 --- a/demboyz/netmessages/net_tick.cpp +++ b/demboyz/netmessages/net_tick.cpp @@ -1,7 +1,6 @@ #include "net_tick.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -12,38 +11,4 @@ namespace NetHandlers data->hostFrameTimeStdDev = bitbuf.ReadUBitLong(16); return !bitbuf.IsOverflowed(); } - - bool Net_Tick_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::Net_Tick* data) - { - bitbuf.WriteUBitLong(data->tick, 32); - bitbuf.WriteUBitLong(data->hostFrameTime, 16); - bitbuf.WriteUBitLong(data->hostFrameTimeStdDev, 16); - return !bitbuf.IsOverflowed(); - } - - bool Net_Tick_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::Net_Tick* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->tick = reader.ReadInt32("tick"); - data->hostFrameTime = reader.ReadUInt32("hostFrameTime"); - data->hostFrameTimeStdDev = reader.ReadUInt32("hostFrameTimeStdDev"); - return !reader.HasReadError(); - } - - bool Net_Tick_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::Net_Tick* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("tick", data->tick); - jsonbuf.WriteUInt32("hostFrameTime", data->hostFrameTime); - jsonbuf.WriteUInt32("hostFrameTimeStdDev", data->hostFrameTimeStdDev); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void Net_Tick_ToString_Internal(std::ostringstream& out, NetMsg::Net_Tick* data) - { - out << "net_Tick: tick " << data->tick; - } } diff --git a/demboyz/netmessages/netcontants.h b/demboyz/netmessages/netcontants.h index d57db64..21dba81 100644 --- a/demboyz/netmessages/netcontants.h +++ b/demboyz/netmessages/netcontants.h @@ -49,5 +49,7 @@ enum constants SIGNONSTATE_FULL = 6, // we are fully connected, first non-delta packet received SIGNONSTATE_CHANGELEVEL = 7, // server is changing level, please wait - MAX_STRINGTABLE_DATA = 2 * 524288 // 2^19 + MAX_STRINGTABLE_DATA = 2 * 524288, // 2^19 + + NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS = 10 }; diff --git a/demboyz/netmessages/nethandlers.cpp b/demboyz/netmessages/nethandlers.cpp index 43c0251..d23f365 100644 --- a/demboyz/netmessages/nethandlers.cpp +++ b/demboyz/netmessages/nethandlers.cpp @@ -45,78 +45,78 @@ void NetHandlers::CreateNetMsgStructs(NetDataStructArray& netDataStructs) { - netDataStructs[0] = new NetMsg::Net_NOP(); - netDataStructs[1] = new NetMsg::Net_Disconnect(); - netDataStructs[2] = new NetMsg::Net_File(); - netDataStructs[3] = new NetMsg::Net_Tick(); - netDataStructs[4] = new NetMsg::Net_StringCmd(); - netDataStructs[5] = new NetMsg::Net_SetConVar(); - netDataStructs[6] = new NetMsg::Net_SignonState(); - netDataStructs[7] = new NetMsg::SVC_Print(); - netDataStructs[8] = new NetMsg::SVC_ServerInfo(); - netDataStructs[9] = new NetMsg::SVC_SendTable(); - netDataStructs[10] = new NetMsg::SVC_ClassInfo(); - netDataStructs[11] = new NetMsg::SVC_SetPause(); - netDataStructs[12] = new NetMsg::SVC_CreateStringTable(); - netDataStructs[13] = new NetMsg::SVC_UpdateStringTable(); - netDataStructs[14] = new NetMsg::SVC_VoiceInit(); - netDataStructs[15] = new NetMsg::SVC_VoiceData(); - netDataStructs[16] = new NetMsg::SVC_HLTV(); - netDataStructs[17] = new NetMsg::SVC_Sounds(); - netDataStructs[18] = new NetMsg::SVC_SetView(); - netDataStructs[19] = new NetMsg::SVC_FixAngle(); - netDataStructs[20] = new NetMsg::SVC_CrosshairAngle(); - netDataStructs[21] = new NetMsg::SVC_BSPDecal(); - netDataStructs[22] = new NetMsg::SVC_TerrainMod(); - netDataStructs[23] = new NetMsg::SVC_UserMessage(); - netDataStructs[24] = new NetMsg::SVC_EntityMessage(); - netDataStructs[25] = new NetMsg::SVC_GameEvent(); - netDataStructs[26] = new NetMsg::SVC_PacketEntities(); - netDataStructs[27] = new NetMsg::SVC_TempEntities(); - netDataStructs[28] = new NetMsg::SVC_Prefetch(); - netDataStructs[29] = new NetMsg::SVC_Menu(); - netDataStructs[30] = new NetMsg::SVC_GameEventList(); - netDataStructs[31] = new NetMsg::SVC_GetCvarValue(); - netDataStructs[32] = new NetMsg::SVC_CmdKeyValues(); - netDataStructs[33] = new NetMsg::SVC_SetPauseTimed(); + netDataStructs[NetMsg::net_NOP] = new NetMsg::Net_NOP(); + netDataStructs[NetMsg::net_Disconnect] = new NetMsg::Net_Disconnect(); + netDataStructs[NetMsg::net_File] = new NetMsg::Net_File(); + netDataStructs[NetMsg::net_Tick] = new NetMsg::Net_Tick(); + netDataStructs[NetMsg::net_StringCmd] = new NetMsg::Net_StringCmd(); + netDataStructs[NetMsg::net_SetConVar] = new NetMsg::Net_SetConVar(); + netDataStructs[NetMsg::net_SignonState] = new NetMsg::Net_SignonState(); + netDataStructs[NetMsg::svc_Print] = new NetMsg::SVC_Print(); + netDataStructs[NetMsg::svc_ServerInfo] = new NetMsg::SVC_ServerInfo(); + netDataStructs[NetMsg::svc_SendTable] = new NetMsg::SVC_SendTable(); + netDataStructs[NetMsg::svc_ClassInfo] = new NetMsg::SVC_ClassInfo(); + netDataStructs[NetMsg::svc_SetPause] = new NetMsg::SVC_SetPause(); + netDataStructs[NetMsg::svc_CreateStringTable] = new NetMsg::SVC_CreateStringTable(); + netDataStructs[NetMsg::svc_UpdateStringTable] = new NetMsg::SVC_UpdateStringTable(); + netDataStructs[NetMsg::svc_VoiceInit] = new NetMsg::SVC_VoiceInit(); + netDataStructs[NetMsg::svc_VoiceData] = new NetMsg::SVC_VoiceData(); + netDataStructs[NetMsg::svc_HLTV] = new NetMsg::SVC_HLTV(); + netDataStructs[NetMsg::svc_Sounds] = new NetMsg::SVC_Sounds(); + netDataStructs[NetMsg::svc_SetView] = new NetMsg::SVC_SetView(); + netDataStructs[NetMsg::svc_FixAngle] = new NetMsg::SVC_FixAngle(); + netDataStructs[NetMsg::svc_CrosshairAngle] = new NetMsg::SVC_CrosshairAngle(); + netDataStructs[NetMsg::svc_BSPDecal] = new NetMsg::SVC_BSPDecal(); + netDataStructs[NetMsg::svc_TerrainMod] = new NetMsg::SVC_TerrainMod(); + netDataStructs[NetMsg::svc_UserMessage] = new NetMsg::SVC_UserMessage(); + netDataStructs[NetMsg::svc_EntityMessage] = new NetMsg::SVC_EntityMessage(); + netDataStructs[NetMsg::svc_GameEvent] = new NetMsg::SVC_GameEvent(); + netDataStructs[NetMsg::svc_PacketEntities] = new NetMsg::SVC_PacketEntities(); + netDataStructs[NetMsg::svc_TempEntities] = new NetMsg::SVC_TempEntities(); + netDataStructs[NetMsg::svc_Prefetch] = new NetMsg::SVC_Prefetch(); + netDataStructs[NetMsg::svc_Menu] = new NetMsg::SVC_Menu(); + netDataStructs[NetMsg::svc_GameEventList] = new NetMsg::SVC_GameEventList(); + netDataStructs[NetMsg::svc_GetCvarValue] = new NetMsg::SVC_GetCvarValue(); + netDataStructs[NetMsg::svc_CmdKeyValues] = new NetMsg::SVC_CmdKeyValues(); + netDataStructs[NetMsg::svc_SetPauseTimed] = new NetMsg::SVC_SetPauseTimed(); } void NetHandlers::DestroyNetMsgStructs(NetDataStructArray& netDataStructs) { - delete reinterpret_cast(netDataStructs[0]); - delete reinterpret_cast(netDataStructs[1]); - delete reinterpret_cast(netDataStructs[2]); - delete reinterpret_cast(netDataStructs[3]); - delete reinterpret_cast(netDataStructs[4]); - delete reinterpret_cast(netDataStructs[5]); - delete reinterpret_cast(netDataStructs[6]); - delete reinterpret_cast(netDataStructs[7]); - delete reinterpret_cast(netDataStructs[8]); - delete reinterpret_cast(netDataStructs[9]); - delete reinterpret_cast(netDataStructs[10]); - delete reinterpret_cast(netDataStructs[11]); - delete reinterpret_cast(netDataStructs[12]); - delete reinterpret_cast(netDataStructs[13]); - delete reinterpret_cast(netDataStructs[14]); - delete reinterpret_cast(netDataStructs[15]); - delete reinterpret_cast(netDataStructs[16]); - delete reinterpret_cast(netDataStructs[17]); - delete reinterpret_cast(netDataStructs[18]); - delete reinterpret_cast(netDataStructs[19]); - delete reinterpret_cast(netDataStructs[20]); - delete reinterpret_cast(netDataStructs[21]); - delete reinterpret_cast(netDataStructs[22]); - delete reinterpret_cast(netDataStructs[23]); - delete reinterpret_cast(netDataStructs[24]); - delete reinterpret_cast(netDataStructs[25]); - delete reinterpret_cast(netDataStructs[26]); - delete reinterpret_cast(netDataStructs[27]); - delete reinterpret_cast(netDataStructs[28]); - delete reinterpret_cast(netDataStructs[29]); - delete reinterpret_cast(netDataStructs[30]); - delete reinterpret_cast(netDataStructs[31]); - delete reinterpret_cast(netDataStructs[32]); - delete reinterpret_cast(netDataStructs[33]); + delete reinterpret_cast(netDataStructs[NetMsg::net_NOP]); + delete reinterpret_cast(netDataStructs[NetMsg::net_Disconnect]); + delete reinterpret_cast(netDataStructs[NetMsg::net_File]); + delete reinterpret_cast(netDataStructs[NetMsg::net_Tick]); + delete reinterpret_cast(netDataStructs[NetMsg::net_StringCmd]); + delete reinterpret_cast(netDataStructs[NetMsg::net_SetConVar]); + delete reinterpret_cast(netDataStructs[NetMsg::net_SignonState]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_Print]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_ServerInfo]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_SendTable]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_ClassInfo]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_SetPause]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_CreateStringTable]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_UpdateStringTable]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_VoiceInit]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_VoiceData]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_HLTV]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_Sounds]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_SetView]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_FixAngle]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_CrosshairAngle]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_BSPDecal]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_TerrainMod]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_UserMessage]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_EntityMessage]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_GameEvent]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_PacketEntities]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_TempEntities]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_Prefetch]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_Menu]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_GameEventList]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_GetCvarValue]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_CmdKeyValues]); + delete reinterpret_cast(netDataStructs[NetMsg::svc_SetPauseTimed]); } #define DECLARE_NET_HANDLER_ARRAY(funcname) \ @@ -158,10 +158,6 @@ void NetHandlers::DestroyNetMsgStructs(NetDataStructArray& netDataStructs) } typedef bool (*NetMsgBitReadFn)(NetHandlers::BitRead& bitbuf, SourceGameContext& context, void* data); -typedef bool (*NetMsgBitWriteFn)(NetHandlers::BitWrite& bitbuf, const SourceGameContext& context, void* data); -typedef bool (*NetMsgJsonReadFn)(NetHandlers::JsonRead& jsonbuf, SourceGameContext& context, void* data); -typedef bool (*NetMsgJsonWriteFn)(NetHandlers::JsonWrite& jsonbuf, const SourceGameContext& context, void* data); -typedef void (*NetMsgToStringFn)(std::ostringstream& out, void* data); template bool NetMsgFuncRunner(const FnType (&netHandlers)[NumHandlers], uint32_t type, BufType& buf, ContextType& context, void* data) @@ -179,30 +175,3 @@ bool NetHandlers::NetMsg_BitRead(uint32_t type, BitRead& bitbuf, SourceGameConte return NetMsgFuncRunner(netHandlers, type, bitbuf, context, data); } -bool NetHandlers::NetMsg_BitWrite(uint32_t type, BitWrite& bitbuf, const SourceGameContext& context, void* data) -{ - static const NetMsgBitWriteFn netHandlers[] = DECLARE_NET_HANDLER_ARRAY(BitWrite); - return NetMsgFuncRunner(netHandlers, type, bitbuf, context, data); -} - -bool NetHandlers::NetMsg_JsonRead(uint32_t type, JsonRead& jsonbuf, SourceGameContext& context, void* data) -{ - static const NetMsgJsonReadFn netHandlers[] = DECLARE_NET_HANDLER_ARRAY(JsonRead); - return NetMsgFuncRunner(netHandlers, type, jsonbuf, context, data); -} - -bool NetHandlers::NetMsg_JsonWrite(uint32_t type, JsonWrite& jsonbuf, const SourceGameContext& context, void* data) -{ - static const NetMsgJsonWriteFn netHandlers[] = DECLARE_NET_HANDLER_ARRAY(JsonWrite); - return NetMsgFuncRunner(netHandlers, type, jsonbuf, context, data); -} - -void NetHandlers::NetMsg_ToString(uint32_t type, std::ostringstream& out, void* data) -{ - static const NetMsgToStringFn netHandlers[] = DECLARE_NET_HANDLER_ARRAY(ToString); - if (type >= (sizeof(netHandlers) / sizeof(NetMsgToStringFn))) - { - return; - } - netHandlers[type](out, data); -} diff --git a/demboyz/netmessages/nethandlers.h b/demboyz/netmessages/nethandlers.h index 6e63080..c067c82 100644 --- a/demboyz/netmessages/nethandlers.h +++ b/demboyz/netmessages/nethandlers.h @@ -6,23 +6,11 @@ #include #include "netmessages.h" -namespace base -{ - class JsonReaderFile; - class JsonWriterFile; - class BitFileRead; - class BitFileWrite; -} - class bf_read; -class bf_write; namespace NetHandlers { using BitRead = bf_read; - using BitWrite = bf_write; - using JsonRead = base::JsonReaderFile; - using JsonWrite = base::JsonWriterFile; } struct SourceGameContext; @@ -35,30 +23,10 @@ struct SourceGameContext; namespace NetHandlers \ { \ bool msgname##_BitRead_Internal(BitRead& bitbuf, SourceGameContext& context, NetMsg::msgname* data); \ - bool msgname##_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::msgname* data); \ - bool msgname##_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::msgname* data); \ - bool msgname##_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::msgname* data); \ - void msgname##_ToString_Internal(std::ostringstream& out, NetMsg::msgname* data); \ inline bool msgname##_BitRead(BitRead& bitbuf, SourceGameContext& context, void* data) \ { \ return msgname##_BitRead_Internal(bitbuf, context, reinterpret_cast(data)); \ } \ - inline bool msgname##_BitWrite(BitWrite& bitbuf, const SourceGameContext& context, void* data) \ - { \ - return msgname##_BitWrite_Internal(bitbuf, context, reinterpret_cast(data)); \ - } \ - inline bool msgname##_JsonRead(JsonRead& jsonbuf, SourceGameContext& context, void* data) \ - { \ - return msgname##_JsonRead_Internal(jsonbuf, context, reinterpret_cast(data)); \ - } \ - inline bool msgname##_JsonWrite(JsonWrite& jsonbuf, const SourceGameContext& context, void* data) \ - { \ - return msgname##_JsonWrite_Internal(jsonbuf, context, reinterpret_cast(data)); \ - } \ - inline void msgname##_ToString(std::ostringstream& out, void* data) \ - { \ - msgname##_ToString_Internal(out, reinterpret_cast(data)); \ - } \ } namespace NetHandlers @@ -68,8 +36,4 @@ namespace NetHandlers void DestroyNetMsgStructs(NetDataStructArray& netDataStructs); bool NetMsg_BitRead(uint32_t type, BitRead& bitbuf, SourceGameContext& context, void* data); - bool NetMsg_BitWrite(uint32_t type, BitWrite& bitbuf, const SourceGameContext& context, void* data); - bool NetMsg_JsonRead(uint32_t type, JsonRead& jsonbuf, SourceGameContext& context, void* data); - bool NetMsg_JsonWrite(uint32_t type, JsonWrite& jsonbuf, const SourceGameContext& context, void* data); - void NetMsg_ToString(uint32_t type, std::ostringstream& out, void* data); } diff --git a/demboyz/netmessages/netmath.cpp b/demboyz/netmessages/netmath.cpp new file mode 100644 index 0000000..abb6377 --- /dev/null +++ b/demboyz/netmessages/netmath.cpp @@ -0,0 +1,18 @@ + +#include "netmath.h" + +namespace math +{ + uint32_t log2(uint32_t value) + { + uint32_t res = 0; + while (value >>= 1) + ++res; + return res; + } + + uint32_t BitsToBytes(uint32_t bits) + { + return ((bits + 7) >> 3); + } +} diff --git a/demboyz/netmessages/netmath.h b/demboyz/netmessages/netmath.h index 95356b3..5804bce 100644 --- a/demboyz/netmessages/netmath.h +++ b/demboyz/netmessages/netmath.h @@ -1,20 +1,11 @@ #pragma once -#include +#include namespace math { - static size_t log2(size_t value) - { - size_t res = 0; - while (value >>= 1) - ++res; - return res; - } + uint32_t log2(uint32_t value); - static size_t BitsToBytes(size_t bits) - { - return ((bits + 7) >> 3); - } + uint32_t BitsToBytes(uint32_t bits); } diff --git a/demboyz/netmessages/netmessages.h b/demboyz/netmessages/netmessages.h index 1c1ee1b..6c131f7 100644 --- a/demboyz/netmessages/netmessages.h +++ b/demboyz/netmessages/netmessages.h @@ -31,7 +31,7 @@ namespace NetMsg svc_VoiceInit = 14, // inits used voice codecs & quality svc_VoiceData = 15, // Voicestream data from the server - //svc_HLTV = 16, // HLTV control messages + svc_HLTV = 16, // HLTV control messages svc_Sounds = 17, // starts playing sound @@ -42,10 +42,10 @@ namespace NetMsg svc_BSPDecal = 21, // add a static decal to the world BSP // NOTE: This is now unused! - // svc_TerrainMod = 22, // modification to the terrain/displacement + svc_TerrainMod = 22, // modification to the terrain/displacement // Message from server side to client side entity - svc_UserMessage = 23, // a game specific message + svc_UserMessage = 23, // a game specific message svc_EntityMessage = 24, // a message for an entity svc_GameEvent = 25, // global game event fired diff --git a/demboyz/netmessages/svc_bspdecal.cpp b/demboyz/netmessages/svc_bspdecal.cpp index d3434b8..55f18d3 100644 --- a/demboyz/netmessages/svc_bspdecal.cpp +++ b/demboyz/netmessages/svc_bspdecal.cpp @@ -1,8 +1,6 @@ #include "svc_bspdecal.h" #include "base/bitfile.h" -#include "base/jsonfile.h" -#include "demofile/demojson.h" #include "netcontants.h" namespace NetHandlers @@ -24,55 +22,4 @@ namespace NetHandlers data->lowPriority = bitbuf.ReadOneBit() != 0; return !bitbuf.IsOverflowed(); } - - bool SVC_BSPDecal_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_BSPDecal* data) - { - bitbuf.WriteBitVec3Coord(data->position); - bitbuf.WriteUBitLong(data->decalTextureIndex, MAX_DECAL_INDEX_BITS); - if (data->entIndex != 0) - { - bitbuf.WriteOneBit(1); - bitbuf.WriteUBitLong(data->entIndex, MAX_EDICT_BITS); - bitbuf.WriteUBitLong(data->modelIndex, SP_MODEL_INDEX_BITS); - } - else - { - bitbuf.WriteOneBit(0); - } - bitbuf.WriteOneBit(data->lowPriority); - return !bitbuf.IsOverflowed(); - } - - bool SVC_BSPDecal_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_BSPDecal* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - DemoJsonReader::ReadVector(reader, "position", data->position); - data->decalTextureIndex = reader.ReadUInt32("decalTextureIndex"); - data->entIndex = reader.ReadUInt32("entIndex"); - data->modelIndex = reader.ReadUInt32("modelIndex"); - data->lowPriority = reader.ReadBool("lowPriority"); - return !reader.HasReadError(); - } - - bool SVC_BSPDecal_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_BSPDecal* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - DemoJsonWriter::WriteVector(jsonbuf, "position", data->position); - jsonbuf.WriteUInt32("decalTextureIndex", data->decalTextureIndex); - jsonbuf.WriteUInt32("entIndex", data->entIndex); - jsonbuf.WriteUInt32("modelIndex", data->modelIndex); - jsonbuf.WriteBool("lowPriority", data->lowPriority); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_BSPDecal_ToString_Internal(std::ostringstream& out, NetMsg::SVC_BSPDecal* data) - { - out << "svc_BSPDecal: tex " << data->decalTextureIndex - << ", ent " << data->entIndex - << ", mod " << data->modelIndex - << " lowpriority " << data->lowPriority; - } } diff --git a/demboyz/netmessages/svc_classinfo.cpp b/demboyz/netmessages/svc_classinfo.cpp index 34489f6..eea1296 100644 --- a/demboyz/netmessages/svc_classinfo.cpp +++ b/demboyz/netmessages/svc_classinfo.cpp @@ -1,7 +1,6 @@ #include "svc_classinfo.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netmath.h" using class_t = NetMsg::SVC_ClassInfo::class_t; @@ -27,67 +26,4 @@ namespace NetHandlers } return !bitbuf.IsOverflowed(); } - - bool SVC_ClassInfo_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_ClassInfo* data) - { - bitbuf.WriteShort(data->numServerClasses); - bitbuf.WriteOneBit(data->createOnClient); - if (!data->createOnClient) - { - const int numServerClassBits = math::log2(data->numServerClasses) + 1; - for (class_t& serverClass : data->serverClasses) - { - bitbuf.WriteUBitLong(serverClass.classID, numServerClassBits); - bitbuf.WriteString(serverClass.className); - bitbuf.WriteString(serverClass.dataTableName); - } - } - return !bitbuf.IsOverflowed(); - } - - bool SVC_ClassInfo_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_ClassInfo* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->numServerClasses = reader.ReadInt32("numServerClasses"); - data->createOnClient = reader.ReadBool("createOnClient"); - if (!data->createOnClient) - { - base::JsonReaderArray serverClasses = reader.ReadArray("serverClasses"); - serverClasses.TransformTo(data->serverClasses, [](base::JsonReaderObject& obj, class_t& serverClass) - { - serverClass.classID = obj.ReadUInt32("classId"); - obj.ReadString("className", serverClass.className, sizeof(serverClass.className)); - obj.ReadString("dataTableName", serverClass.dataTableName, sizeof(serverClass.dataTableName)); - }); - } - return !reader.HasReadError(); - } - - bool SVC_ClassInfo_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_ClassInfo* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("numServerClasses", data->numServerClasses); - jsonbuf.WriteBool("createOnClient", data->createOnClient); - if (!data->createOnClient) - { - jsonbuf.StartArray("serverClasses"); - for (class_t& serverClass : data->serverClasses) - { - jsonbuf.WriteUInt32("classId", serverClass.classID); - jsonbuf.WriteString("className", serverClass.className); - jsonbuf.WriteString("dataTableName", serverClass.dataTableName); - } - jsonbuf.EndArray(); - } - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_ClassInfo_ToString_Internal(std::ostringstream& out, NetMsg::SVC_ClassInfo* data) - { - out << "svc_ClassInfo: num " << data->numServerClasses - << ", " << (data->createOnClient ? "use client classes" : "full update"); - } } diff --git a/demboyz/netmessages/svc_cmdkeyvalues.cpp b/demboyz/netmessages/svc_cmdkeyvalues.cpp index 7e2e5fa..d393406 100644 --- a/demboyz/netmessages/svc_cmdkeyvalues.cpp +++ b/demboyz/netmessages/svc_cmdkeyvalues.cpp @@ -1,7 +1,6 @@ #include "svc_cmdkeyvalues.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -11,28 +10,4 @@ namespace NetHandlers assert(false); return true; } - - bool SVC_CmdKeyValues_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_CmdKeyValues* data) - { - assert(false); - return true; - } - - bool SVC_CmdKeyValues_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_CmdKeyValues* data) - { - assert(false); - return true; - } - - bool SVC_CmdKeyValues_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_CmdKeyValues* data) - { - assert(false); - return true; - } - - void SVC_CmdKeyValues_ToString_Internal(std::ostringstream& out, NetMsg::SVC_CmdKeyValues* data) - { - assert(false); - out << "svc_CmdKeyValues"; - } } diff --git a/demboyz/netmessages/svc_createstringtable.cpp b/demboyz/netmessages/svc_createstringtable.cpp index fd18c4a..0f0c9f6 100644 --- a/demboyz/netmessages/svc_createstringtable.cpp +++ b/demboyz/netmessages/svc_createstringtable.cpp @@ -1,94 +1,14 @@ #include "svc_createstringtable.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "game/sourcecontext.h" +#include "game/stringtables.h" #include "netmath.h" #include "netcontants.h" -// #define WIP_STRINGTABLE - -#ifdef WIP_STRINGTABLE #include "sourcesdk/common.h" #include -#define SUBSTRING_BITS 5 -struct StringHistoryEntry -{ - char string[(1 << SUBSTRING_BITS)]; -}; - -static void StringTable_BitRead(NetHandlers::BitRead& bitbuf, SourceGameContext& context, NetMsg::SVC_CreateStringTable* data) -{ - const size_t numEncodeBits = math::log2(data->maxEntries); - std::vector history; - int entryIndex = -1; - for (uint i = 0; i < data->numEntries; ++i) - { - entryIndex++; - - if (bitbuf.ReadOneBit() == 0) - { - entryIndex = bitbuf.ReadUBitLong(numEncodeBits); - } - - const char *pEntry = NULL; - char entry[1024]; - char substr[1024]; - if (bitbuf.ReadOneBit() != 0) - { - bool substringcheck = bitbuf.ReadOneBit() != 0; - if (substringcheck) - { - int index = bitbuf.ReadUBitLong(5); - int bytestocopy = bitbuf.ReadUBitLong(SUBSTRING_BITS); - strncpy(entry, history.at(index).string, bytestocopy + 1); - entry[bytestocopy + 1] = '\0'; - bitbuf.ReadString(substr, sizeof(substr)); - strncat(entry, substr, sizeof(entry)); - } - else - { - bitbuf.ReadString(entry, sizeof(entry)); - } - pEntry = entry; - printf("%s\n", pEntry); - } - const int MAX_USERDATA_BITS = 14; - unsigned char tempbuf[(1 << MAX_USERDATA_BITS)] = { 0 }; - const void *pUserData = NULL; - if (bitbuf.ReadOneBit() != 0) - { - if (data->isUserDataFixedSize) - { - bitbuf.ReadBits(tempbuf, data->userDataSizeBits); - } - else - { - int nBytes = bitbuf.ReadUBitLong(MAX_USERDATA_BITS); - bitbuf.ReadBytes(tempbuf, nBytes); - } - pUserData = tempbuf; - } - - if (pEntry == NULL) - { - pEntry = ""; - } - - if (history.size() > 31) - { - history.erase(history.begin()); - } - - StringHistoryEntry she; - strncpy(she.string, pEntry, sizeof(she.string)); - history.emplace_back(she); - } -} - -#endif // WIP_STRINGTABLE - namespace NetHandlers { bool SVC_CreateStringTable_BitRead_Internal(BitRead& bitbuf, SourceGameContext& context, NetMsg::SVC_CreateStringTable* data) @@ -105,21 +25,18 @@ namespace NetHandlers bitbuf.ReadString(data->tableName, sizeof(data->tableName)); data->maxEntries = bitbuf.ReadWord(); - const size_t numEncodeBits = math::log2(data->maxEntries); + const uint32_t numEncodeBits = math::log2(data->maxEntries); data->numEntries = bitbuf.ReadUBitLong(numEncodeBits + 1); - size_t dataLengthInBits; if (context.protocol > 23) { - dataLengthInBits = bitbuf.ReadVarInt32(); - data->dataLengthInBits = dataLengthInBits; + data->dataLengthInBits = bitbuf.ReadVarInt32(); } else { - dataLengthInBits = bitbuf.ReadUBitLong(NET_MAX_PAYLOAD_BITS_OLD + 3); - data->dataLengthInBits = dataLengthInBits; + data->dataLengthInBits = bitbuf.ReadUBitLong(NET_MAX_PAYLOAD_BITS_OLD + 3); } - const size_t dataLengthInBytes = math::BitsToBytes(dataLengthInBits); + const uint32_t dataLengthInBytes = math::BitsToBytes(data->dataLengthInBits); data->isUserDataFixedSize = bitbuf.ReadOneBit() != 0; if (data->isUserDataFixedSize) @@ -136,13 +53,24 @@ namespace NetHandlers { data->compressedData = bitbuf.ReadOneBit() != 0; } - data->data.reset(new uint8_t[dataLengthInBytes]); - bitbuf.ReadBits(data->data.get(), dataLengthInBits); + else + { + data->compressedData = false; + } + + data->data.reset(new uint8_t[dataLengthInBytes]); + bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); + + StringTable *table = context.stringTables->GetStringTable(data->tableName, true); + table->maxEntries = data->maxEntries; + table->isUserDataFixedSize = data->isUserDataFixedSize; + table->userDataSize = data->userDataSize; + table->userDataSizeBits = data->userDataSizeBits; + table->entryBits = math::log2(table->maxEntries); -#ifdef WIP_STRINGTABLE if (data->compressedData) { - bf_read bitbuf2(data->data.get(), dataLengthInBytes, dataLengthInBits); + bf_read bitbuf2(data->data.get(), dataLengthInBytes, data->dataLengthInBits); const uint32_t decompressedNumBytes = bitbuf2.ReadUBitLong(32); const uint32_t compressedNumBytes = bitbuf2.ReadUBitLong(32); std::unique_ptr compressedData(new uint8[compressedNumBytes]); @@ -150,98 +78,16 @@ namespace NetHandlers bitbuf2.ReadBytes(compressedData.get(), compressedNumBytes); uint32_t numWritten = COM_BufferToBufferDecompress(uncompressedData.get(), decompressedNumBytes, compressedData.get(), compressedNumBytes); + assert(numWritten == decompressedNumBytes); bitbuf2 = bf_read(uncompressedData.get(), decompressedNumBytes); - StringTable_BitRead(bitbuf2, context, data); + table->ParseUpdate(bitbuf2, data->numEntries, context); } - else + else if(dataLengthInBytes) { - bf_read bitbuf2(data->data.get(), dataLengthInBytes, dataLengthInBits); - StringTable_BitRead(bitbuf2, context, data); + bf_read bitbuf2(data->data.get(), dataLengthInBytes, data->dataLengthInBits); + table->ParseUpdate(bitbuf2, data->numEntries, context); } -#endif // WIP_STRINGTABLE return !bitbuf.IsOverflowed(); } - - bool SVC_CreateStringTable_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_CreateStringTable* data) - { - if (data->isFileNames) - { - bitbuf.WriteByte(':'); - } - bitbuf.WriteString(data->tableName); - bitbuf.WriteWord(data->maxEntries); - bitbuf.WriteUBitLong(data->numEntries, math::log2(data->maxEntries) + 1); - if (context.protocol > 23) - { - bitbuf.WriteVarInt32(data->dataLengthInBits); - } - else - { - bitbuf.WriteUBitLong(data->dataLengthInBits, NET_MAX_PAYLOAD_BITS_OLD + 3); - } - bitbuf.WriteOneBit(data->isUserDataFixedSize); - if (data->isUserDataFixedSize) - { - bitbuf.WriteUBitLong(data->userDataSize, 12); - bitbuf.WriteUBitLong(data->userDataSizeBits, 4); - } - if (context.protocol > 14) - { - bitbuf.WriteOneBit(data->compressedData); - } - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_CreateStringTable_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_CreateStringTable* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->isFileNames = reader.ReadBool("isFilenames"); - reader.ReadString("tableName", data->tableName, sizeof(data->tableName)); - data->maxEntries = reader.ReadUInt32("maxEntries"); - data->numEntries = reader.ReadUInt32("numEntries"); - data->dataLengthInBits = reader.ReadInt32("dataLengthInBits"); - data->isUserDataFixedSize = reader.ReadBool("isUserDataFixedSize"); - data->userDataSize = reader.ReadUInt32("userDataSize"); - data->userDataSizeBits = reader.ReadUInt32("userDataSizeBits"); - if (context.protocol > 14) - { - data->compressedData = reader.ReadBool("compressedData"); - } - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_CreateStringTable_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_CreateStringTable* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("isFilenames", data->isFileNames); - jsonbuf.WriteString("tableName", data->tableName); - jsonbuf.WriteUInt32("maxEntries", data->maxEntries); - jsonbuf.WriteUInt32("numEntries", data->numEntries); - jsonbuf.WriteInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBool("isUserDataFixedSize", data->isUserDataFixedSize); - jsonbuf.WriteUInt32("userDataSize", data->userDataSize); - jsonbuf.WriteUInt32("userDataSizeBits", data->userDataSizeBits); - if (context.protocol > 14) - { - jsonbuf.WriteBool("compressedData", data->compressedData); - } - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_CreateStringTable_ToString_Internal(std::ostringstream& out, NetMsg::SVC_CreateStringTable* data) - { - out << "svc_CreateStringTable: table " << data->tableName - << ", entries " << data->numEntries - << ", bytes " << math::BitsToBytes(data->dataLengthInBits) - << " userdatasize " << data->userDataSize - << " userdatabits " << static_cast(data->userDataSizeBits); - } } diff --git a/demboyz/netmessages/svc_crosshairangle.cpp b/demboyz/netmessages/svc_crosshairangle.cpp index cfd7fa6..3191737 100644 --- a/demboyz/netmessages/svc_crosshairangle.cpp +++ b/demboyz/netmessages/svc_crosshairangle.cpp @@ -1,9 +1,6 @@ #include "svc_crosshairangle.h" #include "base/bitfile.h" -#include "base/jsonfile.h" -#include "demofile/demojson.h" -#include namespace NetHandlers { @@ -14,41 +11,4 @@ namespace NetHandlers data->angle.z = bitbuf.ReadBitAngle(16); return !bitbuf.IsOverflowed(); } - - bool SVC_CrosshairAngle_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_CrosshairAngle* data) - { - bitbuf.WriteBitAngle(data->angle.x, 16); - bitbuf.WriteBitAngle(data->angle.y, 16); - bitbuf.WriteBitAngle(data->angle.z, 16); - return !bitbuf.IsOverflowed(); - } - - bool SVC_CrosshairAngle_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_CrosshairAngle* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - DemoJsonReader::ReadAngle(reader, "angle", data->angle); - return !reader.HasReadError(); - } - - bool SVC_CrosshairAngle_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_CrosshairAngle* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - DemoJsonWriter::WriteAngle(jsonbuf, "angle", data->angle); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_CrosshairAngle_ToString_Internal(std::ostringstream& out, NetMsg::SVC_CrosshairAngle* data) - { - const std::streamsize oldPrecision = out.precision(); - out << "svc_CrosshairAngle:" - << std::setprecision(1) << std::fixed - << " (" << data->angle.x - << " " << data->angle.y - << " " << data->angle.z << ")" - << std::setprecision(oldPrecision); - out.unsetf(std::ios_base::floatfield); - } } diff --git a/demboyz/netmessages/svc_entitymessage.cpp b/demboyz/netmessages/svc_entitymessage.cpp index 125ed4b..85935d2 100644 --- a/demboyz/netmessages/svc_entitymessage.cpp +++ b/demboyz/netmessages/svc_entitymessage.cpp @@ -1,7 +1,6 @@ #include "svc_entitymessage.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netcontants.h" #include "netmath.h" @@ -16,44 +15,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_EntityMessage_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_EntityMessage* data) - { - bitbuf.WriteUBitLong(data->entIndex, MAX_EDICT_BITS); - bitbuf.WriteUBitLong(data->classID, MAX_SERVER_CLASS_BITS); - bitbuf.WriteUBitLong(data->dataLengthInBits, 11); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_EntityMessage_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_EntityMessage* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->entIndex = reader.ReadUInt32("entIndex"); - data->classID = reader.ReadUInt32("classId"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_EntityMessage_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_EntityMessage* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("entIndex", data->entIndex); - jsonbuf.WriteUInt32("classId", data->classID); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_EntityMessage_ToString_Internal(std::ostringstream& out, NetMsg::SVC_EntityMessage* data) - { - out << "svc_EntityMessage: entity " << data->entIndex - << ", class " << data->classID - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_fixangle.cpp b/demboyz/netmessages/svc_fixangle.cpp index d033e5a..b4ca1e6 100644 --- a/demboyz/netmessages/svc_fixangle.cpp +++ b/demboyz/netmessages/svc_fixangle.cpp @@ -1,9 +1,6 @@ #include "svc_fixangle.h" #include "base/bitfile.h" -#include "base/jsonfile.h" -#include "demofile/demojson.h" -#include namespace NetHandlers { @@ -15,44 +12,4 @@ namespace NetHandlers data->angle.z = bitbuf.ReadBitAngle(16); return !bitbuf.IsOverflowed(); } - - bool SVC_FixAngle_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_FixAngle* data) - { - bitbuf.WriteOneBit(data->relative); - bitbuf.WriteBitAngle(data->angle.x, 16); - bitbuf.WriteBitAngle(data->angle.y, 16); - bitbuf.WriteBitAngle(data->angle.z, 16); - return !bitbuf.IsOverflowed(); - } - - bool SVC_FixAngle_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_FixAngle* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->relative = reader.ReadBool("relative"); - DemoJsonReader::ReadAngle(reader, "angle", data->angle); - return !reader.HasReadError(); - } - - bool SVC_FixAngle_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_FixAngle* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("relative", data->relative); - DemoJsonWriter::WriteAngle(jsonbuf, "angle", data->angle); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_FixAngle_ToString_Internal(std::ostringstream& out, NetMsg::SVC_FixAngle* data) - { - const std::streamsize oldPrecision = out.precision(); - out << "svc_FixAngle: " << (data->relative ? "relative" : "absolute") - << std::setprecision(1) << std::fixed - << " " << data->angle.x - << " " << data->angle.y - << " " << data->angle.z - << std::setprecision(oldPrecision); - out.unsetf(std::ios_base::floatfield); - } } diff --git a/demboyz/netmessages/svc_gameevent.cpp b/demboyz/netmessages/svc_gameevent.cpp index 50fd9f7..212db57 100644 --- a/demboyz/netmessages/svc_gameevent.cpp +++ b/demboyz/netmessages/svc_gameevent.cpp @@ -1,13 +1,10 @@ #include "svc_gameevent.h" #include "base/bitfile.h" -#include "base/jsonfile.h" +#include "game/sourcecontext.h" #include "netcontants.h" #include "netmath.h" - -#ifdef WIP_GAMEEVENTS #include "svc_gameeventlist.h" -#endif namespace NetHandlers { @@ -20,49 +17,12 @@ namespace NetHandlers data->data.reset(new uint8_t[numBytes]); bitbuf.ReadBits(data->data.get(), numBits); -#ifdef WIP_GAMEEVENTS - { - BitRead bitbuf2(data->data.get(), numBytes, numBits); - const size_t id = bitbuf2.ReadUBitLong(9); - //std::vector stringMem; - //GameEvents::ParseEventData(bitbuf2, context.gameEventList->eventDescriptors[id], stringMem); - GameEvents::PrintEventData(bitbuf2, context.gameEventList->eventDescriptors[id]); - printf("%i\n", id); - } -#endif // WIP_GAMEEVENTS + BitRead bitbuf2(data->data.get(), numBytes, numBits); + const size_t id = bitbuf2.ReadUBitLong(9); + GameEvents::EventDataMap eventData = GameEvents::ParseEventData(bitbuf2, context.gameEventList->eventDescriptors[id]); + + context.OnGameEvent(context.gameEventList->eventDescriptors[id].name, eventData); return !bitbuf.IsOverflowed(); } - - bool SVC_GameEvent_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_GameEvent* data) - { - bitbuf.WriteUBitLong(data->dataLengthInBits, 11); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_GameEvent_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_GameEvent* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_GameEvent_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_GameEvent* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_GameEvent_ToString_Internal(std::ostringstream& out, NetMsg::SVC_GameEvent* data) - { - out << "svc_GameEvent: bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_gameeventlist.cpp b/demboyz/netmessages/svc_gameeventlist.cpp index 37856bc..85a035a 100644 --- a/demboyz/netmessages/svc_gameeventlist.cpp +++ b/demboyz/netmessages/svc_gameeventlist.cpp @@ -1,7 +1,6 @@ #include "svc_gameeventlist.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "game/sourcecontext.h" #include "netcontants.h" #include "netmath.h" @@ -47,84 +46,11 @@ namespace NetHandlers event.values.shrink_to_fit(); } -#ifdef WIP_GAMEEVENTS if (!context.gameEventList) { context.gameEventList = new NetMsg::SVC_GameEventList(*data); } -#endif + return !bitbuf.IsOverflowed(); } - - bool SVC_GameEventList_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_GameEventList* data) - { - bitbuf.WriteUBitLong(data->eventDescriptors.size(), MAX_EVENT_BITS); - bitbuf.WriteUBitLong(data->dataLengthInBits, 20); - assert(data->dataLengthInBits == CalculateNumDataBits(data->eventDescriptors)); - for (EventDescriptor& event : data->eventDescriptors) - { - bitbuf.WriteUBitLong(event.id, MAX_EVENT_BITS); - bitbuf.WriteString(event.name); - for (EventValue& value : event.values) - { - bitbuf.WriteUBitLong(value.type, 3); - bitbuf.WriteString(value.name); - } - bitbuf.WriteUBitLong(0, 3); - } - return !bitbuf.IsOverflowed(); - } - - bool SVC_GameEventList_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_GameEventList* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - - base::JsonReaderArray eventDescriptors = reader.ReadArray("eventDescriptors"); - eventDescriptors.TransformTo(data->eventDescriptors, [](base::JsonReaderObject& obj, EventDescriptor& event) - { - event.id = obj.ReadUInt32("id"); - obj.ReadString("name", event.name, sizeof(event.name)); - base::JsonReaderArray values = obj.ReadArray("values"); - values.TransformTo(event.values, [](base::JsonReaderObject& obj, EventValue& value) - { - value.type = static_cast(obj.ReadUInt32("type")); - obj.ReadString("name", value.name, sizeof(value.name)); - }); - }); - data->dataLengthInBits = CalculateNumDataBits(data->eventDescriptors); - return !reader.HasReadError(); - } - - bool SVC_GameEventList_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_GameEventList* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.StartArray("eventDescriptors"); - for (const EventDescriptor& event : data->eventDescriptors) - { - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("id", event.id); - jsonbuf.WriteString("name", event.name); - jsonbuf.StartArray("values"); - for (const EventValue& value : event.values) - { - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("type", value.type); - jsonbuf.WriteString("name", value.name); - jsonbuf.EndObject(); - } - jsonbuf.EndArray(); - jsonbuf.EndObject(); - } - jsonbuf.EndArray(); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_GameEventList_ToString_Internal(std::ostringstream& out, NetMsg::SVC_GameEventList* data) - { - out << "svc_GameEventList: number " << data->eventDescriptors.size() - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_getcvarvalue.cpp b/demboyz/netmessages/svc_getcvarvalue.cpp index e9defe1..641e779 100644 --- a/demboyz/netmessages/svc_getcvarvalue.cpp +++ b/demboyz/netmessages/svc_getcvarvalue.cpp @@ -1,7 +1,6 @@ #include "svc_getcvarvalue.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -11,36 +10,4 @@ namespace NetHandlers bitbuf.ReadString(data->cvarName, sizeof(data->cvarName)); return !bitbuf.IsOverflowed(); } - - bool SVC_GetCvarValue_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_GetCvarValue* data) - { - bitbuf.WriteSBitLong(data->cookie, 32); - bitbuf.WriteString(data->cvarName); - return !bitbuf.IsOverflowed(); - } - - bool SVC_GetCvarValue_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_GetCvarValue* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->cookie = reader.ReadInt32("cookie"); - reader.ReadString("cvarName", data->cvarName, sizeof(data->cvarName)); - return !reader.HasReadError(); - } - - bool SVC_GetCvarValue_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_GetCvarValue* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("cookie", data->cookie); - jsonbuf.WriteString("cvarName", data->cvarName); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_GetCvarValue_ToString_Internal(std::ostringstream& out, NetMsg::SVC_GetCvarValue* data) - { - out << "svc_GetCvarValue: cvar: " << data->cvarName - << ", cookie: " << data->cookie; - } } diff --git a/demboyz/netmessages/svc_hltv.cpp b/demboyz/netmessages/svc_hltv.cpp index f9aec64..6cd986d 100644 --- a/demboyz/netmessages/svc_hltv.cpp +++ b/demboyz/netmessages/svc_hltv.cpp @@ -9,27 +9,4 @@ namespace NetHandlers assert(false); return true; } - - bool SVC_HLTV_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_HLTV* data) - { - assert(false); - return true; - } - - bool SVC_HLTV_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_HLTV* data) - { - assert(false); - return true; - } - - bool SVC_HLTV_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_HLTV* data) - { - assert(false); - return true; - } - - void SVC_HLTV_ToString_Internal(std::ostringstream& out, NetMsg::SVC_HLTV* data) - { - out << "svc_HLTV"; - } } diff --git a/demboyz/netmessages/svc_menu.cpp b/demboyz/netmessages/svc_menu.cpp index e8f710b..ccc651b 100644 --- a/demboyz/netmessages/svc_menu.cpp +++ b/demboyz/netmessages/svc_menu.cpp @@ -1,21 +1,9 @@ #include "svc_menu.h" #include "base/bitfile.h" -#include "base/jsonfile.h" using DialogType = NetMsg::SVC_Menu::DialogType; -#define KEYVALUES_TOKEN_SIZE 1024 - -static const char* KeyValuesBin_GetName(uint8_t* data, size_t dataLength) -{ - if (dataLength <= 2) - { - return nullptr; - } - return reinterpret_cast(data + 1); -} - namespace NetHandlers { bool SVC_Menu_BitRead_Internal(BitRead& bitbuf, SourceGameContext& context, NetMsg::SVC_Menu* data) @@ -26,44 +14,4 @@ namespace NetHandlers bitbuf.ReadBytes(data->menuBinaryKeyValues.get(), data->dataLengthInBytes); return !bitbuf.IsOverflowed(); } - - bool SVC_Menu_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_Menu* data) - { - bitbuf.WriteShort(static_cast(data->type)); - bitbuf.WriteWord(data->dataLengthInBytes); - bitbuf.WriteBytes(data->menuBinaryKeyValues.get(), data->dataLengthInBytes); - return !bitbuf.IsOverflowed(); - } - - bool SVC_Menu_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_Menu* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->type = static_cast(reader.ReadInt32("dialogType")); - data->dataLengthInBytes = reader.ReadUInt32("dataLengthInBytes"); - data->menuBinaryKeyValues.reset(new uint8_t[data->dataLengthInBytes]); - reader.ReadBytes("data", data->menuBinaryKeyValues.get(), data->dataLengthInBytes); - return !reader.HasReadError(); - } - - bool SVC_Menu_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_Menu* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("dialogType", static_cast(data->type)); - jsonbuf.WriteUInt32("dataLengthInBytes", data->dataLengthInBytes); - jsonbuf.WriteBytes("data", data->menuBinaryKeyValues.get(), data->dataLengthInBytes); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_Menu_ToString_Internal(std::ostringstream& out, NetMsg::SVC_Menu* data) - { - // binary keyvalues in form [type][name][value] - // [char][cstr][type] - const char* name = KeyValuesBin_GetName(data->menuBinaryKeyValues.get(), data->dataLengthInBytes); - out << "svc_Menu: " << static_cast(data->type) - << " \"" << (name ? name : "No KeyValues") - << "\" (len:" << data->dataLengthInBytes << ")"; - } } diff --git a/demboyz/netmessages/svc_packetentities.cpp b/demboyz/netmessages/svc_packetentities.cpp index 5ec02e2..c92b08a 100644 --- a/demboyz/netmessages/svc_packetentities.cpp +++ b/demboyz/netmessages/svc_packetentities.cpp @@ -1,7 +1,6 @@ #include "svc_packetentities.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netcontants.h" #include "netmath.h" @@ -25,67 +24,35 @@ namespace NetHandlers data->updateBaseline = bitbuf.ReadOneBit() != 0; data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_PacketEntities_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_PacketEntities* data) - { - bitbuf.WriteUBitLong(data->maxEntries, MAX_EDICT_BITS); - if (data->isDelta) +/* + int last_index = -1; + for (int i = 0; i < data->numUpdatedEntries; i++) { - bitbuf.WriteOneBit(1); - bitbuf.WriteLong(data->deltaFromTick); + last_index += 1 + bitbuf.ReadUBitVar(); + + int pvs = bitbuf.ReadUBitLong(2); + printf("%d - %d\n", last_index, pvs); + switch(pvs) + { + case 0: // delta + { + + } break; + case 2: // enter PVS + { + int iClass = bitbuf.ReadUBitLong(MAX_SERVER_CLASS_BITS); + int serial = bitbuf.ReadUBitLong(NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS); + printf("\t%d - %d\n", iClass, serial); + } break; + case 1: // leave PVS + case 3: // delete + { + + } break; + } + } - else - { - bitbuf.WriteOneBit(0); - } - bitbuf.WriteUBitLong(data->baselineIndex, 1); - bitbuf.WriteUBitLong(data->numUpdatedEntries, MAX_EDICT_BITS); - bitbuf.WriteUBitLong(data->dataLengthInBits, DELTASIZE_BITS); - bitbuf.WriteOneBit(data->updateBaseline); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); +*/ return !bitbuf.IsOverflowed(); } - - bool SVC_PacketEntities_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_PacketEntities* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->maxEntries = reader.ReadInt32("maxEntries"); - data->isDelta = reader.ReadBool("isDelta"); - data->deltaFromTick = reader.ReadInt32("deltaFromTick"); - data->baselineIndex = reader.ReadUInt32("baselineIndex"); - data->numUpdatedEntries = reader.ReadUInt32("numUpdatedEntries"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->updateBaseline = reader.ReadBool("updateBaseline"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_PacketEntities_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_PacketEntities* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("maxEntries", data->maxEntries); - jsonbuf.WriteBool("isDelta", data->isDelta); - jsonbuf.WriteInt32("deltaFromTick", data->deltaFromTick); - jsonbuf.WriteUInt32("baselineIndex", data->baselineIndex); - jsonbuf.WriteUInt32("numUpdatedEntries", data->numUpdatedEntries); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBool("updateBaseline", data->updateBaseline); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_PacketEntities_ToString_Internal(std::ostringstream& out, NetMsg::SVC_PacketEntities* data) - { - out << "svc_PacketEntities: delta " << data->deltaFromTick - << ", max " << data->maxEntries - << ", changed " << data->numUpdatedEntries - << "," << (data->updateBaseline ? " BL update," : "") - << " bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_prefetch.cpp b/demboyz/netmessages/svc_prefetch.cpp index 995303f..aa48d7c 100644 --- a/demboyz/netmessages/svc_prefetch.cpp +++ b/demboyz/netmessages/svc_prefetch.cpp @@ -1,7 +1,6 @@ #include "svc_prefetch.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "game/sourcecontext.h" #include "netcontants.h" @@ -20,42 +19,4 @@ namespace NetHandlers } return !bitbuf.IsOverflowed(); } - - bool SVC_Prefetch_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_Prefetch* data) - { - if (context.protocol > 23) - { - bitbuf.WriteUBitLong(data->soundIndex, MAX_SOUND_INDEX_BITS); - } - else - { - bitbuf.WriteUBitLong(data->soundIndex, MAX_SOUND_INDEX_BITS_OLD); - } - return !bitbuf.IsOverflowed(); - } - - bool SVC_Prefetch_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_Prefetch* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->type = reader.ReadUInt32("type"); - data->soundIndex = reader.ReadUInt32("soundIndex"); - return !reader.HasReadError(); - } - - bool SVC_Prefetch_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_Prefetch* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject();; - jsonbuf.WriteUInt32("type", data->type); - jsonbuf.WriteUInt32("soundIndex", data->soundIndex); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_Prefetch_ToString_Internal(std::ostringstream& out, NetMsg::SVC_Prefetch* data) - { - out << "svc_Prefetch: type " << data->type - << " index " << data->soundIndex; - } } diff --git a/demboyz/netmessages/svc_print.cpp b/demboyz/netmessages/svc_print.cpp index fadb0de..040c7b5 100644 --- a/demboyz/netmessages/svc_print.cpp +++ b/demboyz/netmessages/svc_print.cpp @@ -1,7 +1,6 @@ #include "svc_print.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -10,32 +9,4 @@ namespace NetHandlers bitbuf.ReadString(data->text, sizeof(data->text)); return !bitbuf.IsOverflowed(); } - - bool SVC_Print_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_Print* data) - { - bitbuf.WriteString(data->text); - return !bitbuf.IsOverflowed(); - } - - bool SVC_Print_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_Print* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - reader.ReadString("text", data->text, sizeof(data->text)); - return !reader.HasReadError(); - } - - bool SVC_Print_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_Print* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteString("text", data->text); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_Print_ToString_Internal(std::ostringstream& out, NetMsg::SVC_Print* data) - { - out << "svc_Print: \"" << data->text << '"'; - } } diff --git a/demboyz/netmessages/svc_sendtable.cpp b/demboyz/netmessages/svc_sendtable.cpp index e431cc9..f67a34a 100644 --- a/demboyz/netmessages/svc_sendtable.cpp +++ b/demboyz/netmessages/svc_sendtable.cpp @@ -1,7 +1,6 @@ #include "svc_sendtable.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netmath.h" namespace NetHandlers @@ -14,40 +13,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_SendTable_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_SendTable* data) - { - bitbuf.WriteOneBit(data->needsDecoder); - bitbuf.WriteShort(data->dataLengthInBits); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_SendTable_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_SendTable* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->needsDecoder = reader.ReadBool("needsDecoder"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_SendTable_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_SendTable* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("needsDecoder", data->needsDecoder); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_SendTable_ToString_Internal(std::ostringstream& out, NetMsg::SVC_SendTable* data) - { - out << "svc_SendTable: needs Decoder " << (data->needsDecoder ? "yes" : "no") - << ",bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_serverinfo.cpp b/demboyz/netmessages/svc_serverinfo.cpp index 4fe81b1..a06933b 100644 --- a/demboyz/netmessages/svc_serverinfo.cpp +++ b/demboyz/netmessages/svc_serverinfo.cpp @@ -1,7 +1,6 @@ #include "svc_serverinfo.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "game/sourcecontext.h" namespace NetHandlers @@ -20,7 +19,7 @@ namespace NetHandlers } else { - bitbuf.ReadBytes(data->unk1, sizeof(data->unk1)); + bitbuf.ReadBytes(data->mapMD5, sizeof(data->mapMD5)); } data->playerSlot = bitbuf.ReadByte(); data->maxClients = bitbuf.ReadByte(); @@ -32,113 +31,8 @@ namespace NetHandlers bitbuf.ReadString(data->hostName, sizeof(data->hostName)); if (context.protocol > 15) { - data->unk2 = bitbuf.ReadOneBit() != 0; + data->isReplay = bitbuf.ReadOneBit() != 0; } return !bitbuf.IsOverflowed(); } - - bool SVC_ServerInfo_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_ServerInfo* data) - { - bitbuf.WriteShort(data->protocol); - bitbuf.WriteLong(data->serverCount); - bitbuf.WriteOneBit(data->isHLTV); - bitbuf.WriteOneBit(data->isDedicated); - bitbuf.WriteLong(data->clientCRC); - bitbuf.WriteWord(data->maxClasses); - if (context.protocol <= 17) - { - bitbuf.WriteLong(data->mapCRC); - } - else - { - bitbuf.WriteBytes(data->unk1, sizeof(data->unk1)); - } - bitbuf.WriteByte(data->playerSlot); - bitbuf.WriteByte(data->maxClients); - bitbuf.WriteFloat(data->tickInterval); - bitbuf.WriteChar(data->os); - bitbuf.WriteString(data->gameDir); - bitbuf.WriteString(data->mapName); - bitbuf.WriteString(data->skyName); - bitbuf.WriteString(data->hostName); - if (context.protocol > 15) - { - bitbuf.WriteOneBit(data->unk2); - } - return !bitbuf.IsOverflowed(); - } - - bool SVC_ServerInfo_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_ServerInfo* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->protocol = reader.ReadInt32("protocol"); - data->serverCount = reader.ReadUInt32("serverCount"); - data->isHLTV = reader.ReadBool("isHltv"); - data->isDedicated = reader.ReadBool("isDedicated"); - data->clientCRC = reader.ReadUInt32("clientCrc"); - data->maxClasses = reader.ReadUInt32("maxClasses"); - if (context.protocol <= 17) - { - data->mapCRC = reader.ReadUInt32("mapCRC"); - } - else - { - reader.ReadBytes("unk1", data->unk1, sizeof(data->unk1)); - } - data->playerSlot = reader.ReadUInt32("playerSlot"); - data->maxClients = reader.ReadUInt32("maxClients"); - data->tickInterval = reader.ReadFloat("tickInterval"); - data->os = reader.ReadChar("os"); - reader.ReadString("gameDir", data->gameDir, sizeof(data->gameDir)); - reader.ReadString("mapName", data->mapName, sizeof(data->mapName)); - reader.ReadString("skyName", data->skyName, sizeof(data->skyName)); - reader.ReadString("hostName", data->hostName, sizeof(data->hostName)); - if (context.protocol > 15) - { - data->unk2 = reader.ReadBool("unk2"); - } - return !reader.HasReadError(); - } - - bool SVC_ServerInfo_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_ServerInfo* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteInt32("protocol", data->protocol); - jsonbuf.WriteUInt32("serverCount", data->serverCount); - jsonbuf.WriteBool("isHltv", data->isHLTV); - jsonbuf.WriteBool("isDedicated", data->isDedicated); - jsonbuf.WriteUInt32("clientCrc", data->clientCRC); - jsonbuf.WriteUInt32("maxClasses", data->maxClasses); - if (context.protocol <= 17) - { - jsonbuf.WriteUInt32("mapCRC", data->mapCRC); - } - else - { - jsonbuf.WriteBytes("unk1", data->unk1, sizeof(data->unk1)); - } - jsonbuf.WriteUInt32("playerSlot", data->playerSlot); - jsonbuf.WriteUInt32("maxClients", data->maxClients); - jsonbuf.WriteFloat("tickInterval", data->tickInterval); - jsonbuf.WriteChar("os", data->os); - jsonbuf.WriteString("gameDir", data->gameDir); - jsonbuf.WriteString("mapName", data->mapName); - jsonbuf.WriteString("skyName", data->skyName); - jsonbuf.WriteString("hostName", data->hostName); - if (context.protocol > 15) - { - jsonbuf.WriteBool("unk2", data->unk2); - } - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_ServerInfo_ToString_Internal(std::ostringstream& out, NetMsg::SVC_ServerInfo* data) - { - out << "svc_ServerInfo: game \"" << data->gameDir - << "\", map \"" << data->mapName - << "\", max " << static_cast(data->maxClients); - } } diff --git a/demboyz/netmessages/svc_serverinfo.h b/demboyz/netmessages/svc_serverinfo.h index 632933d..c1c7c62 100644 --- a/demboyz/netmessages/svc_serverinfo.h +++ b/demboyz/netmessages/svc_serverinfo.h @@ -14,7 +14,7 @@ namespace NetMsg uint32_t clientCRC; // client.dll CRC server is using uint16_t maxClasses; // max number of server classes uint32_t mapCRC; // server map CRC - uint8_t unk1[16]; + uint8_t mapMD5[16]; uint8_t playerSlot; // our client slot number uint8_t maxClients; // max number of clients on server float tickInterval; // server tick interval @@ -23,7 +23,7 @@ namespace NetMsg char mapName[MAX_OSPATH]; // name of current map char skyName[MAX_OSPATH]; // name of current skybox char hostName[MAX_OSPATH]; // host name - bool unk2; + bool isReplay; }; } diff --git a/demboyz/netmessages/svc_setpause.cpp b/demboyz/netmessages/svc_setpause.cpp index b3f1d74..450a2fd 100644 --- a/demboyz/netmessages/svc_setpause.cpp +++ b/demboyz/netmessages/svc_setpause.cpp @@ -1,7 +1,6 @@ #include "svc_setpause.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -10,32 +9,4 @@ namespace NetHandlers data->isPaused = bitbuf.ReadOneBit() != 0; return !bitbuf.IsOverflowed(); } - - bool SVC_SetPause_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_SetPause* data) - { - bitbuf.WriteOneBit(data->isPaused); - return !bitbuf.IsOverflowed(); - } - - bool SVC_SetPause_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_SetPause* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->isPaused = reader.ReadBool("isPaused"); - return !reader.HasReadError(); - } - - bool SVC_SetPause_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_SetPause* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("isPaused", data->isPaused); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_SetPause_ToString_Internal(std::ostringstream& out, NetMsg::SVC_SetPause* data) - { - out << "svc_SetPause: " << (data->isPaused ? "paused" : "unpaused"); - } } diff --git a/demboyz/netmessages/svc_setpausetimed.cpp b/demboyz/netmessages/svc_setpausetimed.cpp index 5da2e68..2fa5846 100644 --- a/demboyz/netmessages/svc_setpausetimed.cpp +++ b/demboyz/netmessages/svc_setpausetimed.cpp @@ -1,7 +1,6 @@ #include "svc_setpausetimed.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -11,35 +10,4 @@ namespace NetHandlers data->time = bitbuf.ReadFloat(); return !bitbuf.IsOverflowed(); } - - bool SVC_SetPauseTimed_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_SetPauseTimed* data) - { - bitbuf.WriteOneBit(data->isPaused); - bitbuf.WriteFloat(data->time); - return !bitbuf.IsOverflowed(); - } - - bool SVC_SetPauseTimed_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_SetPauseTimed* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->isPaused = reader.ReadBool("isPaused"); - data->time = reader.ReadFloat("time"); - return !reader.HasReadError(); - } - - bool SVC_SetPauseTimed_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_SetPauseTimed* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("isPaused", data->isPaused); - jsonbuf.WriteFloat("time", data->time); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_SetPauseTimed_ToString_Internal(std::ostringstream& out, NetMsg::SVC_SetPauseTimed* data) - { - out << "svc_SetPauseTimed: " << (data->isPaused ? "paused" : "unpaused"); - } } diff --git a/demboyz/netmessages/svc_setview.cpp b/demboyz/netmessages/svc_setview.cpp index 7b1de45..531ce1f 100644 --- a/demboyz/netmessages/svc_setview.cpp +++ b/demboyz/netmessages/svc_setview.cpp @@ -1,7 +1,6 @@ #include "svc_setview.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netcontants.h" namespace NetHandlers @@ -11,32 +10,4 @@ namespace NetHandlers data->entIndex = bitbuf.ReadUBitLong(MAX_EDICT_BITS); return !bitbuf.IsOverflowed(); } - - bool SVC_SetView_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_SetView* data) - { - bitbuf.WriteUBitLong(data->entIndex, MAX_EDICT_BITS); - return !bitbuf.IsOverflowed(); - } - - bool SVC_SetView_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_SetView* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->entIndex = reader.ReadUInt32("entIndex"); - return !reader.HasReadError(); - } - - bool SVC_SetView_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_SetView* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("entIndex", data->entIndex); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_SetView_ToString_Internal(std::ostringstream& out, NetMsg::SVC_SetView* data) - { - out << "svc_SetView: view entity " << data->entIndex; - } } diff --git a/demboyz/netmessages/svc_sounds.cpp b/demboyz/netmessages/svc_sounds.cpp index 669c114..8a87f26 100644 --- a/demboyz/netmessages/svc_sounds.cpp +++ b/demboyz/netmessages/svc_sounds.cpp @@ -1,7 +1,6 @@ #include "svc_sounds.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netmath.h" namespace NetHandlers @@ -23,52 +22,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_Sounds_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_Sounds* data) - { - if (data->reliableSound) - { - bitbuf.WriteOneBit(1); - bitbuf.WriteUBitLong(data->dataLengthInBits, 8); - } - else - { - bitbuf.WriteOneBit(0); - bitbuf.WriteUBitLong(data->numSounds, 8); - bitbuf.WriteUBitLong(data->dataLengthInBits, 16); - } - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_Sounds_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_Sounds* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->reliableSound = reader.ReadBool("reliableSound"); - data->numSounds = reader.ReadUInt32("numSounds"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_Sounds_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_Sounds* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteBool("reliableSound", data->reliableSound); - jsonbuf.WriteUInt32("numSounds", data->numSounds); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_Sounds_ToString_Internal(std::ostringstream& out, NetMsg::SVC_Sounds* data) - { - out << "svc_Sounds: number " << static_cast(data->numSounds) - << (data->reliableSound ? ", reliable" : "") - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_tempentities.cpp b/demboyz/netmessages/svc_tempentities.cpp index cef52a7..6e26062 100644 --- a/demboyz/netmessages/svc_tempentities.cpp +++ b/demboyz/netmessages/svc_tempentities.cpp @@ -1,7 +1,6 @@ #include "svc_tempentities.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "game/sourcecontext.h" #include "netcontants.h" #include "netmath.h" @@ -23,47 +22,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_TempEntities_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_TempEntities* data) - { - bitbuf.WriteUBitLong(data->numEntries, EVENT_INDEX_BITS); - if (context.protocol > 23) - { - bitbuf.WriteVarInt32(data->dataLengthInBits); - } - else - { - bitbuf.WriteUBitLong(data->dataLengthInBits, NET_MAX_PAYLOAD_BITS_OLD); - } - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_TempEntities_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_TempEntities* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->numEntries = reader.ReadUInt32("numEntries"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_TempEntities_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_TempEntities* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("numEntries", data->numEntries); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_TempEntities_ToString_Internal(std::ostringstream& out, NetMsg::SVC_TempEntities* data) - { - out << "svc_TempEntities: number " << data->numEntries - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_terrainmod.cpp b/demboyz/netmessages/svc_terrainmod.cpp index 21fcc38..88d1895 100644 --- a/demboyz/netmessages/svc_terrainmod.cpp +++ b/demboyz/netmessages/svc_terrainmod.cpp @@ -9,27 +9,4 @@ namespace NetHandlers assert(false); return true; } - - bool SVC_TerrainMod_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_TerrainMod* data) - { - assert(false); - return true; - } - - bool SVC_TerrainMod_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_TerrainMod* data) - { - assert(false); - return true; - } - - bool SVC_TerrainMod_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_TerrainMod* data) - { - assert(false); - return true; - } - - void SVC_TerrainMod_ToString_Internal(std::ostringstream& out, NetMsg::SVC_TerrainMod* data) - { - out << "svc_TerrainMod"; - } } diff --git a/demboyz/netmessages/svc_updatestringtable.cpp b/demboyz/netmessages/svc_updatestringtable.cpp index 144e2fe..7ffa0be 100644 --- a/demboyz/netmessages/svc_updatestringtable.cpp +++ b/demboyz/netmessages/svc_updatestringtable.cpp @@ -1,7 +1,8 @@ #include "svc_updatestringtable.h" #include "base/bitfile.h" -#include "base/jsonfile.h" +#include "game/sourcecontext.h" +#include "game/stringtables.h" #include "netmath.h" #include "netcontants.h" @@ -14,54 +15,11 @@ namespace NetHandlers data->dataLengthInBits = bitbuf.ReadUBitLong(20); data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); + + StringTable *table = &context.stringTables->tables[data->tableID]; + bf_read bitbuf2(data->data.get(), math::BitsToBytes(data->dataLengthInBits), data->dataLengthInBits); + table->ParseUpdate(bitbuf2, data->numChangedEntries, context); + return !bitbuf.IsOverflowed(); } - - bool SVC_UpdateStringTable_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_UpdateStringTable* data) - { - bitbuf.WriteUBitLong(data->tableID, math::log2(MAX_TABLES)); - if (data->numChangedEntries != 1) - { - bitbuf.WriteOneBit(1); - bitbuf.WriteWord(data->numChangedEntries); - } - else - { - bitbuf.WriteOneBit(0); - } - bitbuf.WriteUBitLong(data->dataLengthInBits, 20); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_UpdateStringTable_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_UpdateStringTable* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->tableID = reader.ReadUInt32("tableId"); - data->numChangedEntries = reader.ReadUInt32("numChangedEntries"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_UpdateStringTable_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_UpdateStringTable* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("tableId", data->tableID); - jsonbuf.WriteUInt32("numChangedEntries", data->numChangedEntries); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_UpdateStringTable_ToString_Internal(std::ostringstream& out, NetMsg::SVC_UpdateStringTable* data) - { - out << "svc_UpdateStringTable: table " << data->tableID - << ", changed " << data->numChangedEntries - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_usermessage.cpp b/demboyz/netmessages/svc_usermessage.cpp index 5f5e276..4f4f118 100644 --- a/demboyz/netmessages/svc_usermessage.cpp +++ b/demboyz/netmessages/svc_usermessage.cpp @@ -1,7 +1,6 @@ #include "svc_usermessage.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netmath.h" #include "netcontants.h" #include @@ -17,40 +16,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_UserMessage_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_UserMessage* data) - { - bitbuf.WriteByte(data->msgType); - bitbuf.WriteUBitLong(data->dataLengthInBits, 11); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_UserMessage_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_UserMessage* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->msgType = reader.ReadUInt32("msgType"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_UserMessage_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_UserMessage* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("msgType", data->msgType); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_UserMessage_ToString_Internal(std::ostringstream& out, NetMsg::SVC_UserMessage* data) - { - out << "svc_UserMessage: type " << static_cast(data->msgType) - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_voicedata.cpp b/demboyz/netmessages/svc_voicedata.cpp index b9114e4..ecd80b6 100644 --- a/demboyz/netmessages/svc_voicedata.cpp +++ b/demboyz/netmessages/svc_voicedata.cpp @@ -1,7 +1,7 @@ #include "svc_voicedata.h" +#include "svc_voiceinit.h" #include "base/bitfile.h" -#include "base/jsonfile.h" #include "netmath.h" namespace NetHandlers @@ -15,43 +15,4 @@ namespace NetHandlers bitbuf.ReadBits(data->data.get(), data->dataLengthInBits); return !bitbuf.IsOverflowed(); } - - bool SVC_VoiceData_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_VoiceData* data) - { - bitbuf.WriteByte(data->fromClientIndex); - bitbuf.WriteByte(data->proximity); - bitbuf.WriteWord(data->dataLengthInBits); - bitbuf.WriteBits(data->data.get(), data->dataLengthInBits); - return !bitbuf.IsOverflowed(); - } - - bool SVC_VoiceData_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_VoiceData* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - data->fromClientIndex = reader.ReadUInt32("fromClientIndex"); - data->proximity = reader.ReadBool("proximity"); - data->dataLengthInBits = reader.ReadUInt32("dataLengthInBits"); - data->data.reset(new uint8_t[math::BitsToBytes(data->dataLengthInBits)]); - reader.ReadBits("data", data->data.get(), data->dataLengthInBits); - return !reader.HasReadError(); - } - - bool SVC_VoiceData_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_VoiceData* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteUInt32("fromClientIndex", data->fromClientIndex); - jsonbuf.WriteBool("proximity", data->proximity); - jsonbuf.WriteUInt32("dataLengthInBits", data->dataLengthInBits); - jsonbuf.WriteBits("data", data->data.get(), data->dataLengthInBits); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_VoiceData_ToString_Internal(std::ostringstream& out, NetMsg::SVC_VoiceData* data) - { - out << "svc_VoiceData: client " << static_cast(data->fromClientIndex) - << ", bytes " << math::BitsToBytes(data->dataLengthInBits); - } } diff --git a/demboyz/netmessages/svc_voiceinit.cpp b/demboyz/netmessages/svc_voiceinit.cpp index 95fd0b9..b85e97b 100644 --- a/demboyz/netmessages/svc_voiceinit.cpp +++ b/demboyz/netmessages/svc_voiceinit.cpp @@ -1,7 +1,6 @@ #include "svc_voiceinit.h" #include "base/bitfile.h" -#include "base/jsonfile.h" namespace NetHandlers { @@ -20,49 +19,4 @@ namespace NetHandlers } return !bitbuf.IsOverflowed(); } - - bool SVC_VoiceInit_BitWrite_Internal(BitWrite& bitbuf, const SourceGameContext& context, NetMsg::SVC_VoiceInit* data) - { - bitbuf.WriteString(data->voiceCodec); - bitbuf.WriteByte(data->quality); - if(data->quality == NetMsg::SVC_VoiceInit::QUALITY_HAS_SAMPLE_RATE) - { - bitbuf.WriteShort(data->sampleRate); - } - return !bitbuf.IsOverflowed(); - } - - bool SVC_VoiceInit_JsonRead_Internal(JsonRead& jsonbuf, SourceGameContext& context, NetMsg::SVC_VoiceInit* data) - { - base::JsonReaderObject reader = jsonbuf.ParseObject(); - assert(!reader.HasReadError()); - reader.ReadString("voiceCodec", data->voiceCodec, sizeof(data->voiceCodec)); - data->quality = reader.ReadUInt32("quality"); - data->sampleRate = reader.ReadInt32("sampleRate"); - return !reader.HasReadError(); - } - - bool SVC_VoiceInit_JsonWrite_Internal(JsonWrite& jsonbuf, const SourceGameContext& context, NetMsg::SVC_VoiceInit* data) - { - jsonbuf.Reset(); - jsonbuf.StartObject(); - jsonbuf.WriteString("voiceCodec", data->voiceCodec); - jsonbuf.WriteUInt32("quality", data->quality); - jsonbuf.WriteInt32("sampleRate", data->sampleRate); - jsonbuf.EndObject(); - return jsonbuf.IsComplete(); - } - - void SVC_VoiceInit_ToString_Internal(std::ostringstream& out, NetMsg::SVC_VoiceInit* data) - { - out << "svc_VoiceInit: codec \"" << data->voiceCodec; - if(data->quality == NetMsg::SVC_VoiceInit::QUALITY_HAS_SAMPLE_RATE) - { - out << "\", sample rate " << static_cast(data->sampleRate); - } - else - { - out << "\", qualitty " << static_cast(data->quality); - } - } } diff --git a/demboyz/netmessages/usermessages.h b/demboyz/netmessages/usermessages.h new file mode 100644 index 0000000..73c3dae --- /dev/null +++ b/demboyz/netmessages/usermessages.h @@ -0,0 +1,56 @@ + +#pragma once + +namespace UserMsg +{ + enum + { + Geiger = 0, + Train = 1, + HudText = 2, + SayText = 3, + SayText2 = 4, + TextMsg = 5, + HudMsg = 6, + ResetHUD = 7, + GameTitle = 8, + ItemPickup = 9, + ShowMenu = 10, + Shake = 11, + Fade = 12, + VGUIMenu = 13, + Rumble = 14, + CloseCaption = 15, + SendAudio = 16, + RawAudio = 17, + VoiceMask = 18, + RequestState = 19, + BarTime = 20, + Damage = 21, + RadioText = 22, + HintText = 23, + KeyHintText = 24, + ReloadEffect = 25, + PlayerAnimEvent = 26, + AmmoDenied = 27, + UpdateRadar = 28, + KillCam = 29, + MarkAchievement = 30, + CallVoteFailed = 31, + VoteStart = 32, + VotePass = 33, + VoteFailed = 34, + VoteSetup = 35, + SPHapWeapEvent = 36, + HapDmg = 37, + HapPunch = 38, + HapSetDrag = 39, + HapSetConst = 40, + HapMeleeContact = 41, + PlayerStatsUpdate_DEPRECATED = 42, + AchievementEvent = 43, + MatchEndConditions = 44, + MatchStatsUpdate = 45, + PlayerStatsUpdate = 46 + }; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/Makefile b/external/SILK_SDK_SRC_FLP_v1.0.9/Makefile new file mode 100755 index 0000000..ccdd3f7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/Makefile @@ -0,0 +1,98 @@ +# +# Makefile for Silk SDK +# +# Copyright (c) 2012, Skype Limited +# All rights reserved. +# + +#Platform detection and settings + +BUILD_OS := $(shell uname | sed -e 's/^.*Darwin.*/MacOS-X/ ; s/^.*CYGWIN.*/Windows/') +BUILD_ARCHITECTURE := $(shell uname -m | sed -e 's/i686/i386/') + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)gcc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cflags-from-defines = $(addprefix -D,$(1)) +cflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +CFLAGS += -Wall -enable-threads -O3 + +CFLAGS += $(call cflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cflags-from-defines,$(ADDED_DEFINES)) +CFLAGS += $(call cflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -lm -o $@$(EXESUFFIX) +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +# Directives + +CINCLUDES += interface src test + +# VPATH e.g. VPATH = src:../headers +VPATH = ./ \ + interface \ + src \ + test + +# Variable definitions +LIB_NAME = SKP_SILK_SDK +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(wildcard src/*.c) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +ENCODER_SRCS_C = test/Encoder.c +ENCODER_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(ENCODER_SRCS_C)) + +DECODER_SRCS_C = test/Decoder.c +DECODER_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(DECODER_SRCS_C)) + +SIGNALCMP_SRCS_C = test/signalCompare.c +SIGNALCMP_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SIGNALCMP_SRCS_C)) + +LIBS = \ + $(LIB_NAME) + +LDLIBDIRS = ./ + +# Rules +default: all + +all: $(TARGET) encoder decoder signalcompare + +lib: $(TARGET) + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +encoder$(EXESUFFIX): $(ENCODER_OBJS) + $(LINK.o.cmdline) + +decoder$(EXESUFFIX): $(DECODER_OBJS) + $(LINK.o.cmdline) + +signalcompare$(EXESUFFIX): $(SIGNALCMP_OBJS) + $(LINK.o.cmdline) + +clean: + $(RM) $(TARGET)* $(OBJS) $(ENCODER_OBJS) $(DECODER_OBJS) \ + $(SIGNALCMP_OBJS) $(TEST_OBJS) \ + encoder$(EXESUFFIX) decoder$(EXESUFFIX) signalcompare$(EXESUFFIX) + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK.sln b/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK.sln new file mode 100755 index 0000000..fd887d7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dec_SDK", "test\Dec_SDK.vcxproj", "{82685D7F-0589-42BD-877C-31A952D53A8E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Enc_SDK", "test\Enc_SDK.vcxproj", "{6D97A8EF-5724-4D85-8BF4-C583714BBA78}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silk_FLP", "src\Silk_FLP.vcxproj", "{56B91D01-9150-4BBF-AFA1-5B68AB991B76}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SignalCompare", "test\SignalCompare.vcxproj", "{7FE8F544-9175-40C3-A187-7F15CE9A75D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|Win32.ActiveCfg = Debug|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|Win32.Build.0 = Debug|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|x64.ActiveCfg = Debug|x64 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|x64.Build.0 = Debug|x64 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|Win32.ActiveCfg = Release|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|Win32.Build.0 = Release|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|x64.ActiveCfg = Release|x64 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|x64.Build.0 = Release|x64 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|Win32.Build.0 = Debug|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|x64.ActiveCfg = Debug|x64 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|x64.Build.0 = Debug|x64 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|Win32.ActiveCfg = Release|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|Win32.Build.0 = Release|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|x64.ActiveCfg = Release|x64 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|x64.Build.0 = Release|x64 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.ActiveCfg = Debug|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.Build.0 = Debug|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.ActiveCfg = Debug|x64 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.Build.0 = Debug|x64 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.ActiveCfg = Release|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.Build.0 = Release|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.ActiveCfg = Release|x64 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.Build.0 = Release|x64 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|Win32.Build.0 = Debug|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|x64.ActiveCfg = Debug|x64 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|x64.Build.0 = Debug|x64 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|Win32.ActiveCfg = Release|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|Win32.Build.0 = Release|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|x64.ActiveCfg = Release|x64 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK_VS2005.sln b/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK_VS2005.sln new file mode 100755 index 0000000..b982e0e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/Silk_SDK_VS2005.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dec_SDK", "test\Dec_SDK.vcproj", "{82685D7F-0589-42BD-877C-31A952D53A8E}" + ProjectSection(ProjectDependencies) = postProject + {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {56B91D01-9150-4BBF-AFA1-5B68AB991B76} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Enc_SDK", "test\Enc_SDK.vcproj", "{6D97A8EF-5724-4D85-8BF4-C583714BBA78}" + ProjectSection(ProjectDependencies) = postProject + {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {56B91D01-9150-4BBF-AFA1-5B68AB991B76} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silk_FLP", "src\Silk_FLP.vcproj", "{56B91D01-9150-4BBF-AFA1-5B68AB991B76}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SignalCompare", "test\SignalCompare.vcproj", "{7FE8F544-9175-40C3-A187-7F15CE9A75D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|Win32.ActiveCfg = Debug|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Debug|Win32.Build.0 = Debug|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|Win32.ActiveCfg = Release|Win32 + {82685D7F-0589-42BD-877C-31A952D53A8E}.Release|Win32.Build.0 = Release|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Debug|Win32.Build.0 = Debug|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|Win32.ActiveCfg = Release|Win32 + {6D97A8EF-5724-4D85-8BF4-C583714BBA78}.Release|Win32.Build.0 = Release|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.ActiveCfg = Debug|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.Build.0 = Debug|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.ActiveCfg = Release|Win32 + {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.Build.0 = Release|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Debug|Win32.Build.0 = Debug|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|Win32.ActiveCfg = Release|Win32 + {7FE8F544-9175-40C3-A187-7F15CE9A75D8}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/doc/SILK_Evaluation.pdf b/external/SILK_SDK_SRC_FLP_v1.0.9/doc/SILK_Evaluation.pdf new file mode 100755 index 0000000000000000000000000000000000000000..07a9233c192d6a9322ed8ffdb8119ede14629cf3 GIT binary patch literal 80724 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

{c57dPRx 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¬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

$*#ZNJwFkvz?Vy4LgNXe-?6) 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%0AnNo|;1=y#-A(*j^IFRW>qg&3 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

Eba2tC@2*-c#~vINI#QN??y|qYmQ_ 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�rIBmV%K23=UrK#0ymSRkoG@XB(pBMHp2_7-Nnw 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 T_U8t&A5XwRmM^z +#if defined( __GNUC__ ) +#include +#endif + +#define SKP_int int /* used for counters etc; at least 16 bits */ +#ifdef __GNUC__ +# define SKP_int64 int64_t +#else +# define SKP_int64 long long +#endif +#define SKP_int32 int +#define SKP_int16 short +#define SKP_int8 signed char + +#define SKP_uint unsigned int /* used for counters etc; at least 16 bits */ +#ifdef __GNUC__ +# define SKP_uint64 uint64_t +#else +# define SKP_uint64 unsigned long long +#endif +#define SKP_uint32 unsigned int +#define SKP_uint16 unsigned short +#define SKP_uint8 unsigned char + +#define SKP_int_ptr_size intptr_t + +#if SKP_USE_DOUBLE_PRECISION_FLOATS +# define SKP_float double +# define SKP_float_MAX DBL_MAX +#else +# define SKP_float float +# define SKP_float_MAX FLT_MAX +#endif + +#define SKP_INLINE static __inline + +#ifdef _WIN32 +# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y) +#else +# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y) +#endif + +#define SKP_int64_MAX ((SKP_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define SKP_int64_MIN ((SKP_int64)0x8000000000000000LL) /* -2^63 */ +#define SKP_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647*/ +#define SKP_int32_MIN ((SKP_int32)0x80000000) /* -2^31 = -2147483648*/ +#define SKP_int16_MAX 0x7FFF /* 2^15 - 1 = 32767*/ +#define SKP_int16_MIN ((SKP_int16)0x8000) /* -2^15 = -32768*/ +#define SKP_int8_MAX 0x7F /* 2^7 - 1 = 127*/ +#define SKP_int8_MIN ((SKP_int8)0x80) /* -2^7 = -128*/ + +#define SKP_uint32_MAX 0xFFFFFFFF /* 2^32 - 1 = 4294967295 */ +#define SKP_uint32_MIN 0x00000000 +#define SKP_uint16_MAX 0xFFFF /* 2^16 - 1 = 65535 */ +#define SKP_uint16_MIN 0x0000 +#define SKP_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ +#define SKP_uint8_MIN 0x00 + +#define SKP_TRUE 1 +#define SKP_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef SKP_assert +# include /* ASSERTE() */ +# define SKP_assert(COND) _ASSERTE(COND) +# endif +#else +# define SKP_assert(COND) +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/readme.txt b/external/SILK_SDK_SRC_FLP_v1.0.9/readme.txt new file mode 100755 index 0000000..28b26cb --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/readme.txt @@ -0,0 +1,94 @@ +************************************************************************ +Floating Point SILK SDK 1.0.9 source code package +Copyright 2012 (c), Skype Limited +https://developer.skype.com/silk/ +************************************************************************ + +Date: 03/08/2012 (Format: DD/MM/YYYY) + +I. Description + +This package contains files for compilation and evaluation of the floating +point SILK SDK library. The following is included in this package: + + o Source code for the floating point SILK SDK library + o Source code for creating encoder and decoder executables + o Test vectors + o Comparison tool + o Microsoft Visual Studio solutions and project files + o Makefile for GNU C-compiler (GCC) + +II. Files and Folders + + o doc/ - contains more information about the SILK SDK + o interface/ - contains API header files + o src/ - contains all SILK SDK library source files + o test/ - contains source files for testing the SILK SDK + o test_vectors/ - contains test vectors + o Makefile - Makefile for compiling with GCC + o readme.txt - this file + o Silk_SDK.sln - Visual Studio 2010 solution for all SILK SDK code + o Silk_SDK_VS2005.sln - Visual Studio 2005 solution for all SILK SDK code + +III. How to use the Makefile + + 1. How to clean and compile the SILK SDK library: + + make clean lib + + 2. How to compile an encoder executable: + + make encoder + + 3. How to compile a decoder executable: + + make decoder + + 4. How to clean and compile all of the above: + + make clean all + + 5. How to build for big endian CPU's + + Make clean all ADDED_DEFINES+=_SYSTEM_IS_BIG_ENDIAN + To be able to use the test vectors with big endian CPU's the test programs + need to be compiled in a different way. Note that the 16 bit input and output + from the test programs will have the upper and lower bytes swapped with this setting. + + 6. How to use the comparison tool: + + See 'How to use the test vectors.txt' in the test_vectors folder. + +IV. History + + Version 1.0.9 - Added 64-bit support. Added iOS LLVM compiler support. Lowered DTX mode bitrate. Bugfixes for ARM builds. Various other small fixes. + Version 1.0.8 - Improved noise shaping, various other improvements, and various bugfixes. Added a MIPS version + Version 1.0.7 - Updated with bugfixes for LBRR and pitch estimator. SignalCompare updated + Version 1.0.6 - Updated with bugfixes for ARM builds + Version 1.0.5 - Updated with bugfixes for ARM builds + Version 1.0.4 - Updated with various bugfixes and improvements, including some API changes + Added support for big endian platforms + Added resampler support for additional API sample rates + Version 1.0.3 - Updated with various bugfixes and improvements + Version 1.0.2 - Updated with various bugfixes and improvements + Version 1.0.1 - First beta source code release + +V. Compatibility + + This package has been tested on the following platforms: + + Windows 7 Professional, 32-bit version, Intel Core i7 CPU + Windows 7 Professional, 64-bit version, Intel Core i7 CPU + Mac OS X Version 10.7.4, 64-bit version, Intel Core i7 CPU + Ubuntu Linux 10.04 LTS, 32-bit version, Intel Core i7 CPU + Ubuntu Linux 12.04 LTS, 64-bit version, Intel Core 2 Duo CPU + +VI. Known Issues + + None + +VII. Additional Resources + + For more information, visit the SILK SDK web site at: + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_A2NLSF.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_A2NLSF.c new file mode 100755 index 0000000..8307e02 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_A2NLSF.c @@ -0,0 +1,279 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* function are accurate inverses of each other */ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Number of binary divisions */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define QPoly 16 +#define MAX_ITERATIONS_A2NLSF_FIX 30 + +/* Flag for using 2x as many cosine sampling points, reduces the risk of missing a root */ +#define OVERSAMPLE_COSINE_TABLE 0 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +SKP_INLINE void SKP_Silk_A2NLSF_trans_poly( + SKP_int32 *p, /* I/O Polynomial */ + const SKP_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + SKP_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= SKP_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +SKP_INLINE SKP_int32 SKP_Silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in QPoly */ + SKP_int32 *p, /* I Polynomial, QPoly */ + const SKP_int32 x, /* I Evaluation point, Q12 */ + const SKP_int dd /* I Order */ +) +{ + SKP_int n; + SKP_int32 x_Q16, y32; + + y32 = p[ dd ]; /* QPoly */ + x_Q16 = SKP_LSHIFT( x, 4 ); + for( n = dd - 1; n >= 0; n-- ) { + y32 = SKP_SMLAWW( p[ n ], y32, x_Q16 ); /* QPoly */ + } + return y32; +} + +SKP_INLINE void SKP_Silk_A2NLSF_init( + const SKP_int32 *a_Q16, + SKP_int32 *P, + SKP_int32 *Q, + const SKP_int dd +) +{ + SKP_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = SKP_LSHIFT( 1, QPoly ); + Q[dd] = SKP_LSHIFT( 1, QPoly ); + for( k = 0; k < dd; k++ ) { +#if( QPoly < 16 ) + P[ k ] = SKP_RSHIFT_ROUND( -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ], 16 - QPoly ); /* QPoly */ + Q[ k ] = SKP_RSHIFT_ROUND( -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ], 16 - QPoly ); /* QPoly */ +#elif( QPoly == 16 ) + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; // QPoly + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; // QPoly +#else + P[ k ] = SKP_LSHIFT( -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ], QPoly - 16 ); /* QPoly */ + Q[ k ] = SKP_LSHIFT( -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ], QPoly - 16 ); /* QPoly */ +#endif + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + SKP_Silk_A2NLSF_trans_poly( P, dd ); + SKP_Silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void SKP_Silk_A2NLSF( + SKP_int *NLSF, /* O Normalized Line Spectral Frequencies, Q15 (0 - (2^15-1)), [d] */ + SKP_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const SKP_int d /* I Filter order (must be even) */ +) +{ + SKP_int i, k, m, dd, root_ix, ffrac; + SKP_int32 xlo, xhi, xmid; + SKP_int32 ylo, yhi, ymid; + SKP_int32 nom, den; + SKP_int32 P[ SKP_Silk_MAX_ORDER_LPC / 2 + 1 ]; + SKP_int32 Q[ SKP_Silk_MAX_ORDER_LPC / 2 + 1 ]; + SKP_int32 *PQ[ 2 ]; + SKP_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = SKP_RSHIFT( d, 1 ); + + SKP_Silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ 0 ]; // Q12 + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + while( 1 ) { + /* Evaluate polynomial */ +#if OVERSAMPLE_COSINE_TABLE + xhi = SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] + + ( ( SKP_Silk_LSFCosTab_FIX_Q12[ ( k + 1 ) >> 1 ] - + SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] ) >> 1 ); /* Q12 */ +#else + xhi = SKP_Silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ +#endif + yhi = SKP_Silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= 0 ) || ( ylo >= 0 && yhi <= 0 ) ) { + /* Binary division */ +#if OVERSAMPLE_COSINE_TABLE + ffrac = -128; +#else + ffrac = -256; +#endif + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = SKP_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = SKP_Silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; +#if OVERSAMPLE_COSINE_TABLE + ffrac = SKP_ADD_RSHIFT( ffrac, 64, m ); +#else + ffrac = SKP_ADD_RSHIFT( ffrac, 128, m ); +#endif + } + } + + /* Interpolate */ + if( SKP_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = SKP_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + SKP_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += SKP_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += SKP_DIV32( ylo, SKP_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } +#if OVERSAMPLE_COSINE_TABLE + NLSF[ root_ix ] = (SKP_int)SKP_min_32( SKP_LSHIFT( (SKP_int32)k, 7 ) + ffrac, SKP_int16_MAX ); +#else + NLSF[ root_ix ] = (SKP_int)SKP_min_32( SKP_LSHIFT( (SKP_int32)k, 8 ) + ffrac, SKP_int16_MAX ); +#endif + + SKP_assert( NLSF[ root_ix ] >= 0 ); + SKP_assert( NLSF[ root_ix ] <= 32767 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ +#if OVERSAMPLE_COSINE_TABLE + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ ( k - 1 ) >> 1 ] + + ( ( SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] - + SKP_Silk_LSFCosTab_FIX_Q12[ ( k - 1 ) >> 1 ] ) >> 1 ); // Q12 +#else + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ k - 1 ]; // Q12 +#endif + ylo = SKP_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + +#if OVERSAMPLE_COSINE_TABLE + if( k > 2 * LSF_COS_TAB_SZ_FIX ) { +#else + if( k > LSF_COS_TAB_SZ_FIX ) { +#endif + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = SKP_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = SKP_SMULBB( k + 1, NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + SKP_Silk_bwexpander_32( a_Q16, d, 65536 - SKP_SMULBB( 10 + i, i ) ); // 10_Q16 = 0.00015 + + SKP_Silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ 0 ]; // Q12 + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_CNG.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_CNG.c new file mode 100755 index 0000000..c7b7905 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_CNG.c @@ -0,0 +1,149 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Generates excitation for CNG LPC synthesis */ +SKP_INLINE void SKP_Silk_CNG_exc( + SKP_int16 residual[], /* O CNG residual signal Q0 */ + SKP_int32 exc_buf_Q10[], /* I Random samples buffer Q10 */ + SKP_int32 Gain_Q16, /* I Gain to apply */ + SKP_int length, /* I Length */ + SKP_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + SKP_int32 seed; + SKP_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = SKP_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = SKP_RAND( seed ); + idx = ( SKP_int )( SKP_RSHIFT( seed, 24 ) & exc_mask ); + SKP_assert( idx >= 0 ); + SKP_assert( idx <= CNG_BUF_MASK_MAX ); + residual[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ), 10 ) ); + } + *rand_seed = seed; +} + +void SKP_Silk_CNG_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + SKP_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = SKP_DIV32_16( SKP_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void SKP_Silk_CNG( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O Signal */ + SKP_int length /* I Length of residual */ +) +{ + SKP_int i, subfr; + SKP_int32 tmp_32, Gain_Q26, max_Gain_Q16; + SKP_int16 LPC_buf[ MAX_LPC_ORDER ]; + SKP_int16 CNG_sig[ MAX_FRAME_LENGTH ]; + SKP_Silk_CNG_struct *psCNG; + psCNG = &psDec->sCNG; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + SKP_Silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->vadFlag == NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += SKP_SMULWB( psDec->prevNLSF_Q15[ i ] - psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < NB_SUBFR; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + SKP_memmove( &psCNG->CNG_exc_buf_Q10[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q10, ( NB_SUBFR - 1 ) * psDec->subfr_length * sizeof( SKP_int32 ) ); + SKP_memcpy( psCNG->CNG_exc_buf_Q10, &psDec->exc_Q10[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( SKP_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < NB_SUBFR; i++ ) { + psCNG->CNG_smth_Gain_Q16 += SKP_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost and / or when low speech activity */ + if( psDec->lossCnt ) {//|| psDec->vadFlag == NO_VOICE_ACTIVITY ) { + + /* Generate CNG excitation */ + SKP_Silk_CNG_exc( CNG_sig, psCNG->CNG_exc_buf_Q10, + psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + SKP_Silk_NLSF2A_stable( LPC_buf, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); + + Gain_Q26 = ( SKP_int32 )1 << 26; /* 1.0 */ + + /* Generate CNG signal, by synthesis filtering */ + if( psDec->LPC_order == 16 ) { + SKP_Silk_LPC_synthesis_order16( CNG_sig, LPC_buf, + Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length ); + } else { + SKP_Silk_LPC_synthesis_filter( CNG_sig, LPC_buf, + Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length, psDec->LPC_order ); + } + /* Mix with signal */ + for( i = 0; i < length; i++ ) { + tmp_32 = signal[ i ] + CNG_sig[ i ]; + signal[ i ] = SKP_SAT16( tmp_32 ); + } + } else { + SKP_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( SKP_int32 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_HP_variable_cutoff_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_HP_variable_cutoff_FLP.c new file mode 100755 index 0000000..0e3f97f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_HP_variable_cutoff_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +#if HIGH_PASS_INPUT + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_int16 *out, /* O High-pass filtered output signal */ + const SKP_int16 *in /* I Input signal */ +) +{ + SKP_float pitch_freq_Hz, pitch_freq_log, quality, delta_freq, smth_coef, Fc, r; + SKP_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + + /*********************************************/ + /* Estimate low end of pitch frequency range */ + /*********************************************/ + if( psEnc->sCmn.prev_sigtype == SIG_TYPE_VOICED ) { + + /* Difference, in log domain */ + pitch_freq_Hz = 1e3f * psEnc->sCmn.fs_kHz / psEnc->sCmn.prevLag; + pitch_freq_log = SKP_Silk_log2( pitch_freq_Hz ); + + /* Adjustment based on quality */ + quality = psEncCtrl->input_quality_bands[ 0 ]; + pitch_freq_log -= quality * quality * ( pitch_freq_log - SKP_Silk_log2( VARIABLE_HP_MIN_FREQ ) ); + pitch_freq_log += 0.5f * ( 0.6f - quality ); + + delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; + if( delta_freq < 0.0 ) { + /* Less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq *= 3.0f; + } + + /* Limit delta, to reduce impact of outliers */ + delta_freq = SKP_LIMIT_float( delta_freq, -VARIABLE_HP_MAX_DELTA_FREQ, VARIABLE_HP_MAX_DELTA_FREQ ); + + /* Update smoother */ + smth_coef = VARIABLE_HP_SMTH_COEF1 * psEnc->speech_activity; + psEnc->variable_HP_smth1 += smth_coef * delta_freq; + } + + /* Second smoother */ + psEnc->variable_HP_smth2 += VARIABLE_HP_SMTH_COEF2 * ( psEnc->variable_HP_smth1 - psEnc->variable_HP_smth2 ); + + /* Convert from log scale to Hertz */ + psEncCtrl->pitch_freq_low_Hz = ( SKP_float )pow( 2.0f, psEnc->variable_HP_smth2 ); + + /* Limit frequency range */ + psEncCtrl->pitch_freq_low_Hz = SKP_LIMIT_float( psEncCtrl->pitch_freq_low_Hz, VARIABLE_HP_MIN_FREQ, VARIABLE_HP_MAX_FREQ ); + + /*******************************/ + /* Compute filter coefficients */ + /*******************************/ + /* Compute cut-off frequency, in radians */ + Fc = ( SKP_float )( 0.45f * 2.0f * 3.14159265359 * psEncCtrl->pitch_freq_low_Hz / ( 1e3f * psEnc->sCmn.fs_kHz ) ); + + /* 2nd order ARMA coefficients */ + r = 1.0f - 0.92f * Fc; + + /* b = r * [1; -2; 1]; */ + /* a = [1; -2 * r * (1 - 0.5 * Fc^2); r^2]; */ + B_Q28[ 0 ] = SKP_float2int( ( 1 << 28 ) * r ); + B_Q28[ 1 ] = SKP_float2int( ( 1 << 28 ) * -2.0f * r ); + B_Q28[ 2 ] = B_Q28[ 0 ]; + A_Q28[ 0 ] = SKP_float2int( ( 1 << 28 ) * -2.0f * r * ( 1.0f - 0.5f * Fc * Fc ) ); + A_Q28[ 1 ] = SKP_float2int( ( 1 << 28 ) * r * r ); + + /********************/ + /* High-pass filter */ + /********************/ + SKP_Silk_biquad_alt( in, B_Q28, A_Q28, psEnc->sCmn.In_HP_State, out, psEnc->sCmn.frame_length ); +} + +#endif // HIGH_PASS_INPUT diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_Inlines.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_Inlines.h new file mode 100755 index 0000000..3409f6f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_Inlines.h @@ -0,0 +1,278 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*! \file SKP_Silk_Inlines.h + * \brief SigProcFix_Inlines.h defines inline signal processing functions. + */ + +#ifndef _SKP_SILK_FIX_INLINES_H_ +#define _SKP_SILK_FIX_INLINES_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of SKP_int64 */ +SKP_INLINE SKP_int32 SKP_Silk_CLZ64(SKP_int64 in) +{ + SKP_int32 in_upper; + + in_upper = (SKP_int32)SKP_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + SKP_Silk_CLZ32( (SKP_int32) in ); + } else { + /* Search in the upper 32 bits */ + return SKP_Silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +SKP_INLINE void SKP_Silk_CLZ_FRAC(SKP_int32 in, /* I: input */ + SKP_int32 *lz, /* O: number of leading zeros */ + SKP_int32 *frac_Q7) /* O: the 7 bits right after the leading one */ +{ + SKP_int32 lzeros = SKP_Silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = SKP_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +SKP_INLINE SKP_int32 SKP_Silk_SQRT_APPROX(SKP_int32 x) +{ + SKP_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + SKP_Silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= SKP_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = SKP_SMLAWB(y, y, SKP_SMULBB(213, frac_Q7)); + + return y; +} + +/* returns the number of left shifts before overflow for a 16 bit number (ITU definition with norm(0)=0) */ +SKP_INLINE SKP_int32 SKP_Silk_norm16(SKP_int16 a) { + + SKP_int32 a32; + + /* if ((a == 0) || (a == SKP_int16_MIN)) return(0); */ + if ((a << 1) == 0) return(0); + + a32 = a; + /* if (a32 < 0) a32 = -a32 - 1; */ + a32 ^= SKP_RSHIFT(a32, 31); + + return SKP_Silk_CLZ32(a32) - 17; +} + +/* returns the number of left shifts before overflow for a 32 bit number (ITU definition with norm(0)=0) */ +SKP_INLINE SKP_int32 SKP_Silk_norm32(SKP_int32 a) { + + /* if ((a == 0) || (a == SKP_int32_MIN)) return(0); */ + if ((a << 1) == 0) return(0); + + /* if (a < 0) a = -a - 1; */ + a ^= SKP_RSHIFT(a, 31); + + return SKP_Silk_CLZ32(a) - 1; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +SKP_INLINE SKP_int32 SKP_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const SKP_int32 a32, /* I numerator (Q0) */ + const SKP_int32 b32, /* I denominator (Q0) */ + const SKP_int Qres /* I Q-domain of result (>= 0) */ +) +{ + SKP_int a_headrm, b_headrm, lshift; + SKP_int32 b32_inv, a32_nrm, b32_nrm, result; + + SKP_assert( b32 != 0 ); + SKP_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = SKP_Silk_CLZ32( SKP_abs(a32) ) - 1; + a32_nrm = SKP_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = SKP_Silk_CLZ32( SKP_abs(b32) ) - 1; + b32_nrm = SKP_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = SKP_DIV32_16( SKP_int32_MAX >> 2, SKP_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = SKP_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + a32_nrm -= SKP_LSHIFT_ovflw( SKP_SMMUL(b32_nrm, result), 3 ); /* Q: a_headrm */ + + /* Refinement */ + result = SKP_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift <= 0 ) { + return SKP_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return SKP_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +SKP_INLINE SKP_int32 SKP_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const SKP_int32 b32, /* I denominator (Q0) */ + const SKP_int Qres /* I Q-domain of result (> 0) */ +) +{ + SKP_int b_headrm, lshift; + SKP_int32 b32_inv, b32_nrm, err_Q32, result; + + SKP_assert( b32 != 0 ); + SKP_assert( b32 != SKP_int32_MIN ); /* SKP_int32_MIN is not handled by SKP_abs */ + SKP_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = SKP_Silk_CLZ32( SKP_abs(b32) ) - 1; + b32_nrm = SKP_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = SKP_DIV32_16( SKP_int32_MAX >> 2, SKP_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = SKP_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = SKP_LSHIFT_ovflw( -SKP_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = SKP_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return SKP_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return SKP_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#define SKP_SIN_APPROX_CONST0 (1073735400) +#define SKP_SIN_APPROX_CONST1 (-82778932) +#define SKP_SIN_APPROX_CONST2 (1059577) +#define SKP_SIN_APPROX_CONST3 (-5013) + +/* Sine approximation; an input of 65536 corresponds to 2 * pi */ +/* Uses polynomial expansion of the input to the power 0, 2, 4 and 6 */ +/* The relative error is below 1e-5 */ +SKP_INLINE SKP_int32 SKP_Silk_SIN_APPROX_Q24( /* O returns approximately 2^24 * sin(x * 2 * pi / 65536) */ + SKP_int32 x +) +{ + SKP_int y_Q30; + + /* Keep only bottom 16 bits (the function repeats itself with period 65536) */ + x &= 65535; + + /* Split range in four quadrants */ + if( x <= 32768 ) { + if( x < 16384 ) { + /* Return cos(pi/2 - x) */ + x = 16384 - x; + } else { + /* Return cos(x - pi/2) */ + x -= 16384; + } + if( x < 1100 ) { + /* Special case: high accuracy */ + return SKP_SMLAWB( 1 << 24, SKP_MUL( x, x ), -5053 ); + } + x = SKP_SMULWB( SKP_LSHIFT( x, 8 ), x ); /* contains x^2 in Q20 */ + y_Q30 = SKP_SMLAWB( SKP_SIN_APPROX_CONST2, x, SKP_SIN_APPROX_CONST3 ); + y_Q30 = SKP_SMLAWW( SKP_SIN_APPROX_CONST1, x, y_Q30 ); + y_Q30 = SKP_SMLAWW( SKP_SIN_APPROX_CONST0 + 66, x, y_Q30 ); + } else { + if( x < 49152 ) { + /* Return -cos(3*pi/2 - x) */ + x = 49152 - x; + } else { + /* Return -cos(x - 3*pi/2) */ + x -= 49152; + } + if( x < 1100 ) { + /* Special case: high accuracy */ + return SKP_SMLAWB( -1 << 24, SKP_MUL( x, x ), 5053 ); + } + x = SKP_SMULWB( SKP_LSHIFT( x, 8 ), x ); /* contains x^2 in Q20 */ + y_Q30 = SKP_SMLAWB( -SKP_SIN_APPROX_CONST2, x, -SKP_SIN_APPROX_CONST3 ); + y_Q30 = SKP_SMLAWW( -SKP_SIN_APPROX_CONST1, x, y_Q30 ); + y_Q30 = SKP_SMLAWW( -SKP_SIN_APPROX_CONST0, x, y_Q30 ); + } + return SKP_RSHIFT_ROUND( y_Q30, 6 ); +} + +/* Cosine approximation; an input of 65536 corresponds to 2 * pi */ +/* The relative error is below 1e-5 */ +SKP_INLINE SKP_int32 SKP_Silk_COS_APPROX_Q24( /* O returns approximately 2^24 * cos(x * 2 * pi / 65536) */ + SKP_int32 x +) +{ + return SKP_Silk_SIN_APPROX_Q24( x + 16384 ); +} + +#ifdef __cplusplus +} +#endif + +#endif /*_SKP_SILK_FIX_INLINES_H_*/ diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LBRR_reset.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LBRR_reset.c new file mode 100755 index 0000000..57bcec6 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LBRR_reset.c @@ -0,0 +1,40 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Resets LBRR buffer, used if packet size changes */ +void SKP_Silk_LBRR_reset( + SKP_Silk_encoder_state *psEncC /* I/O state */ +) +{ + SKP_int i; + + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + psEncC->LBRR_buffer[ i ].usage = SKP_SILK_NO_LBRR; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_analysis_filter_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_analysis_filter_FLP.c new file mode 100755 index 0000000..04918d9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_analysis_filter_FLP.c @@ -0,0 +1,238 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include +#include "SKP_Silk_main_FLP.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are not set */ +/*******************************************/ + +void SKP_Silk_LPC_analysis_filter_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length, /* I Length of input signal */ + const SKP_int Order /* I LPC order */ +) +{ + SKP_assert( Order <= length ); + + switch( Order ) { + case 6: + SKP_Silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + SKP_Silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + SKP_Silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + SKP_Silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + SKP_Silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + SKP_assert( 0 ); + break; + } + + /* Set first LPC Order samples to zero instead of undefined */ + SKP_memset( r_LPC, 0, Order * sizeof( SKP_float ) ); +} + +/* 16th order LPC analysis filter, does not write first 16 samples */ +void SKP_Silk_LPC_analysis_filter16_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +) +{ + SKP_int ix = 16; + SKP_float LPC_pred; + const SKP_float *s_ptr; + + for ( ; ix < length; ix++) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[-1] * PredCoef[ 1 ] + + s_ptr[-2] * PredCoef[ 2 ] + + s_ptr[-3] * PredCoef[ 3 ] + + s_ptr[-4] * PredCoef[ 4 ] + + s_ptr[-5] * PredCoef[ 5 ] + + s_ptr[-6] * PredCoef[ 6 ] + + s_ptr[-7] * PredCoef[ 7 ] + + s_ptr[-8] * PredCoef[ 8 ] + + s_ptr[-9] * PredCoef[ 9 ] + + s_ptr[-10] * PredCoef[ 10 ] + + s_ptr[-11] * PredCoef[ 11 ] + + s_ptr[-12] * PredCoef[ 12 ] + + s_ptr[-13] * PredCoef[ 13 ] + + s_ptr[-14] * PredCoef[ 14 ] + + s_ptr[-15] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +void SKP_Silk_LPC_analysis_filter12_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +) +{ + SKP_int ix = 12; + SKP_float LPC_pred; + const SKP_float *s_ptr; + + for ( ; ix < length; ix++) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[-1] * PredCoef[ 1 ] + + s_ptr[-2] * PredCoef[ 2 ] + + s_ptr[-3] * PredCoef[ 3 ] + + s_ptr[-4] * PredCoef[ 4 ] + + s_ptr[-5] * PredCoef[ 5 ] + + s_ptr[-6] * PredCoef[ 6 ] + + s_ptr[-7] * PredCoef[ 7 ] + + s_ptr[-8] * PredCoef[ 8 ] + + s_ptr[-9] * PredCoef[ 9 ] + + s_ptr[-10] * PredCoef[ 10 ] + + s_ptr[-11] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +void SKP_Silk_LPC_analysis_filter10_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +) +{ + SKP_int ix = 10; + SKP_float LPC_pred; + const SKP_float *s_ptr; + + for ( ; ix < length; ix++) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[-1] * PredCoef[ 1 ] + + s_ptr[-2] * PredCoef[ 2 ] + + s_ptr[-3] * PredCoef[ 3 ] + + s_ptr[-4] * PredCoef[ 4 ] + + s_ptr[-5] * PredCoef[ 5 ] + + s_ptr[-6] * PredCoef[ 6 ] + + s_ptr[-7] * PredCoef[ 7 ] + + s_ptr[-8] * PredCoef[ 8 ] + + s_ptr[-9] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +void SKP_Silk_LPC_analysis_filter8_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +) +{ + SKP_int ix = 8; + SKP_float LPC_pred; + const SKP_float *s_ptr; + + for ( ; ix < length; ix++) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +void SKP_Silk_LPC_analysis_filter6_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +) +{ + SKP_int ix = 6; + SKP_float LPC_pred; + const SKP_float *s_ptr; + + for ( ; ix < length; ix++) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain.c new file mode 100755 index 0000000..ddd1462 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain.c @@ -0,0 +1,153 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_inverse_pred_gain.c * + * * + * Compute inverse of LPC prediction gain, and * + * test if LPC coefficients are stable (all poles within unit circle) * + * * + * Copyright 2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +#define QA 16 +#define A_LIMIT SKP_FIX_CONST( 0.99975, QA ) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static SKP_int LPC_inverse_pred_gain_QA( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + SKP_int32 A_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ], + /* I: Prediction coefficients */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k, n, headrm; + SKP_int32 rc_Q31, rc_mult1_Q30, rc_mult2_Q16, tmp_QA; + SKP_int32 *Aold_QA, *Anew_QA; + + Anew_QA = A_QA[ order & 1 ]; + + *invGain_Q30 = ( 1 << 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) { + return 1; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -SKP_LSHIFT( Anew_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30-1 ] */ + rc_mult1_Q30 = ( SKP_int32_MAX >> 1 ) - SKP_SMMUL( rc_Q31, rc_Q31 ); + SKP_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + SKP_assert( rc_mult1_Q30 < ( 1 << 30 ) ); + + /* rc_mult2_Q16 range: [ 2^16 : SKP_int32_MAX ] */ + rc_mult2_Q16 = SKP_INVERSE32_varQ( rc_mult1_Q30, 46 ); /* 16 = 46 - 30 */ + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + *invGain_Q30 = SKP_LSHIFT( SKP_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 ); + SKP_assert( *invGain_Q30 >= 0 ); + SKP_assert( *invGain_Q30 <= ( 1 << 30 ) ); + + /* Swap pointers */ + Aold_QA = Anew_QA; + Anew_QA = A_QA[ k & 1 ]; + + /* Update AR coefficient */ + headrm = SKP_Silk_CLZ32( rc_mult2_Q16 ) - 1; + rc_mult2_Q16 = SKP_LSHIFT( rc_mult2_Q16, headrm ); /* Q: 16 + headrm */ + for( n = 0; n < k; n++ ) { + tmp_QA = Aold_QA[ n ] - SKP_LSHIFT( SKP_SMMUL( Aold_QA[ k - n - 1 ], rc_Q31 ), 1 ); + Anew_QA[ n ] = SKP_LSHIFT( SKP_SMMUL( tmp_QA, rc_mult2_Q16 ), 16 - headrm ); + } + } + + /* Check for stability */ + if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) { + return 1; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -SKP_LSHIFT( Anew_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( SKP_int32_MAX >> 1 ) - SKP_SMMUL( rc_Q31, rc_Q31 ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + *invGain_Q30 = SKP_LSHIFT( SKP_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 ); + SKP_assert( *invGain_Q30 >= 0 ); + SKP_assert( *invGain_Q30 <= 1<<30 ); + + return 0; +} +/* For input in Q12 domain */ +SKP_int SKP_Silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int16 *A_Q12, /* I: Prediction coefficients, Q12 [order] */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k; + SKP_int32 Atmp_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = SKP_LSHIFT( (SKP_int32)A_Q12[ k ], QA - 12 ); + } + + return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order ); +} + +/* For input in Q24 domain */ +SKP_int SKP_Silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int32 *A_Q24, /* I: Prediction coefficients, Q24 [order] */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k; + SKP_int32 Atmp_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = SKP_RSHIFT_ROUND( A_Q24[ k ], 24 - QA ); + } + + return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain_FLP.c new file mode 100755 index 0000000..d274a5a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_inv_pred_gain_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_inverse_pred_gain.c * + * * + * compute inverse of LPC prediction gain, and * + * test if LPC coefficients are stable (all poles within unit circle) * + * * + * Copyright 2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_SigProc_FLP.h" + +#define RC_THRESHOLD 0.9999f + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on SKP_Silk_a2k_FLP() */ +SKP_int SKP_Silk_LPC_inverse_pred_gain_FLP( /* O: returns 1 if unstable, otherwise 0 */ + SKP_float *invGain, /* O: inverse prediction gain, energy domain */ + const SKP_float *A, /* I: prediction coefficients [order] */ + SKP_int32 order /* I: prediction order */ +) +{ + SKP_int k, n; + double rc, rc_mult1, rc_mult2; + SKP_float Atmp[ 2 ][ SKP_Silk_MAX_ORDER_LPC ]; + SKP_float *Aold, *Anew; + + Anew = Atmp[ order & 1 ]; + SKP_memcpy( Anew, A, order * sizeof(SKP_float) ); + + *invGain = 1.0f; + for( k = order - 1; k > 0; k-- ) { + rc = -Anew[ k ]; + if (rc > RC_THRESHOLD || rc < -RC_THRESHOLD) { + return 1; + } + rc_mult1 = 1.0f - rc * rc; + rc_mult2 = 1.0f / rc_mult1; + *invGain *= (SKP_float)rc_mult1; + /* swap pointers */ + Aold = Anew; + Anew = Atmp[ k & 1 ]; + for( n = 0; n < k; n++ ) { + Anew[ n ] = (SKP_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 ); + } + } + rc = -Anew[ 0 ]; + if ( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { + return 1; + } + rc_mult1 = 1.0f - rc * rc; + *invGain *= (SKP_float)rc_mult1; + return 0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_filter.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_filter.c new file mode 100755 index 0000000..9b3a562 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_filter.c @@ -0,0 +1,84 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_synthesis_filter.c * + * Coefficients are in Q12 * + * * + * even order AR filter * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* even order AR filter */ +void SKP_Silk_LPC_synthesis_filter( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [Order], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [Order] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len, /* I: signal length */ + const SKP_int Order /* I: filter order, must be even */ +) +{ + SKP_int k, j, idx, Order_half = SKP_RSHIFT( Order, 1 ); + SKP_int32 SA, SB, out32_Q10, out32; + + /* Order must be even */ + SKP_assert( 2 * Order_half == Order ); + + /* S[] values are in Q14 */ + for( k = 0; k < len; k++ ) { + SA = S[ Order - 1 ]; + out32_Q10 = 0; + for( j = 0; j < ( Order_half - 1 ); j++ ) { + idx = SKP_SMULBB( 2, j ) + 1; + SB = S[ Order - 1 - idx ]; + S[ Order - 1 - idx ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ ( j << 1 ) ] ); + out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ ( j << 1 ) + 1 ] ); + SA = S[ Order - 2 - idx ]; + S[ Order - 2 - idx ] = SB; + } + + /* unrolled loop: epilog */ + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ Order - 2 ] ); + out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ Order - 1 ] ); + /* apply gain to excitation signal and add to prediction */ + out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) ); + + /* scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 ); + + /* saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* move result into delay line */ + S[ Order - 1 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_order16.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_order16.c new file mode 100755 index 0000000..f4d0bc3 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LPC_synthesis_order16.c @@ -0,0 +1,122 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_synthesis_order16.c * + * Coefficients are in Q12 * + * * + * 16th order AR filter * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* 16th order AR filter */ +void SKP_Silk_LPC_synthesis_order16(const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [16], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [16] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length, must be multiple of 16 */ +) +{ + SKP_int k; + SKP_int32 SA, SB, out32_Q10, out32; + for( k = 0; k < len; k++ ) { + /* unrolled loop: prolog */ + /* multiply-add two prediction coefficients per iteration */ + SA = S[ 15 ]; + SB = S[ 14 ]; + S[ 14 ] = SA; + out32_Q10 = SKP_SMULWB( SA, A_Q12[ 0 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 1 ] ); + SA = S[ 13 ]; + S[ 13 ] = SB; + + /* unrolled loop: main loop */ + SB = S[ 12 ]; + S[ 12 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 2 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 3 ] ); + SA = S[ 11 ]; + S[ 11 ] = SB; + + SB = S[ 10 ]; + S[ 10 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 4 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 5 ] ); + SA = S[ 9 ]; + S[ 9 ] = SB; + + SB = S[ 8 ]; + S[ 8 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 6 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 7 ] ); + SA = S[ 7 ]; + S[ 7 ] = SB; + + SB = S[ 6 ]; + S[ 6 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 8 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 9 ] ); + SA = S[ 5 ]; + S[ 5 ] = SB; + + SB = S[ 4 ]; + S[ 4 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 10 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 11 ] ); + SA = S[ 3 ]; + S[ 3 ] = SB; + + SB = S[ 2 ]; + S[ 2 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 12 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 13 ] ); + SA = S[ 1 ]; + S[ 1 ] = SB; + + /* unrolled loop: epilog */ + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 14 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 15 ] ); + + /* unrolled loop: end */ + /* apply gain to excitation signal and add to prediction */ + out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) ); + + /* scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 ); + + /* saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* move result into delay line */ + S[ 15 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 ); + } +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LP_variable_cutoff.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LP_variable_cutoff.c new file mode 100755 index 0000000..b8e1b88 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LP_variable_cutoff.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. + +*/ +#include "SKP_Silk_main.h" + +#if SWITCH_TRANSITION_FILTERING + +/* Helper function, that interpolates the filter taps */ +SKP_INLINE void SKP_Silk_LP_interpolate_filter_taps( + SKP_int32 B_Q28[ TRANSITION_NB ], + SKP_int32 A_Q28[ TRANSITION_NA ], + const SKP_int ind, + const SKP_int32 fac_Q16 +) +{ + SKP_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 == SKP_SAT16( fac_Q16 ) ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ], + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ], + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else if( fac_Q16 == ( 1 << 15 ) ) { /* Neither fac_Q16 nor ( ( 1 << 16 ) - fac_Q16 ) is in range of a 16-bit int */ + + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_RSHIFT( + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ] + + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + 1 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_RSHIFT( + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ] + + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + 1 ); + } + } else { /* ( ( 1 << 16 ) - fac_Q16 ) is in range of a 16-bit int */ + + SKP_assert( ( ( 1 << 16 ) - fac_Q16 ) == SKP_SAT16( ( ( 1 << 16 ) - fac_Q16) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ] - + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + ( 1 << 16 ) - fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ] - + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + ( 1 << 16 ) - fac_Q16 ); + } + } + } else { + SKP_memcpy( B_Q28, SKP_Silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( SKP_int32 ) ); + SKP_memcpy( A_Q28, SKP_Silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( SKP_int32 ) ); + } + } else { + SKP_memcpy( B_Q28, SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( SKP_int32 ) ); + SKP_memcpy( A_Q28, SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( SKP_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->transition_frame_no = 1; */ +/* Deactivate by setting psEncC->transition_frame_no = 0; */ +void SKP_Silk_LP_variable_cutoff( + SKP_Silk_LP_state *psLP, /* I/O LP filter state */ + SKP_int16 *out, /* O Low-pass filtered output signal */ + const SKP_int16 *in, /* I Input signal */ + const SKP_int frame_length /* I Frame length */ +) +{ + SKP_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + SKP_int ind = 0; + + SKP_assert( psLP->transition_frame_no >= 0 ); + SKP_assert( ( ( ( psLP->transition_frame_no <= TRANSITION_FRAMES_DOWN ) && ( psLP->mode == 0 ) ) || + ( ( psLP->transition_frame_no <= TRANSITION_FRAMES_UP ) && ( psLP->mode == 1 ) ) ) ); + + /* Interpolate filter coefficients if needed */ + if( psLP->transition_frame_no > 0 ) { + if( psLP->mode == 0 ) { + if( psLP->transition_frame_no < TRANSITION_FRAMES_DOWN ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS_DOWN == 32 ) + fac_Q16 = SKP_LSHIFT( psLP->transition_frame_no, 16 - 5 ); +#else + fac_Q16 = SKP_DIV32_16( SKP_LSHIFT( psLP->transition_frame_no, 16 ), TRANSITION_INT_STEPS_DOWN ); +#endif + ind = SKP_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= SKP_LSHIFT( ind, 16 ); + + SKP_assert( ind >= 0 ); + SKP_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Increment transition frame number for next frame */ + psLP->transition_frame_no++; + + } else { + SKP_assert( psLP->transition_frame_no == TRANSITION_FRAMES_DOWN ); + /* End of transition phase */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, TRANSITION_INT_NUM - 1, 0 ); + } + } else { + SKP_assert( psLP->mode == 1 ); + if( psLP->transition_frame_no < TRANSITION_FRAMES_UP ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS_UP == 64 ) + fac_Q16 = SKP_LSHIFT( TRANSITION_FRAMES_UP - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = SKP_DIV32_16( SKP_LSHIFT( TRANSITION_FRAMES_UP - psLP->transition_frame_no, 16 ), TRANSITION_INT_STEPS_UP ); +#endif + ind = SKP_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= SKP_LSHIFT( ind, 16 ); + + SKP_assert( ind >= 0 ); + SKP_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Increment transition frame number for next frame */ + psLP->transition_frame_no++; + + } else { + SKP_assert( psLP->transition_frame_no == TRANSITION_FRAMES_UP ); + /* End of transition phase */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, 0, 0 ); + } + } + } + + if( psLP->transition_frame_no > 0 ) { + /* ARMA low-pass filtering */ + SKP_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + SKP_Silk_biquad_alt( in, B_Q28, A_Q28, psLP->In_LP_State, out, frame_length ); + } else { + /* Instead of using the filter, copy input directly to output */ + SKP_memcpy( out, in, frame_length * sizeof( SKP_int16 ) ); + } +} +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LSF_cos_table.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LSF_cos_table.c new file mode 100755 index 0000000..aba3e1d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LSF_cos_table.c @@ -0,0 +1,65 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +// Q12 values (even) +const SKP_int SKP_Silk_LSFCosTab_FIX_Q12[LSF_COS_TAB_SZ_FIX + 1] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_analysis_filter_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_analysis_filter_FLP.c new file mode 100755 index 0000000..dd34892 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_analysis_filter_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +void SKP_Silk_LTP_analysis_filter_FLP( + SKP_float *LTP_res, /* O LTP res NB_SUBFR*(pre_lgth+subfr_lngth) */ + const SKP_float *x, /* I Input signal, with preceeding samples */ + const SKP_float B[ LTP_ORDER * NB_SUBFR ], /* I LTP coefficients for each subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I Pitch lags */ + const SKP_float invGains[ NB_SUBFR ], /* I Inverse quantization gains */ + const SKP_int subfr_length, /* I Length of each subframe */ + const SKP_int pre_length /* I Preceeding samples for each subframe */ +) +{ + const SKP_float *x_ptr, *x_lag_ptr; + SKP_float Btmp[ LTP_ORDER ]; + SKP_float *LTP_res_ptr; + SKP_float inv_gain; + SKP_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < NB_SUBFR; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_scale_ctrl_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_scale_ctrl_FLP.c new file mode 100755 index 0000000..59aaa70 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_LTP_scale_ctrl_FLP.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +#define NB_THRESHOLDS 11 +/* Table containing trained thresholds for LTP scaling */ +static const SKP_float LTPScaleThresholds[ NB_THRESHOLDS ] = +{ + 0.95f, 0.8f, 0.50f, 0.400f, 0.3f, 0.2f, + 0.15f, 0.1f, 0.08f, 0.075f, 0.0f +}; + + +void SKP_Silk_LTP_scale_ctrl_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl /* I/O Encoder control FLP */ +) +{ + SKP_int round_loss, frames_per_packet; + SKP_float g_out, g_limit, thrld1, thrld2; + + /* 1st order high-pass filter */ + //g_HP(n) = g(n) - g(n-1) + 0.5 * g_HP(n-1); // tune the 0.5: higher means longer impact of jump + psEnc->HPLTPredCodGain = SKP_max_float( psEncCtrl->LTPredCodGain - psEnc->prevLTPredCodGain, 0.0f ) + + 0.5f * psEnc->HPLTPredCodGain; + + psEnc->prevLTPredCodGain = psEncCtrl->LTPredCodGain; + + /* Combine input and filtered input */ + g_out = 0.5f * psEncCtrl->LTPredCodGain + ( 1.0f - 0.5f ) * psEnc->HPLTPredCodGain; + g_limit = SKP_sigmoid( 0.5f * ( g_out - 6 ) ); + + + /* Default is minimum scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 0; + + /* Round the loss measure to whole pct */ + round_loss = ( SKP_int )( psEnc->sCmn.PacketLoss_perc ); + round_loss = SKP_max( 0, round_loss ); + + /* Only scale if first frame in packet 0% */ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ){ + + frames_per_packet = psEnc->sCmn.PacketSize_ms / FRAME_LENGTH_MS; + + round_loss += ( frames_per_packet - 1 ); + thrld1 = LTPScaleThresholds[ SKP_min_int( round_loss, NB_THRESHOLDS - 1 ) ]; + thrld2 = LTPScaleThresholds[ SKP_min_int( round_loss + 1, NB_THRESHOLDS - 1 ) ]; + + if( g_limit > thrld1 ) { + /* High Scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 2; + } else if( g_limit > thrld2 ) { + /* Middle Scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 1; + } + } + psEncCtrl->LTP_scale = ( SKP_float)SKP_Silk_LTPScales_table_Q14[ psEncCtrl->sCmn.LTP_scaleIndex ] / 16384.0f; + +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_MA.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_MA.c new file mode 100755 index 0000000..461e291 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_MA.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_MA.c * + * * + * Variable order MA filter * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Variable order MA prediction error filter */ +void SKP_Silk_MA_Prediction( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int32 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 order /* I: Filter order */ +) +{ + SKP_int k, d, in16; + SKP_int32 out32; + + for( k = 0; k < len; k++ ) { + in16 = in[ k ]; + out32 = SKP_LSHIFT( in16, 12 ) - S[ 0 ]; + out32 = SKP_RSHIFT_ROUND( out32, 12 ); + + for( d = 0; d < order - 1; d++ ) { + S[ d ] = SKP_SMLABB_ovflw( S[ d + 1 ], in16, B[ d ] ); + } + S[ order - 1 ] = SKP_SMULBB( in16, B[ order - 1 ] ); + + /* Limit */ + out[ k ] = (SKP_int16)SKP_SAT16( out32 ); + } +} + + +void SKP_Silk_LPC_analysis_filter( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int16 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 Order /* I: Filter order */ +) +{ + SKP_int k, j, idx, Order_half = SKP_RSHIFT( Order, 1 ); + SKP_int32 out32_Q12, out32; + SKP_int16 SA, SB; + /* Order must be even */ + SKP_assert( 2 * Order_half == Order ); + + /* S[] values are in Q0 */ + for( k = 0; k < len; k++ ) { + SA = S[ 0 ]; + out32_Q12 = 0; + for( j = 0; j < ( Order_half - 1 ); j++ ) { + idx = SKP_SMULBB( 2, j ) + 1; + /* Multiply-add two prediction coefficients for each loop */ + SB = S[ idx ]; + S[ idx ] = SA; + out32_Q12 = SKP_SMLABB( out32_Q12, SA, B[ idx - 1 ] ); + out32_Q12 = SKP_SMLABB( out32_Q12, SB, B[ idx ] ); + SA = S[ idx + 1 ]; + S[ idx + 1 ] = SB; + } + + /* Unrolled loop: epilog */ + SB = S[ Order - 1 ]; + S[ Order - 1 ] = SA; + out32_Q12 = SKP_SMLABB( out32_Q12, SA, B[ Order - 2 ] ); + out32_Q12 = SKP_SMLABB( out32_Q12, SB, B[ Order - 1 ] ); + + /* Subtract prediction */ + out32_Q12 = SKP_SUB_SAT32( SKP_LSHIFT( (SKP_int32)in[ k ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* Move input line */ + S[ 0 ] = in[ k ]; + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A.c new file mode 100755 index 0000000..47b62b9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* function are accurate inverses of each other */ + +#include "SKP_Silk_SigProc_FIX.h" + +/* helper function for NLSF2A(..) */ +SKP_INLINE void SKP_Silk_NLSF2A_find_poly( + SKP_int32 *out, /* o intermediate polynomial, Q20 */ + const SKP_int32 *cLSF, /* i vector of interleaved 2*cos(LSFs), Q20 */ + SKP_int dd /* i polynomial order (= 1/2 * filter order) */ +) +{ + SKP_int k, n; + SKP_int32 ftmp; + + out[0] = SKP_LSHIFT( 1, 20 ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; // Q20 + out[k+1] = SKP_LSHIFT( out[k-1], 1 ) - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[k] ), 20 ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[n-1] ), 20 ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void SKP_Silk_NLSF2A( + SKP_int16 *a, /* o monic whitening filter coefficients in Q12, [d] */ + const SKP_int *NLSF, /* i normalized line spectral frequencies in Q15, [d] */ + const SKP_int d /* i filter order (should be even) */ +) +{ + SKP_int k, i, dd; + SKP_int32 cos_LSF_Q20[SKP_Silk_MAX_ORDER_LPC]; + SKP_int32 P[SKP_Silk_MAX_ORDER_LPC/2+1], Q[SKP_Silk_MAX_ORDER_LPC/2+1]; + SKP_int32 Ptmp, Qtmp; + SKP_int32 f_int; + SKP_int32 f_frac; + SKP_int32 cos_val, delta; + SKP_int32 a_int32[SKP_Silk_MAX_ORDER_LPC]; + SKP_int32 maxabs, absval, idx=0, sc_Q16; + + SKP_assert(LSF_COS_TAB_SZ_FIX == 128); + + /* convert LSFs to 2*cos(LSF(i)), using piecewise linear curve from table */ + for( k = 0; k < d; k++ ) { + SKP_assert(NLSF[k] >= 0 ); + SKP_assert(NLSF[k] <= 32767 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = SKP_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - SKP_LSHIFT( f_int, 15 - 7 ); + + SKP_assert(f_int >= 0); + SKP_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = SKP_Silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = SKP_Silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_Q20[k] = SKP_LSHIFT( cos_val, 8 ) + SKP_MUL( delta, f_frac ); /* Q20 */ + } + + dd = SKP_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + SKP_Silk_NLSF2A_find_poly( P, &cos_LSF_Q20[0], dd ); + SKP_Silk_NLSF2A_find_poly( Q, &cos_LSF_Q20[1], dd ); + + /* convert even and odd polynomials to SKP_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[k+1] + P[k]; + Qtmp = Q[k+1] - Q[k]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + + a_int32[k] = -SKP_RSHIFT_ROUND( Ptmp + Qtmp, 9 ); /* Q20 -> Q12 */ + a_int32[d-k-1] = SKP_RSHIFT_ROUND( Qtmp - Ptmp, 9 ); /* Q20 -> Q12 */ + } + + /* Limit the maximum absolute value of the prediction coefficients */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = SKP_abs( a_int32[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + + if( maxabs > SKP_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = SKP_min( maxabs, 98369 ); // ( SKP_int32_MAX / ( 65470 >> 2 ) ) + SKP_int16_MAX = 98369 + sc_Q16 = 65470 - SKP_DIV32( SKP_MUL( 65470 >> 2, maxabs - SKP_int16_MAX ), + SKP_RSHIFT32( SKP_MUL( maxabs, idx + 1), 2 ) ); + SKP_Silk_bwexpander_32( a_int32, d, sc_Q16 ); + } else { + break; + } + } + + /* Reached the last iteration */ + if( i == 10 ) { + SKP_assert(0); + for( k = 0; k < d; k++ ) { + a_int32[k] = SKP_SAT16( a_int32[k] ); + } + } + + /* Return as SKP_int16 Q12 coefficients */ + for( k = 0; k < d; k++ ) { + a[k] = (SKP_int16)a_int32[k]; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A_stable.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A_stable.c new file mode 100755 index 0000000..d36b075 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF2A_stable.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Convert NLSF parameters to stable AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable( + SKP_int16 pAR_Q12[ MAX_LPC_ORDER ], /* O Stabilized AR coefs [LPC_order] */ + const SKP_int pNLSF[ MAX_LPC_ORDER ], /* I NLSF vector [LPC_order] */ + const SKP_int LPC_order /* I LPC/LSF order */ +) +{ + SKP_int i; + SKP_int32 invGain_Q30; + + SKP_Silk_NLSF2A( pAR_Q12, pNLSF, LPC_order ); + + /* Ensure stable LPCs */ + for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + if( SKP_Silk_LPC_inverse_pred_gain( &invGain_Q30, pAR_Q12, LPC_order ) == 1 ) { + SKP_Silk_bwexpander( pAR_Q12, LPC_order, 65536 - SKP_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015 */ + } else { + break; + } + } + + /* Reached the last iteration */ + if( i == MAX_LPC_STABILIZE_ITERATIONS ) { + SKP_assert( 0 ); + for( i = 0; i < LPC_order; i++ ) { + pAR_Q12[ i ] = 0; + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode.c new file mode 100755 index 0000000..bb3baf8 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode( + SKP_int *pNLSF_Q15, /* O Pointer to decoded output vector [LPC_ORDER x 1] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Pointer to NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I Pointer to NLSF indices [nStages x 1] */ + const SKP_int LPC_order /* I LPC order used */ +) +{ + const SKP_int16 *pCB_element; + SKP_int s; + SKP_int i; + + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ 0 ] && NLSFIndices[ 0 ] < psNLSF_CB->CBStages[ 0 ].nVectors ); + + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ 0 ].CB_NLSF_Q15[ SKP_MUL( NLSFIndices[ 0 ], LPC_order ) ]; + + /* Initialize with the codebook vector from stage 0 */ + for( i = 0; i < LPC_order; i++ ) { + pNLSF_Q15[ i ] = ( SKP_int )pCB_element[ i ]; + } + + for( s = 1; s < psNLSF_CB->nStages; s++ ) { + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ s ] && NLSFIndices[ s ] < psNLSF_CB->CBStages[ s ].nVectors ); + + if( LPC_order == 16 ) { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ s ].CB_NLSF_Q15[ SKP_LSHIFT( NLSFIndices[ s ], 4 ) ]; + + /* Add the codebook vector from the current stage */ + pNLSF_Q15[ 0 ] += pCB_element[ 0 ]; + pNLSF_Q15[ 1 ] += pCB_element[ 1 ]; + pNLSF_Q15[ 2 ] += pCB_element[ 2 ]; + pNLSF_Q15[ 3 ] += pCB_element[ 3 ]; + pNLSF_Q15[ 4 ] += pCB_element[ 4 ]; + pNLSF_Q15[ 5 ] += pCB_element[ 5 ]; + pNLSF_Q15[ 6 ] += pCB_element[ 6 ]; + pNLSF_Q15[ 7 ] += pCB_element[ 7 ]; + pNLSF_Q15[ 8 ] += pCB_element[ 8 ]; + pNLSF_Q15[ 9 ] += pCB_element[ 9 ]; + pNLSF_Q15[ 10 ] += pCB_element[ 10 ]; + pNLSF_Q15[ 11 ] += pCB_element[ 11 ]; + pNLSF_Q15[ 12 ] += pCB_element[ 12 ]; + pNLSF_Q15[ 13 ] += pCB_element[ 13 ]; + pNLSF_Q15[ 14 ] += pCB_element[ 14 ]; + pNLSF_Q15[ 15 ] += pCB_element[ 15 ]; + } else { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ s ].CB_NLSF_Q15[ SKP_SMULBB( NLSFIndices[ s ], LPC_order ) ]; + + /* Add the codebook vector from the current stage */ + for( i = 0; i < LPC_order; i++ ) { + pNLSF_Q15[ i ] += pCB_element[ i ]; + } + } + } + + /* NLSF stabilization */ + SKP_Silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->NDeltaMin_Q15, LPC_order ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode_FLP.c new file mode 100755 index 0000000..e7c560a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_decode_FLP.c @@ -0,0 +1,89 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode_FLP( + SKP_float *pNLSF, /* O Decoded output vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP, /* I NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I NLSF indices [ nStages ] */ + const SKP_int LPC_order /* I LPC order used */ +) +{ + const SKP_float *pCB_element; + SKP_int s; + SKP_int i; + + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ 0 ] && NLSFIndices[ 0 ] < psNLSF_CB_FLP->CBStages[ 0 ].nVectors ); + + /* Point to the first vector element */ + pCB_element = &psNLSF_CB_FLP->CBStages[ 0 ].CB[ SKP_MUL( NLSFIndices[ 0 ], LPC_order ) ]; + + /* Initialize with the codebook vector from stage 0 */ + SKP_memcpy( pNLSF, pCB_element, LPC_order * sizeof( SKP_float ) ); + + for( s = 1; s < psNLSF_CB_FLP->nStages; s++ ) { + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ s ] && NLSFIndices[ s ] < psNLSF_CB_FLP->CBStages[ s ].nVectors ); + + if( LPC_order == 16 ) { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB_FLP->CBStages[ s ].CB[ SKP_LSHIFT( NLSFIndices[ s ], 4 ) ]; + + /* Add the codebook vector from the current stage */ + pNLSF[ 0 ] += pCB_element[ 0 ]; + pNLSF[ 1 ] += pCB_element[ 1 ]; + pNLSF[ 2 ] += pCB_element[ 2 ]; + pNLSF[ 3 ] += pCB_element[ 3 ]; + pNLSF[ 4 ] += pCB_element[ 4 ]; + pNLSF[ 5 ] += pCB_element[ 5 ]; + pNLSF[ 6 ] += pCB_element[ 6 ]; + pNLSF[ 7 ] += pCB_element[ 7 ]; + pNLSF[ 8 ] += pCB_element[ 8 ]; + pNLSF[ 9 ] += pCB_element[ 9 ]; + pNLSF[ 10 ] += pCB_element[ 10 ]; + pNLSF[ 11 ] += pCB_element[ 11 ]; + pNLSF[ 12 ] += pCB_element[ 12 ]; + pNLSF[ 13 ] += pCB_element[ 13 ]; + pNLSF[ 14 ] += pCB_element[ 14 ]; + pNLSF[ 15 ] += pCB_element[ 15 ]; + } else { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB_FLP->CBStages[ s ].CB[ NLSFIndices[ s ] * LPC_order ]; + + /* Add the codebook vector from the current stage */ + for( i = 0; i < LPC_order; i++ ) { + pNLSF[ i ] += pCB_element[ i ]; + } + } + } + + /* NLSF stabilization */ + SKP_Silk_NLSF_stabilize_FLP( pNLSF, psNLSF_CB_FLP->NDeltaMin, LPC_order ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_encode_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_encode_FLP.c new file mode 100755 index 0000000..22bc9d1 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_MSVQ_encode_FLP.c @@ -0,0 +1,233 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +void SKP_Silk_NLSF_MSVQ_encode_FLP( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_float *pNLSF, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP, /* I Codebook object */ + const SKP_float *pNLSF_q_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_float *pW, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_float NLSF_mu, /* I Rate weight for the RD optimization */ + const SKP_float NLSF_mu_fluc_red, /* I Fluctuation reduction error weight */ + const SKP_int NLSF_MSVQ_Survivors,/* I Max survivors from each stage */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int deactivate_fluc_red /* I Deactivate fluctuation reduction */ +) +{ + SKP_int i, s, k, cur_survivors, prev_survivors, min_survivors, input_index, cb_index, bestIndex; + SKP_float se, wsse, rateDistThreshold, bestRateDist; + +#if( LOW_COMPLEXITY_ONLY == 1 ) + SKP_float pRateDist[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE ]; + SKP_float pRate[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_float pRate_new[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int pTempIndices[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int pPath[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pPath_new[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_float pRes[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; + SKP_float pRes_new[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; +#else + SKP_float pRateDist[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED ]; + SKP_float pRate[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_float pRate_new[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int pTempIndices[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int pPath[ MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pPath_new[ MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_float pRes[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; + SKP_float pRes_new[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; +#endif + + const SKP_float *pConstFloat; + SKP_float *pFloat; + const SKP_int *pConstInt; + SKP_int *pInt; + const SKP_float *pCB_element; + const SKP_Silk_NLSF_CBS_FLP *pCurrentCBStage; + +#ifdef USE_UNQUANTIZED_LSFS + SKP_float NLSF_orig[ MAX_LPC_ORDER ]; + SKP_memcpy( NLSF_orig, pNLSF, LPC_order * sizeof( SKP_float ) ); +#endif + + SKP_assert( NLSF_MSVQ_Survivors <= MAX_NLSF_MSVQ_SURVIVORS ); + SKP_assert( ( LOW_COMPLEXITY_ONLY == 0 ) || ( NLSF_MSVQ_Survivors <= MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ) ); + + cur_survivors = NLSF_MSVQ_Survivors; + + + /****************************************************/ + /* Tree search for the multi-stage vector quantizer */ + /****************************************************/ + + /* Clear accumulated rates */ + SKP_memset( pRate, 0, NLSF_MSVQ_Survivors * sizeof( SKP_float ) ); + + /* Copy NLSFs into residual signal vector */ + SKP_memcpy( pRes, pNLSF, LPC_order * sizeof( SKP_float ) ); + + /* Set first stage values */ + prev_survivors = 1; + + /* Minimum number of survivors */ + min_survivors = NLSF_MSVQ_Survivors / 2; + + /* Loop over all stages */ + for( s = 0; s < psNLSF_CB_FLP->nStages; s++ ) { + + /* Set a pointer to the current stage codebook */ + pCurrentCBStage = &psNLSF_CB_FLP->CBStages[ s ]; + + /* Calculate the number of survivors in the current stage */ + cur_survivors = SKP_min_32( NLSF_MSVQ_Survivors, prev_survivors * pCurrentCBStage->nVectors ); + +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 0 ) + /* Find a single best survivor in the last stage, if we */ + /* do not need candidates for fluctuation reduction */ + if( s == psNLSF_CB_FLP->nStages - 1 ) { + cur_survivors = 1; + } +#endif + + /* Nearest neighbor clustering for multiple input data vectors */ + SKP_Silk_NLSF_VQ_rate_distortion_FLP( pRateDist, pCurrentCBStage, pRes, pW, pRate, NLSF_mu, prev_survivors, LPC_order ); + + /* Sort the rate-distortion errors */ + SKP_Silk_insertion_sort_increasing_FLP( pRateDist, pTempIndices, prev_survivors * pCurrentCBStage->nVectors, cur_survivors ); + + /* Discard survivors with rate-distortion values too far above the best one */ + rateDistThreshold = ( 1.0f + NLSF_MSVQ_Survivors * NLSF_MSVQ_SURV_MAX_REL_RD ) * pRateDist[ 0 ]; + while( pRateDist[ cur_survivors - 1 ] > rateDistThreshold && cur_survivors > min_survivors ) { + cur_survivors--; + } + + /* Update accumulated codebook contributions for the 'cur_survivors' best codebook indices */ + for( k = 0; k < cur_survivors; k++ ) { + if( s > 0 ) { + /* Find the indices of the input and the codebook vector */ + if( pCurrentCBStage->nVectors == 8 ) { + input_index = SKP_RSHIFT( pTempIndices[ k ], 3 ); + cb_index = pTempIndices[ k ] & 7; + } else { + input_index = pTempIndices[ k ] / pCurrentCBStage->nVectors; + cb_index = pTempIndices[ k ] - input_index * pCurrentCBStage->nVectors; + } + } else { + /* Find the indices of the input and the codebook vector */ + input_index = 0; + cb_index = pTempIndices[ k ]; + } + + /* Subtract new contribution from the previous residual vector for each of 'cur_survivors' */ + pConstFloat = &pRes[ input_index * LPC_order ]; + pCB_element = &pCurrentCBStage->CB[ cb_index * LPC_order ]; + pFloat = &pRes_new[ k * LPC_order ]; + for( i = 0; i < LPC_order; i++ ) { + pFloat[ i ] = pConstFloat[ i ] - pCB_element[ i ]; + } + + /* Update accumulated rate for stage 1 to the current */ + pRate_new[ k ] = pRate[ input_index ] + pCurrentCBStage->Rates[ cb_index ]; + + /* Copy paths from previous matrix, starting with the best path */ + pConstInt = &pPath[ input_index * psNLSF_CB_FLP->nStages ]; + pInt = &pPath_new[ k * psNLSF_CB_FLP->nStages ]; + for( i = 0; i < s; i++ ) { + pInt[ i ] = pConstInt[ i ]; + } + /* Write the current stage indices for the 'cur_survivors' to the best path matrix */ + pInt[ s ] = cb_index; + } + + if( s < psNLSF_CB_FLP->nStages - 1 ) { + /* Copy NLSF residual matrix for next stage */ + SKP_memcpy(pRes, pRes_new, cur_survivors * LPC_order * sizeof( SKP_float ) ); + + /* Copy rate vector for next stage */ + SKP_memcpy(pRate, pRate_new, cur_survivors * sizeof( SKP_float ) ); + + /* Copy best path matrix for next stage */ + SKP_memcpy(pPath, pPath_new, cur_survivors * psNLSF_CB_FLP->nStages * sizeof( SKP_int ) ); + } + + prev_survivors = cur_survivors; + } + + /* (Preliminary) index of the best survivor, later to be decoded */ + bestIndex = 0; + +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 1 ) + /******************************/ + /* NLSF fluctuation reduction */ + /******************************/ + if( deactivate_fluc_red != 1 ) { + + /* Search among all survivors, now taking also weighted fluctuation errors into account */ + bestRateDist = SKP_float_MAX; + for( s = 0; s < cur_survivors; s++ ) { + /* Decode survivor to compare with previous quantized NLSF vector */ + SKP_Silk_NLSF_MSVQ_decode_FLP( pNLSF, psNLSF_CB_FLP, &pPath_new[ s * psNLSF_CB_FLP->nStages ], LPC_order ); + + /* Compare decoded NLSF vector with the previously quantized vector */ + wsse = 0; + for( i = 0; i < LPC_order; i += 2 ) { + /* Compute weighted squared quantization error for index i */ + se = pNLSF[ i ] - pNLSF_q_prev[ i ]; + wsse += pW[ i ] * se * se; + + /* Compute weighted squared quantization error for index i + 1 */ + se = pNLSF[ i + 1 ] - pNLSF_q_prev[ i + 1 ]; + wsse += pW[ i + 1 ] * se * se; + } + + /* Add the fluctuation reduction penalty to the rate distortion error */ + wsse = pRateDist[s] + wsse * NLSF_mu_fluc_red; + + /* Keep index of best survivor */ + if( wsse < bestRateDist ) { + bestRateDist = wsse; + bestIndex = s; + } + } + } +#endif + + /* Copy best path to output argument */ + SKP_memcpy( NLSFIndices, &pPath_new[ bestIndex * psNLSF_CB_FLP->nStages ], psNLSF_CB_FLP->nStages * sizeof( SKP_int ) ); + + /* Decode and stabilize the best survivor */ + SKP_Silk_NLSF_MSVQ_decode_FLP( pNLSF, psNLSF_CB_FLP, NLSFIndices, LPC_order ); + +#ifdef USE_UNQUANTIZED_LSFS + SKP_memcpy( pNLSF, NLSF_orig, LPC_order * sizeof( SKP_float ) ); +#endif + +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c new file mode 100755 index 0000000..0635ce5 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FLP( + SKP_float *pRD, /* O Rate-distortion values [psNLSF_CBS_FLP->nVectors*N] */ + const SKP_Silk_NLSF_CBS_FLP *psNLSF_CBS_FLP, /* I NLSF codebook stage struct */ + const SKP_float *in, /* I Input vectors to be quantized */ + const SKP_float *w, /* I Weight vector */ + const SKP_float *rate_acc, /* I Accumulated rates from previous stage */ + const SKP_float mu, /* I Weight between weighted error and rate */ + const SKP_int N, /* I Number of input vectors to be quantized */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_float *pRD_vec; + SKP_int i, n; + + /* Compute weighted quantization errors for all input vectors over one codebook stage */ + SKP_Silk_NLSF_VQ_sum_error_FLP( pRD, in, w, psNLSF_CBS_FLP->CB, N, psNLSF_CBS_FLP->nVectors, LPC_order ); + + /* Loop over input vectors */ + pRD_vec = pRD; + for( n = 0; n < N; n++ ) { + /* Add rate cost to error for each codebook vector */ + for( i = 0; i < psNLSF_CBS_FLP->nVectors; i++ ) { + pRD_vec[ i ] += mu * ( rate_acc[n] + psNLSF_CBS_FLP->Rates[ i ] ); + } + pRD_vec += psNLSF_CBS_FLP->nVectors; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_sum_error_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_sum_error_FLP.c new file mode 100755 index 0000000..ae62683 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_sum_error_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* compute weighted quantization errors for LPC_order element input vectors, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FLP( + SKP_float *err, /* O Weighted quantization errors [ N * K ] */ + const SKP_float *in, /* I Input vectors [ N * LPC_order ] */ + const SKP_float *w, /* I Weighting vectors [ N * LPC_order ] */ + const SKP_float *pCB, /* I Codebook vectors [ K * LPC_order ] */ + const SKP_int N, /* I Number of input vectors */ + const SKP_int K, /* I Number of codebook vectors */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int i, n; + SKP_float diff, sum_error; + SKP_float Wcpy[ MAX_LPC_ORDER ]; + const SKP_float *cb_vec; + + /* Copy to local stack */ + SKP_memcpy( Wcpy, w, LPC_order * sizeof( SKP_float ) ); + + if( LPC_order == 16 ) { + /* Loop over input vectors */ + for( n = 0; n < N; n++ ) { + /* Loop over codebook */ + cb_vec = pCB; + for( i = 0; i < K; i++ ) { + /* Compute weighted squared quantization error */ + diff = in[ 0 ] - cb_vec[ 0 ]; + sum_error = Wcpy[ 0 ] * diff * diff; + diff = in[ 1 ] - cb_vec[ 1 ]; + sum_error += Wcpy[ 1 ] * diff * diff; + diff = in[ 2 ] - cb_vec[ 2 ]; + sum_error += Wcpy[ 2 ] * diff * diff; + diff = in[ 3 ] - cb_vec[ 3 ]; + sum_error += Wcpy[ 3 ] * diff * diff; + diff = in[ 4 ] - cb_vec[ 4 ]; + sum_error += Wcpy[ 4 ] * diff * diff; + diff = in[ 5 ] - cb_vec[ 5 ]; + sum_error += Wcpy[ 5 ] * diff * diff; + diff = in[ 6 ] - cb_vec[ 6 ]; + sum_error += Wcpy[ 6 ] * diff * diff; + diff = in[ 7 ] - cb_vec[ 7 ]; + sum_error += Wcpy[ 7 ] * diff * diff; + diff = in[ 8 ] - cb_vec[ 8 ]; + sum_error += Wcpy[ 8 ] * diff * diff; + diff = in[ 9 ] - cb_vec[ 9 ]; + sum_error += Wcpy[ 9 ] * diff * diff; + diff = in[ 10 ] - cb_vec[ 10 ]; + sum_error += Wcpy[ 10 ] * diff * diff; + diff = in[ 11 ] - cb_vec[ 11 ]; + sum_error += Wcpy[ 11 ] * diff * diff; + diff = in[ 12 ] - cb_vec[ 12 ]; + sum_error += Wcpy[ 12 ] * diff * diff; + diff = in[ 13 ] - cb_vec[ 13 ]; + sum_error += Wcpy[ 13 ] * diff * diff; + diff = in[ 14 ] - cb_vec[ 14 ]; + sum_error += Wcpy[ 14 ] * diff * diff; + diff = in[ 15 ] - cb_vec[ 15 ]; + sum_error += Wcpy[ 15 ] * diff * diff; + + err[ i ] = sum_error; + cb_vec += 16; + } + err += K; + in += 16; + } + } else { + SKP_assert( LPC_order == 10 ); + + /* Loop over input vectors */ + for( n = 0; n < N; n++ ) { + /* Loop over codebook */ + cb_vec = pCB; + for( i = 0; i < K; i++ ) { + /* Compute weighted squared quantization error */ + diff = in[ 0 ] - cb_vec[ 0 ]; + sum_error = Wcpy[ 0 ] * diff * diff; + diff = in[ 1 ] - cb_vec[ 1 ]; + sum_error += Wcpy[ 1 ] * diff * diff; + diff = in[ 2 ] - cb_vec[ 2 ]; + sum_error += Wcpy[ 2 ] * diff * diff; + diff = in[ 3 ] - cb_vec[ 3 ]; + sum_error += Wcpy[ 3 ] * diff * diff; + diff = in[ 4 ] - cb_vec[ 4 ]; + sum_error += Wcpy[ 4 ] * diff * diff; + diff = in[ 5 ] - cb_vec[ 5 ]; + sum_error += Wcpy[ 5 ] * diff * diff; + diff = in[ 6 ] - cb_vec[ 6 ]; + sum_error += Wcpy[ 6 ] * diff * diff; + diff = in[ 7 ] - cb_vec[ 7 ]; + sum_error += Wcpy[ 7 ] * diff * diff; + diff = in[ 8 ] - cb_vec[ 8 ]; + sum_error += Wcpy[ 8 ] * diff * diff; + diff = in[ 9 ] - cb_vec[ 9 ]; + sum_error += Wcpy[ 9 ] * diff * diff; + + err[ i ] = sum_error; + cb_vec += 10; + } + err += K; + in += 10; + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c new file mode 100755 index 0000000..76bf8f9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +#define MIN_NDELTA 1e-4f + +/* Laroia low complexity NLSF weights */ +void SKP_Silk_NLSF_VQ_weights_laroia_FLP( + SKP_float *pXW, /* 0: Pointer to input vector weights [D x 1] */ + const SKP_float *pX, /* I: Pointer to input vector [D x 1] */ + const SKP_int D /* I: Input vector dimension */ +) +{ + SKP_int k; + SKP_float tmp1, tmp2; + + /* Safety checks */ + SKP_assert( D > 0 ); + SKP_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1 = 1.0f / SKP_max_float( pX[ 0 ], MIN_NDELTA ); + tmp2 = 1.0f / SKP_max_float( pX[ 1 ] - pX[ 0 ], MIN_NDELTA ); + pXW[ 0 ] = tmp1 + tmp2; + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1 = 1.0f / SKP_max_float( pX[ k + 1 ] - pX[ k ], MIN_NDELTA ); + pXW[ k ] = tmp1 + tmp2; + + tmp2 = 1.0f / SKP_max_float( pX[ k + 2 ] - pX[ k + 1 ], MIN_NDELTA ); + pXW[ k + 1 ] = tmp1 + tmp2; + } + + /* Last value */ + tmp1 = 1.0f / SKP_max_float( 1.0f - pX[ D - 1 ], MIN_NDELTA ); + pXW[ D - 1 ] = tmp1 + tmp2; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_stabilize.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_stabilize.c new file mode 100755 index 0000000..70b554b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NLSF_stabilize.c @@ -0,0 +1,139 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs futher apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize( + SKP_int *NLSF_Q15, /* I/O: Unstable/stabilized normalized LSF vector in Q15 [L] */ + const SKP_int *NDeltaMin_Q15, /* I: Normalized delta min vector in Q15, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const SKP_int L /* I: Number of NLSF parameters in the input vector */ +) +{ + SKP_int center_freq_Q15, diff_Q15, min_center_Q15, max_center_Q15; + SKP_int32 min_diff_Q15; + SKP_int loops; + SKP_int i, I=0, k; + + /* This is necessary to ensure an output within range of a SKP_int16 */ + SKP_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = (1<<15) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if (min_diff_Q15 >= 0) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = (1<<15) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += SKP_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = (1<<15); + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= ( NDeltaMin_Q15[I] - SKP_RSHIFT( NDeltaMin_Q15[I], 1 ) ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = SKP_LIMIT_32( SKP_RSHIFT_ROUND( (SKP_int32)NLSF_Q15[I-1] + (SKP_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - SKP_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + SKP_Silk_insertion_sort_increasing_all_values(&NLSF_Q15[0], L); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = SKP_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = SKP_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = SKP_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = SKP_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ.c new file mode 100755 index 0000000..1d9ba52 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ.c @@ -0,0 +1,421 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +SKP_INLINE void SKP_Silk_nsq_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I input in Q0 */ + SKP_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + SKP_int subfr_length, /* I length of input */ + const SKP_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I subframe number */ + const SKP_int LTP_scale_Q14, /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I */ +); + +SKP_INLINE void SKP_Silk_noise_shape_quantizer( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_sc_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int shapingLPCOrder, /* I Noise shaping AR filter order */ + SKP_int predictLPCOrder /* I Prediction filter order */ +); + +void SKP_Silk_NSQ( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I prefiltered input signal */ + SKP_int8 q[], /* O quantized qulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefficients */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I Long term prediction coefficients */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + SKP_int k, lag, start_idx, LSF_interpolation_flag; + const SKP_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + SKP_int16 *pxq; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 HarmShapeFIRPacked_Q14; + SKP_int offset_Q10; + SKP_int32 FiltState[ MAX_LPC_ORDER ]; + SKP_int32 x_sc_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + + NSQ->rand_seed = psEncCtrlC->Seed; + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + SKP_assert( NSQ->prev_inv_gain_Q16 != 0 ); + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrlC->sigtype ][ psEncCtrlC->QuantOffsetType ]; + + if( LSFInterpFactor_Q2 == ( 1 << 2 ) ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Setup pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->frame_length; + NSQ->sLTP_buf_idx = psEncC->frame_length; + pxq = &NSQ->xq[ psEncC->frame_length ]; + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + SKP_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = SKP_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + lag = psEncCtrlC->pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - SKP_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + + /* Rewhiten with new A coefs */ + start_idx = psEncC->frame_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psEncC->frame_length - psEncC->predictLPCOrder ); + + SKP_memset( FiltState, 0, psEncC->predictLPCOrder * sizeof( SKP_int32 ) ); + SKP_Silk_MA_Prediction( &NSQ->xq[ start_idx + k * ( psEncC->frame_length >> 2 ) ], + A_Q12, FiltState, sLTP + start_idx, psEncC->frame_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->frame_length; + } + } + + SKP_Silk_nsq_scale_states( NSQ, x, x_sc_Q10, psEncC->subfr_length, sLTP, + sLTP_Q16, k, LTP_scale_Q14, Gains_Q16, psEncCtrlC->pitchL ); + + SKP_Silk_noise_shape_quantizer( NSQ, psEncCtrlC->sigtype, x_sc_Q10, q, pxq, sLTP_Q16, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder + ); + + x += psEncC->subfr_length; + q += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = psEncCtrlC->pitchL[ NB_SUBFR - 1 ]; + + /* Save quantized speech and noise shaping signals */ + SKP_memcpy( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int16 ) ); + SKP_memcpy( NSQ->sLTP_shp_Q10, &NSQ->sLTP_shp_Q10[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int32 ) ); + +#ifdef USE_UNQUANTIZED_LSFS + DEBUG_STORE_DATA( xq_unq_lsfs.pcm, NSQ->xq, psEncC->frame_length * sizeof( SKP_int16 ) ); +#endif + +} + +/***********************************/ +/* SKP_Silk_noise_shape_quantizer */ +/***********************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_sc_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int shapingLPCOrder, /* I Noise shaping AR filter order */ + SKP_int predictLPCOrder /* I Prediction filter order */ +) +{ + SKP_int i, j; + SKP_int32 LTP_pred_Q14, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14; + SKP_int32 n_LF_Q10, r_Q10, q_Q0, q_Q10; + SKP_int32 thr1_Q10, thr2_Q10, thr3_Q10; + SKP_int32 dither, exc_Q10, LPC_exc_Q10, xq_Q10; + SKP_int32 tmp1, tmp2, sLF_AR_shp_Q10; + SKP_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + shp_lag_ptr = &NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q16[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + + /* Setup short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + /* Quantization thresholds */ + thr1_Q10 = SKP_SUB_RSHIFT32( -1536, Lambda_Q10, 1 ); + thr2_Q10 = SKP_SUB_RSHIFT32( -512, Lambda_Q10, 1 ); + thr2_Q10 = SKP_ADD_RSHIFT32( thr2_Q10, SKP_SMULBB( offset_Q10, Lambda_Q10 ), 10 ); + thr3_Q10 = SKP_ADD_RSHIFT32( 512, Lambda_Q10, 1 ); + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = SKP_RAND( NSQ->rand_seed ); + + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( NSQ->rand_seed, 31 ); + + /* Short-term prediction */ + SKP_assert( ( predictLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* check that array starts at 4-byte aligned address */ + SKP_assert( ( ( SKP_int64 )( ( SKP_int8* )a_Q12 - ( SKP_int8* )0 ) & 3 ) == 0 ); + SKP_assert( predictLPCOrder >= 10 ); /* check that unrolling works */ + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + for( j = 10; j < predictLPCOrder; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], a_Q12[ j ] ); + } + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Noise shape feedback */ + SKP_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + tmp2 = psLPC_Q14[ 0 ]; + tmp1 = NSQ->sAR2_Q14[ 0 ]; + NSQ->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q10 = SKP_SMULWB( tmp2, AR_shp_Q13[ 0 ] ); + for( j = 2; j < shapingLPCOrder; j += 2 ) { + tmp2 = NSQ->sAR2_Q14[ j - 1 ]; + NSQ->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ j - 1 ] ); + tmp1 = NSQ->sAR2_Q14[ j + 0 ]; + NSQ->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp2, AR_shp_Q13[ j ] ); + } + NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q10 = SKP_RSHIFT( n_AR_Q10, 1 ); /* Q11 -> Q10 */ + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, NSQ->sLF_AR_shp_Q12, Tilt_Q14 ); + + n_LF_Q10 = SKP_LSHIFT( SKP_SMULWB( NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ), 2 ); + n_LF_Q10 = SKP_SMLAWT( n_LF_Q10, NSQ->sLF_AR_shp_Q12, LF_shp_Q14 ); + + SKP_assert( lag > 0 || sigtype == SIG_TYPE_UNVOICED ); + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = SKP_SMULWB( SKP_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_LSHIFT( n_LTP_Q14, 6 ); + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + /* Input minus prediction plus noise feedback */ + //r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP; + tmp1 = SKP_SUB32( LTP_pred_Q14, n_LTP_Q14 ); /* Add Q14 stuff */ + tmp1 = SKP_RSHIFT( tmp1, 4 ); /* convert to Q10 */ + tmp1 = SKP_ADD32( tmp1, LPC_pred_Q10 ); /* add Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_AR_Q10 ); /* subtract Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_LF_Q10 ); /* subtract Q10 stuff */ + r_Q10 = SKP_SUB32( x_sc_Q10[ i ], tmp1 ); + + /* Flip sign depending on dither */ + r_Q10 = ( r_Q10 ^ dither ) - dither; + r_Q10 = SKP_SUB32( r_Q10, offset_Q10 ); + r_Q10 = SKP_LIMIT_32( r_Q10, -64 << 10, 64 << 10 ); + + /* Quantize */ + q_Q0 = 0; + q_Q10 = 0; + if( r_Q10 < thr2_Q10 ) { + if( r_Q10 < thr1_Q10 ) { + q_Q0 = SKP_RSHIFT_ROUND( SKP_ADD_RSHIFT32( r_Q10, Lambda_Q10, 1 ), 10 ); + q_Q10 = SKP_LSHIFT( q_Q0, 10 ); + } else { + q_Q0 = -1; + q_Q10 = -1024; + } + } else { + if( r_Q10 > thr3_Q10 ) { + q_Q0 = SKP_RSHIFT_ROUND( SKP_SUB_RSHIFT32( r_Q10, Lambda_Q10, 1 ), 10 ); + q_Q10 = SKP_LSHIFT( q_Q0, 10 ); + } + } + q[ i ] = ( SKP_int8 )q_Q0; /* No saturation needed because max is 64 */ + + /* Excitation */ + exc_Q10 = SKP_ADD32( q_Q10, offset_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = SKP_ADD32( exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( xq_Q10, Gain_Q16 ), 10 ) ); + + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + NSQ->sLF_AR_shp_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx ] = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + sLTP_Q16[ NSQ->sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed += q[ i ]; + } + + /* Update LPC synth buffer */ + SKP_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); +} + +SKP_INLINE void SKP_Silk_nsq_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I input in Q0 */ + SKP_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + SKP_int subfr_length, /* I length of input */ + const SKP_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I subframe number */ + const SKP_int LTP_scale_Q14, /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I */ +) +{ + SKP_int i, lag; + SKP_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q32; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gains_Q16[ subfr ], 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + lag = pitchL[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + SKP_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q16[ i ] = SKP_SMULWB( inv_gain_Q32, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( inv_gain_Q16 != NSQ->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, NSQ->prev_inv_gain_Q16, 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - subfr_length * NB_SUBFR; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q10[ i ] ); + } + + /* Scale long-term prediction state */ + if( NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, sLTP_Q16[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q12 = SKP_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q12 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } + + /* Scale input */ + for( i = 0; i < subfr_length; i++ ) { + x_sc_Q10[ i ] = SKP_RSHIFT( SKP_SMULBB( x[ i ], ( SKP_int16 )inv_gain_Q16 ), 6 ); + } + + /* save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + NSQ->prev_inv_gain_Q16 = inv_gain_Q16; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ_del_dec.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ_del_dec.c new file mode 100755 index 0000000..928187d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_NSQ_del_dec.c @@ -0,0 +1,703 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +typedef struct { + SKP_int32 RandState[ DECISION_DELAY ]; + SKP_int32 Q_Q10[ DECISION_DELAY ]; + SKP_int32 Xq_Q10[ DECISION_DELAY ]; + SKP_int32 Pred_Q16[ DECISION_DELAY ]; + SKP_int32 Shape_Q10[ DECISION_DELAY ]; + SKP_int32 Gain_Q16[ DECISION_DELAY ]; + SKP_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + NSQ_LPC_BUF_LENGTH ]; + SKP_int32 LF_AR_Q12; + SKP_int32 Seed; + SKP_int32 SeedInit; + SKP_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + SKP_int32 Q_Q10; + SKP_int32 RD_Q10; + SKP_int32 xq_Q14; + SKP_int32 LF_AR_Q12; + SKP_int32 sLTP_shp_Q10; + SKP_int32 LPC_exc_Q16; +} NSQ_sample_struct; + +SKP_INLINE void SKP_Silk_copy_del_dec_state( + NSQ_del_dec_struct *DD_dst, /* I Dst del dec state */ + NSQ_del_dec_struct *DD_src, /* I Src del dec state */ + SKP_int LPC_state_idx /* I Index to LPC buffer */ +); + +SKP_INLINE void SKP_Silk_nsq_del_dec_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const SKP_int16 x[], /* I Input in Q0 */ + SKP_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + SKP_int subfr_length, /* I Length of input */ + const SKP_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I Subframe number */ + SKP_int nStatesDelayedDecision, /* I Number of del dec states */ + SKP_int smpl_buf_idx, /* I Index to newest samples in buffers */ + const SKP_int LTP_scale_Q14, /* I LTP state scaling */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I Pitch lag */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer_del_dec( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP filter state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int subfr, /* I Subframe number */ + SKP_int shapingLPCOrder, /* I Shaping LPC filter order */ + SKP_int predictLPCOrder, /* I Prediction filter order */ + SKP_int warping_Q16, /* I */ + SKP_int nStatesDelayedDecision, /* I Number of states in decision tree */ + SKP_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + SKP_int decisionDelay /* I */ +); + +void SKP_Silk_NSQ_del_dec( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Prediction coefs */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I LT prediction coefs */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + SKP_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + SKP_int last_smple_idx, smpl_buf_idx, decisionDelay, subfr_length; + const SKP_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + SKP_int16 *pxq; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 HarmShapeFIRPacked_Q14; + SKP_int offset_Q10; + SKP_int32 FiltState[ MAX_LPC_ORDER ], RDmin_Q10; + SKP_int32 x_sc_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + NSQ_del_dec_struct psDelDec[ MAX_DEL_DEC_STATES ]; + NSQ_del_dec_struct *psDD; + + subfr_length = psEncC->frame_length / NB_SUBFR; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + SKP_assert( NSQ->prev_inv_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + SKP_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psEncCtrlC->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q12 = NSQ->sLF_AR_shp_Q12; + psDD->Shape_Q10[ 0 ] = NSQ->sLTP_shp_Q10[ psEncC->frame_length - 1 ]; + SKP_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + SKP_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrlC->sigtype ][ psEncCtrlC->QuantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = SKP_min_int( DECISION_DELAY, subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + for( k = 0; k < NB_SUBFR; k++ ) { + decisionDelay = SKP_min_int( decisionDelay, psEncCtrlC->pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = SKP_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( LSFInterpFactor_Q2 == ( 1 << 2 ) ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Setup pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->frame_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->frame_length; + NSQ->sLTP_buf_idx = psEncC->frame_length; + subfr = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + SKP_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = SKP_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + lag = psEncCtrlC->pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - SKP_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( SKP_int32_MAX >> 4 ); + SKP_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], + psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q10[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->frame_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psEncC->frame_length - psEncC->predictLPCOrder ); + + SKP_memset( FiltState, 0, psEncC->predictLPCOrder * sizeof( SKP_int32 ) ); + SKP_Silk_MA_Prediction( &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, FiltState, sLTP + start_idx, psEncC->frame_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->sLTP_buf_idx = psEncC->frame_length; + NSQ->rewhite_flag = 1; + } + } + + SKP_Silk_nsq_del_dec_scale_states( NSQ, psDelDec, x, x_sc_Q10, + subfr_length, sLTP, sLTP_Q16, k, psEncC->nStatesDelayedDecision, smpl_buf_idx, + LTP_scale_Q14, Gains_Q16, psEncCtrlC->pitchL ); + + SKP_Silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psEncCtrlC->sigtype, x_sc_Q10, q, pxq, sLTP_Q16, + A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], + Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, + psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x += psEncC->subfr_length; + q += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psEncCtrlC->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q10[ last_smple_idx ]; + sLTP_Q16[ NSQ->sLTP_buf_idx - decisionDelay + i ] = psDD->Pred_Q16[ last_smple_idx ]; + } + SKP_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + SKP_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q12 = psDD->LF_AR_Q12; + NSQ->lagPrev = psEncCtrlC->pitchL[ NB_SUBFR - 1 ]; + + /* Save quantized speech and noise shaping signals */ + SKP_memcpy( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int16 ) ); + SKP_memcpy( NSQ->sLTP_shp_Q10, &NSQ->sLTP_shp_Q10[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int32 ) ); + +#ifdef USE_UNQUANTIZED_LSFS + DEBUG_STORE_DATA( xq_unq_lsfs.pcm, NSQ->xq, psEncC->frame_length * sizeof( SKP_int16 ) ); +#endif + +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer_del_dec( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP filter state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int subfr, /* I Subframe number */ + SKP_int shapingLPCOrder, /* I Shaping LPC filter order */ + SKP_int predictLPCOrder, /* I Prediction filter order */ + SKP_int warping_Q16, /* I */ + SKP_int nStatesDelayedDecision, /* I Number of states in decision tree */ + SKP_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + SKP_int decisionDelay /* I */ +) +{ + SKP_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + SKP_int32 Winner_rand_state; + SKP_int32 LTP_pred_Q14, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14; + SKP_int32 n_LF_Q10, r_Q10, rr_Q20, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + SKP_int32 q1_Q10, q2_Q10, dither, exc_Q10, LPC_exc_Q10, xq_Q10; + SKP_int32 tmp1, tmp2, sLF_AR_shp_Q10; + SKP_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + + shp_lag_ptr = &NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q16[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = SKP_SMULWB( SKP_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_LSHIFT( n_LTP_Q14, 6 ); + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = SKP_RAND( psDD->Seed ); + + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( psDD->Seed, 31 ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + SKP_assert( predictLPCOrder >= 10 ); /* check that unrolling works */ + SKP_assert( ( predictLPCOrder & 1 ) == 0 ); /* check that order is even */ + SKP_assert( ( ( ( int )( ( char* )( a_Q12 ) - ( ( char* ) 0 ) ) ) & 3 ) == 0 ); /* check that array starts at 4-byte aligned address */ + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + for( j = 10; j < predictLPCOrder; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], a_Q12[ j ] ); + } + + /* Noise shape feedback */ + SKP_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = SKP_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q10 = SKP_SMULWB( tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = SKP_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q10 = SKP_RSHIFT( n_AR_Q10, 1 ); /* Q11 -> Q10 */ + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, psDD->LF_AR_Q12, Tilt_Q14 ); + + n_LF_Q10 = SKP_LSHIFT( SKP_SMULWB( psDD->Shape_Q10[ *smpl_buf_idx ], LF_shp_Q14 ), 2 ); + n_LF_Q10 = SKP_SMLAWT( n_LF_Q10, psDD->LF_AR_Q12, LF_shp_Q14 ); + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = SKP_SUB32( LTP_pred_Q14, n_LTP_Q14 ); /* Add Q14 stuff */ + tmp1 = SKP_RSHIFT( tmp1, 4 ); /* convert to Q10 */ + tmp1 = SKP_ADD32( tmp1, LPC_pred_Q10 ); /* add Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_AR_Q10 ); /* subtract Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_LF_Q10 ); /* subtract Q10 stuff */ + r_Q10 = SKP_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + r_Q10 = ( r_Q10 ^ dither ) - dither; + r_Q10 = SKP_SUB32( r_Q10, offset_Q10 ); + r_Q10 = SKP_LIMIT_32( r_Q10, -64 << 10, 64 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + if( r_Q10 < -1536 ) { + q1_Q10 = SKP_LSHIFT( SKP_RSHIFT_ROUND( r_Q10, 10 ), 10 ); + r_Q10 = SKP_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = SKP_RSHIFT( SKP_SMLABB( SKP_MUL( -SKP_ADD32( q1_Q10, offset_Q10 ), Lambda_Q10 ), r_Q10, r_Q10 ), 10 ); + rd2_Q10 = SKP_ADD32( rd1_Q10, 1024 ); + rd2_Q10 = SKP_SUB32( rd2_Q10, SKP_ADD_LSHIFT32( Lambda_Q10, r_Q10, 1 ) ); + q2_Q10 = SKP_ADD32( q1_Q10, 1024 ); + } else if( r_Q10 > 512 ) { + q1_Q10 = SKP_LSHIFT( SKP_RSHIFT_ROUND( r_Q10, 10 ), 10 ); + r_Q10 = SKP_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = SKP_RSHIFT( SKP_SMLABB( SKP_MUL( SKP_ADD32( q1_Q10, offset_Q10 ), Lambda_Q10 ), r_Q10, r_Q10 ), 10 ); + rd2_Q10 = SKP_ADD32( rd1_Q10, 1024 ); + rd2_Q10 = SKP_SUB32( rd2_Q10, SKP_SUB_LSHIFT32( Lambda_Q10, r_Q10, 1 ) ); + q2_Q10 = SKP_SUB32( q1_Q10, 1024 ); + } else { /* r_Q10 >= -1536 && q1_Q10 <= 512 */ + rr_Q20 = SKP_SMULBB( offset_Q10, Lambda_Q10 ); + rd2_Q10 = SKP_RSHIFT( SKP_SMLABB( rr_Q20, r_Q10, r_Q10 ), 10 ); + rd1_Q10 = SKP_ADD32( rd2_Q10, 1024 ); + rd1_Q10 = SKP_ADD32( rd1_Q10, SKP_SUB_RSHIFT32( SKP_ADD_LSHIFT32( Lambda_Q10, r_Q10, 1 ), rr_Q20, 9 ) ); + q1_Q10 = -1024; + q2_Q10 = 0; + } + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q10 = SKP_ADD32( offset_Q10, psSS[ 0 ].Q_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = exc_Q10 + SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Update states */ + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + psSS[ 0 ].sLTP_shp_Q10 = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + psSS[ 0 ].LF_AR_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + psSS[ 0 ].xq_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + psSS[ 0 ].LPC_exc_Q16 = SKP_LSHIFT( LPC_exc_Q10, 6 ); + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q10 = SKP_ADD32( offset_Q10, psSS[ 1 ].Q_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = exc_Q10 + SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Update states */ + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + psSS[ 1 ].sLTP_shp_Q10 = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + psSS[ 1 ].LF_AR_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + psSS[ 1 ].xq_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + psSS[ 1 ].LPC_exc_Q16 = SKP_LSHIFT( LPC_exc_Q10, 6 ); + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = SKP_ADD32( psSampleState[ k ][ 0 ].RD_Q10, ( SKP_int32_MAX >> 4 ) ); + psSampleState[ k ][ 1 ].RD_Q10 = SKP_ADD32( psSampleState[ k ][ 1 ].RD_Q10, ( SKP_int32_MAX >> 4 ) ); + SKP_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + SKP_Silk_copy_del_dec_state( &psDelDec[ RDmax_ind ], &psDelDec[ RDmin_ind ], i ); + SKP_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q10[ last_smple_idx ]; + sLTP_Q16[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q16[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q12 = psSS->LF_AR_Q12; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q10[ *smpl_buf_idx ] = SKP_RSHIFT( psSS->xq_Q14, 4 ); + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q16[ *smpl_buf_idx ] = psSS->LPC_exc_Q16; + psDD->Shape_Q10[ *smpl_buf_idx ] = psSS->sLTP_shp_Q10; + psDD->Seed = SKP_ADD_RSHIFT32( psDD->Seed, psSS->Q_Q10, 10 ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + psDD->Gain_Q16[ *smpl_buf_idx ] = Gain_Q16; + } + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + SKP_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + } +} + +SKP_INLINE void SKP_Silk_nsq_del_dec_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const SKP_int16 x[], /* I Input in Q0 */ + SKP_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + SKP_int subfr_length, /* I Length of input */ + const SKP_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I Subframe number */ + SKP_int nStatesDelayedDecision, /* I Number of del dec states */ + SKP_int smpl_buf_idx, /* I Index to newest samples in buffers */ + const SKP_int LTP_scale_Q14, /* I LTP state scaling */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I Pitch lag */ +) +{ + SKP_int i, k, lag; + SKP_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q32; + NSQ_del_dec_struct *psDD; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gains_Q16[ subfr ], 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + lag = pitchL[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + SKP_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q16[ i ] = SKP_SMULWB( inv_gain_Q32, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( inv_gain_Q16 != NSQ->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, NSQ->prev_inv_gain_Q16, 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - subfr_length * NB_SUBFR; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q10[ i ] ); + } + + /* Scale long-term prediction state */ + if( NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, sLTP_Q16[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q12 = SKP_SMULWW( gain_adj_Q16, psDD->LF_AR_Q12 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->Pred_Q16[ i ] ); + psDD->Shape_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->Shape_Q10[ i ] ); + } + } + } + + /* Scale input */ + for( i = 0; i < subfr_length; i++ ) { + x_sc_Q10[ i ] = SKP_RSHIFT( SKP_SMULBB( x[ i ], ( SKP_int16 )inv_gain_Q16 ), 6 ); + } + + /* save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + NSQ->prev_inv_gain_Q16 = inv_gain_Q16; +} + +SKP_INLINE void SKP_Silk_copy_del_dec_state( + NSQ_del_dec_struct *DD_dst, /* I Dst del dec state */ + NSQ_del_dec_struct *DD_src, /* I Src del dec state */ + SKP_int LPC_state_idx /* I Index to LPC buffer */ +) +{ + SKP_memcpy( DD_dst->RandState, DD_src->RandState, sizeof( DD_src->RandState ) ); + SKP_memcpy( DD_dst->Q_Q10, DD_src->Q_Q10, sizeof( DD_src->Q_Q10 ) ); + SKP_memcpy( DD_dst->Pred_Q16, DD_src->Pred_Q16, sizeof( DD_src->Pred_Q16 ) ); + SKP_memcpy( DD_dst->Shape_Q10, DD_src->Shape_Q10, sizeof( DD_src->Shape_Q10 ) ); + SKP_memcpy( DD_dst->Xq_Q10, DD_src->Xq_Q10, sizeof( DD_src->Xq_Q10 ) ); + SKP_memcpy( DD_dst->sAR2_Q14, DD_src->sAR2_Q14, sizeof( DD_src->sAR2_Q14 ) ); + SKP_memcpy( &DD_dst->sLPC_Q14[ LPC_state_idx ], &DD_src->sLPC_Q14[ LPC_state_idx ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + DD_dst->LF_AR_Q12 = DD_src->LF_AR_Q12; + DD_dst->Seed = DD_src->Seed; + DD_dst->SeedInit = DD_src->SeedInit; + DD_dst->RD_Q10 = DD_src->RD_Q10; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.c new file mode 100755 index 0000000..b2ab5af --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.c @@ -0,0 +1,388 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" + +#define NB_ATT 2 +static const SKP_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const SKP_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const SKP_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +void SKP_Silk_PLC_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = SKP_RSHIFT( psDec->frame_length, 1 ); +} + +void SKP_Silk_PLC( + SKP_Silk_decoder_state *psDec, /* I Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 signal[], /* O Concealed signal */ + SKP_int length, /* I length of residual */ + SKP_int lost /* I Loss flag */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + SKP_Silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + SKP_Silk_PLC_conceal( psDec, psDecCtrl, signal, length ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + SKP_Silk_PLC_update( psDec, psDecCtrl, signal, length ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +void SKP_Silk_PLC_update( + SKP_Silk_decoder_state *psDec, /* (I/O) Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* (I/O) Decoder control */ + SKP_int16 signal[], + SKP_int length +) +{ + SKP_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + SKP_int i, j; + SKP_Silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prev_sigtype = psDecCtrl->sigtype; + LTP_Gain_Q14 = 0; + if( psDecCtrl->sigtype == SIG_TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ NB_SUBFR - 1 ]; j++ ) { + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( NB_SUBFR - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + SKP_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ SKP_SMULBB( NB_SUBFR - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( SKP_int16 ) ); + + psPLC->pitchL_Q8 = SKP_LSHIFT( psDecCtrl->pitchL[ NB_SUBFR - 1 - j ], 8 ); + } + } + +#if USE_SINGLE_TAP + SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( SKP_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; +#endif + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + SKP_int scale_Q10; + SKP_int32 tmp; + + tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + SKP_int scale_Q14; + SKP_int32 tmp; + + tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = SKP_LSHIFT( SKP_SMULBB( psDec->fs_kHz, 18 ), 8 ); + SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( SKP_int16 )); + } + + /* Save LPC coeficients */ + SKP_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( SKP_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save Gains */ + SKP_memcpy( psPLC->prevGain_Q16, psDecCtrl->Gains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); +} + +void SKP_Silk_PLC_conceal( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* O concealed signal */ + SKP_int length /* I length of residual */ +) +{ + SKP_int i, j, k; + SKP_int16 *B_Q14, exc_buf[ MAX_FRAME_LENGTH ], *exc_buf_ptr; + SKP_int16 rand_scale_Q14; + union { + SKP_int16 as_int16[ MAX_LPC_ORDER ]; + SKP_int32 as_int32[ MAX_LPC_ORDER / 2 ]; + } A_Q12_tmp; + SKP_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15; + SKP_int lag, idx, sLTP_buf_idx, shift1, shift2; + SKP_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + SKP_int32 sig_Q10[ MAX_FRAME_LENGTH ], *sig_Q10_ptr, LPC_exc_Q10, LPC_pred_Q10, LTP_pred_Q14; + SKP_Silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + /* Update LTP buffer */ + SKP_memcpy( psDec->sLTP_Q16, &psDec->sLTP_Q16[ psDec->frame_length ], psDec->frame_length * sizeof( SKP_int32 ) ); + + /* LPC concealment. Apply BWE to previous LPC */ + SKP_Silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, BWE_COEF_Q16 ); + + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = ( NB_SUBFR >> 1 ); k < NB_SUBFR; k++ ) { + for( i = 0; i < psDec->subfr_length; i++ ) { + exc_buf_ptr[ i ] = ( SKP_int16 )SKP_RSHIFT( + SKP_SMULWW( psDec->exc_Q10[ i + k * psDec->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 ); + } + exc_buf_ptr += psDec->subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + SKP_Silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psDec->subfr_length ); + SKP_Silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psDec->subfr_length ], psDec->subfr_length ); + + if( SKP_RSHIFT( energy1, shift2 ) < SKP_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, 3 * psDec->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, psDec->frame_length - RAND_BUF_SIZE ) ]; + } + + /* Setup Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Setup attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = (1 << 14 ); + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = SKP_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = ( SKP_int16 )SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } + + /* Reduce random noise for unvoiced frames with high LPC gain */ + if( psDec->prev_sigtype == SIG_TYPE_UNVOICED ) { + SKP_int32 invGain_Q30, down_scale_Q30; + + SKP_Silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order ); + + down_scale_Q30 = SKP_min_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = SKP_max_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = SKP_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = SKP_RSHIFT( SKP_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->frame_length; + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + sig_Q10_ptr = sig_Q10; + for( k = 0; k < NB_SUBFR; k++ ) { + /* Setup pointer */ + pred_lag_ptr = &psDec->sLTP_Q16[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + rand_seed = SKP_RAND( rand_seed ); + idx = SKP_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC residual */ + LPC_exc_Q10 = SKP_LSHIFT( SKP_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 2 ); /* Random noise part */ + LPC_exc_Q10 = SKP_ADD32( LPC_exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); /* Harmonic part */ + + /* Update states */ + psDec->sLTP_Q16[ sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 ); + sLTP_buf_idx++; + + /* Save LPC residual */ + sig_Q10_ptr[ i ] = LPC_exc_Q10; + } + sig_Q10_ptr += psDec->subfr_length; + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = SKP_RSHIFT( SKP_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 += SKP_SMULWB( psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = SKP_min_32( psPLC->pitchL_Q8, SKP_LSHIFT( SKP_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sig_Q10_ptr = sig_Q10; + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( A_Q12_tmp.as_int16, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( SKP_int16 ) ); + SKP_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( k = 0; k < NB_SUBFR; k++ ) { + for( i = 0; i < psDec->subfr_length; i++ ){ + /* partly unrolled */ + LPC_pred_Q10 = SKP_SMULWB( psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp.as_int16[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp.as_int16[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp.as_int16[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp.as_int16[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp.as_int16[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp.as_int16[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp.as_int16[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp.as_int16[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp.as_int16[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp.as_int16[ 9 ] ); + + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - j - 1 ], A_Q12_tmp.as_int16[ j ] ); + } + /* Add prediction to LPC residual */ + sig_Q10_ptr[ i ] = SKP_ADD32( sig_Q10_ptr[ i ], LPC_pred_Q10 ); + + /* Update states */ + psDec->sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT( sig_Q10_ptr[ i ], 4 ); + } + sig_Q10_ptr += psDec->subfr_length; + /* Update LPC filter state */ + SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + } + + /* Scale with Gain */ + for( i = 0; i < psDec->frame_length; i++ ) { + signal[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( sig_Q10[ i ], psPLC->prevGain_Q16[ NB_SUBFR - 1 ] ), 10 ) ); + } + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } +} + +/* Glues concealed frames with new good recieved frames */ +void SKP_Silk_PLC_glue_frames( + SKP_Silk_decoder_state *psDec, /* I/O decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length /* I length of residual */ +) +{ + SKP_int i, energy_shift; + SKP_int32 energy; + SKP_Silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + SKP_Silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, signal, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + SKP_Silk_sum_sqr_shift( &energy, &energy_shift, signal, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = SKP_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = SKP_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + SKP_int32 frac_Q24, LZ; + SKP_int32 gain_Q12, slope_Q12; + + LZ = SKP_Silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = SKP_LSHIFT( psPLC->conc_energy, LZ ); + energy = SKP_RSHIFT( energy, SKP_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = SKP_DIV32( psPLC->conc_energy, SKP_max( energy, 1 ) ); + + gain_Q12 = SKP_Silk_SQRT_APPROX( frac_Q24 ); + slope_Q12 = SKP_DIV32_16( ( 1 << 12 ) - gain_Q12, length ); + + for( i = 0; i < length; i++ ) { + signal[ i ] = SKP_RSHIFT( SKP_MUL( gain_Q12, signal[ i ] ), 12 ); + gain_Q12 += slope_Q12; + gain_Q12 = SKP_min( gain_Q12, ( 1 << 12 ) ); + } + } + } + psPLC->last_frame_lost = 0; + + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.h new file mode 100755 index 0000000..027fcda --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_PLC.h @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_PLC_FIX_H +#define SKP_SILK_PLC_FIX_H + +#include "SKP_Silk_main.h" + +#define BWE_COEF_Q16 64880 /* 0.99 in Q16 */ +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define SA_THRES_Q8 50 +#define USE_SINGLE_TAP 1 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK (RAND_BUF_SIZE - 1) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void SKP_Silk_PLC_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +); + +void SKP_Silk_PLC( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length, /* I length of residual */ + SKP_int lost /* I Loss flag */ +); + +void SKP_Silk_PLC_update( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], + SKP_int length +); + +void SKP_Silk_PLC_conceal( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* O LPC residual signal */ + SKP_int length /* I length of signal */ +); + +void SKP_Silk_PLC_glue_frames( + SKP_Silk_decoder_state *psDec, /* I/O decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length /* I length of signal */ +); + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FIX.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FIX.h new file mode 100755 index 0000000..3f89f82 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FIX.h @@ -0,0 +1,636 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef _SKP_SILK_SIGPROC_FIX_H_ +#define _SKP_SILK_SIGPROC_FIX_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SKP_Silk_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */ +#define SKP_Silk_MAX_CORRELATION_LENGTH 640 /* max input length to the correlation */ +#include "SKP_Silk_typedef.h" +#include +#include /* for abs() */ +#include "SKP_Silk_resampler_structs.h" + +# include "SKP_Silk_macros.h" + + + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +SKP_int SKP_Silk_resampler_init( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int32 Fs_Hz_in, /* I: Input sampling rate (Hz) */ + SKP_int32 Fs_Hz_out /* I: Output sampling rate (Hz) */ +); + + +/*! + * Clear the states of all resampling filters, without resetting sampling rate ratio + */ +SKP_int SKP_Silk_resampler_clear( + SKP_Silk_resampler_state_struct *S /* I/O: Resampler state */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +SKP_int SKP_Silk_resampler( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + Upsample 2x, low quality + */ +void SKP_Silk_resampler_up2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void SKP_Silk_resampler_down2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ len ] */ + const SKP_int16 *in, /* I: Input signal [ floor(len/2) ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + + +/*! + * Downsample by a factor 2/3, low quality +*/ +void SKP_Silk_resampler_down2_3( + SKP_int32 *S, /* I/O: State vector [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ floor(2*inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + * Downsample by a factor 3, low quality +*/ +void SKP_Silk_resampler_down3( + SKP_int32 *S, /* I/O: State vector [ 8 ] */ + SKP_int16 *out, /* O: Output signal [ floor(inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + * second order ARMA filter + * can handle (slowly) varying coefficients + */ +void SKP_Silk_biquad( + const SKP_int16 *in, /* I: input signal */ + const SKP_int16 *B, /* I: MA coefficients, Q13 [3] */ + const SKP_int16 *A, /* I: AR coefficients, Q13 [2] */ + SKP_int32 *S, /* I/O: state vector [2] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length */ +); +/*! + * Second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void SKP_Silk_biquad_alt( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int32 *B_Q28, /* I: MA coefficients [3] */ + const SKP_int32 *A_Q28, /* I: AR coefficients [2] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len /* I: Signal length (must be even) */ +); + +/*! + * variable order MA filter. Prediction error filter implementation. Coeficients negated and starting with coef to x[n - 1] + */ +void SKP_Silk_MA_Prediction( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int32 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 order /* I: Filter order */ +); + +/*! + * 16th order AR filter for LPC synthesis, coefficients are in Q12 + */ +void SKP_Silk_LPC_synthesis_order16( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [16], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [16] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length, must be multiple of 16 */ +); + +/* variable order MA prediction error filter. */ +/* Inverse filter of SKP_Silk_LPC_synthesis_filter */ +void SKP_Silk_LPC_analysis_filter( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int16 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 Order /* I: Filter order */ +); + +/* even order AR filter */ +void SKP_Silk_LPC_synthesis_filter( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [Order], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [Order] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len, /* I: signal length */ + const SKP_int Order /* I: filter order, must be even */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander( + SKP_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander_32( + SKP_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +SKP_int SKP_Silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int16 *A_Q12, /* I: Prediction coefficients, Q12 [order] */ + const SKP_int order /* I: Prediction order */ +); + +SKP_int SKP_Silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int32 *A_Q24, /* I: Prediction coefficients, Q24 [order] */ + const SKP_int order /* I: Prediction order */ +); + +/* split signal in two decimated bands using first-order allpass filters */ +void SKP_Silk_ana_filt_bank_1( + const SKP_int16 *in, /* I: Input signal [N] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *outL, /* O: Low band [N/2] */ + SKP_int16 *outH, /* O: High band [N/2] */ + SKP_int32 *scratch, /* I: Scratch memory [3*N/2] */ + const SKP_int32 N /* I: Number of input samples */ +); + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (very close inverse of approx 2^() below) */ +/* Convert input to a log scale */ +SKP_int32 SKP_Silk_lin2log(const SKP_int32 inLin); /* I: Input in linear scale */ + +/* Approximation of a sigmoid function */ +SKP_int SKP_Silk_sigm_Q15(SKP_int in_Q5); + +/* approximation of 2^() (exact inverse of approx log2() above) */ +/* convert input to a linear scale */ +SKP_int32 SKP_Silk_log2lin(const SKP_int32 inLog_Q7); /* I: input on log scale */ + +/* Function that returns the maximum absolut value of the input vector */ +SKP_int16 SKP_Silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const SKP_int16 *vec, /* I Input vector [len] */ + const SKP_int32 len /* I Length of input vector */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void SKP_Silk_sum_sqr_shift( + SKP_int32 *energy, /* O Energy of x, after shifting to the right */ + SKP_int *shift, /* O Number of bits right shift applied to energy */ + const SKP_int16 *x, /* I Input vector */ + SKP_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* Uses SMLAWB(), requiring armv5E and higher. */ +SKP_int32 SKP_Silk_schur( /* O: Returns residual energy */ + SKP_int16 *rc_Q15, /* O: reflection coefficients [order] Q15 */ + const SKP_int32 *c, /* I: correlations [order+1] */ + const SKP_int32 order /* I: prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +SKP_int32 SKP_Silk_schur64( /* O: returns residual energy */ + SKP_int32 rc_Q16[], /* O: Reflection coefficients [order] Q16 */ + const SKP_int32 c[], /* I: Correlations [order+1] */ + SKP_int32 order /* I: Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int16 *rc_Q15, /* I: Reflection coefficients [order] Q15 */ + const SKP_int32 order /* I: Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a_Q16( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int32 *rc_Q16, /* I: Reflection coefficients [order] Q16 */ + const SKP_int32 order /* I: Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +void SKP_Silk_apply_sine_window( + SKP_int16 px_win[], /* O Pointer to windowed signal */ + const SKP_int16 px[], /* I Pointer to input signal */ + const SKP_int win_type, /* I Selects a window type */ + const SKP_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void SKP_Silk_autocorr( + SKP_int32 *results, /* O Result (length correlationCount) */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *inputData, /* I Input data to correlate */ + const SKP_int inputDataSize, /* I Length of input */ + const SKP_int correlationCount /* I Number of correlation taps to compute */ +); + +/* Pitch estimator */ +#define SKP_Silk_PITCH_EST_MIN_COMPLEX 0 +#define SKP_Silk_PITCH_EST_MID_COMPLEX 1 +#define SKP_Silk_PITCH_EST_MAX_COMPLEX 2 + +void SKP_Silk_decode_pitch( + SKP_int lagIndex, /* I */ + SKP_int contourIndex, /* O */ + SKP_int pitch_lags[], /* O 4 pitch values */ + SKP_int Fs_kHz /* I sampling frequency (kHz) */ +); + +SKP_int SKP_Silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const SKP_int16 *signal, /* I Signal of length PITCH_EST_FRAME_LENGTH_MS*Fs_kHz */ + SKP_int *pitch_out, /* O 4 pitch lag values */ + SKP_int *lagIndex, /* O Lag Index */ + SKP_int *contourIndex, /* O Pitch contour Index */ + SKP_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + SKP_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const SKP_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const SKP_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const SKP_int Fs_kHz, /* I Sample frequency (kHz) */ + const SKP_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const SKP_int forLJC /* I 1 if this function is called from LJC code, 0 otherwise. */ +); + +/* parameter defining the size and accuracy of the piecewise linear */ +/* cosine approximatin table. */ + +#define LSF_COS_TAB_SZ_FIX 128 +/* rom table with cosine values */ +extern const SKP_int SKP_Silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void SKP_Silk_A2NLSF( + SKP_int *NLSF, /* O Normalized Line Spectral Frequencies, Q15 (0 - (2^15-1)), [d] */ + SKP_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const SKP_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void SKP_Silk_NLSF2A( + SKP_int16 *a, /* o monic whitening filter coefficients in Q12, [d] */ + const SKP_int *NLSF, /* i normalized line spectral frequencies in Q15, [d] */ + const SKP_int d /* i filter order (should be even) */ +); + +void SKP_Silk_insertion_sort_increasing( + SKP_int32 *a, /* I/O Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +void SKP_Silk_insertion_sort_decreasing_int16( + SKP_int16 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +void SKP_Silk_insertion_sort_increasing_all_values( + SKP_int *a, /* I/O: Unsorted / Sorted vector */ + const SKP_int L /* I: Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize( + SKP_int *NLSF_Q15, /* I/O: Unstable/stabilized normalized LSF vector in Q15 [L] */ + const SKP_int *NDeltaMin_Q15, /* I: Normalized delta min vector in Q15, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const SKP_int L /* I: Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void SKP_Silk_NLSF_VQ_weights_laroia( + SKP_int *pNLSFW_Q6, /* O: Pointer to input vector weights [D x 1] */ + const SKP_int *pNLSF_Q15, /* I: Pointer to input vector [D x 1] */ + const SKP_int D /* I: Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void SKP_Silk_burg_modified( + SKP_int32 *res_nrg, /* O residual energy */ + SKP_int *res_nrgQ, /* O residual energy Q value */ + SKP_int32 A_Q16[], /* O prediction coefficients (length order) */ + const SKP_int16 x[], /* I input signal, length: nb_subfr * ( D + subfr_length ) */ + const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ + const SKP_int nb_subfr, /* I number of subframes stacked in x */ + const SKP_int32 WhiteNoiseFrac_Q32, /* I fraction added to zero-lag autocorrelation */ + const SKP_int D /* I order */ +); + +/* Copy and multiply a vector by a constant */ +void SKP_Silk_scale_copy_vector16( + SKP_int16 *data_out, + const SKP_int16 *data_in, + SKP_int32 gain_Q16, /* I: gain in Q16 */ + const SKP_int dataSize /* I: length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void SKP_Silk_scale_vector32_Q26_lshift_18( + SKP_int32 *data1, /* I/O: Q0/Q18 */ + SKP_int32 gain_Q26, /* I: Q26 */ + SKP_int dataSize /* I: length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum(inVec1[i]*inVec2[i]) */ +/* inVec1 and inVec2 should be increasing ordered, and starting address should be 4 byte aligned. (a factor of 4)*/ +SKP_int32 SKP_Silk_inner_prod_aligned( + const SKP_int16* const inVec1, /* I input vector 1 */ + const SKP_int16* const inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +); + +SKP_int64 SKP_Silk_inner_prod16_aligned_64( + const SKP_int16 *inVec1, /* I input vector 1 */ + const SKP_int16 *inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +); +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expressions below and + compile them into 'ror' instructions if available. No need for inline ASM! */ +#if defined(EMBEDDED_MIPS) +/* For MIPS (and most likely for ARM! and >=i486) we don't have to handle + negative rot's as only 5 bits of rot are encoded into ROR instructions. */ +SKP_INLINE SKP_int32 SKP_ROR32(SKP_int32 a32, SKP_int rot) +{ + SKP_uint32 _x = (SKP_uint32) a32; + SKP_uint32 _r = (SKP_uint32) rot; + return (SKP_int32) ((_x << (32 - _r)) | (_x >> _r)); +} +#else +/* PPC must use this generic implementation. */ +SKP_INLINE SKP_int32 SKP_ROR32( SKP_int32 a32, SKP_int rot ) +{ + SKP_uint32 x = (SKP_uint32) a32; + SKP_uint32 r = (SKP_uint32) rot; + SKP_uint32 m = (SKP_uint32) -rot; + if(rot <= 0) + return (SKP_int32) ((x << m) | (x >> (32 - m))); + else + return (SKP_int32) ((x << (32 - r)) | (x >> r)); +} +#endif + +/* Allocate SKP_int16 alligned to 4-byte memory address */ +#if EMBEDDED_ARM +#if defined(_WIN32) && defined(_M_ARM) +#define SKP_DWORD_ALIGN __declspec(align(4)) +#else +#define SKP_DWORD_ALIGN __attribute__((aligned(4))) +#endif +#else +#define SKP_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define SKP_memcpy(a, b, c) memcpy((a), (b), (c)) /* Dest, Src, ByteCount */ +#define SKP_memset(a, b, c) memset((a), (b), (c)) /* Dest, value, ByteCount */ +#define SKP_memmove(a, b, c) memmove((a), (b), (c)) /* Dest, Src, ByteCount */ +/* fixed point macros */ + +// (a32 * b32) output have to be 32bit int +#define SKP_MUL(a32, b32) ((a32) * (b32)) + +// (a32 * b32) output have to be 32bit uint +#define SKP_MUL_uint(a32, b32) SKP_MUL(a32, b32) + +// a32 + (b32 * c32) output have to be 32bit int +#define SKP_MLA(a32, b32, c32) SKP_ADD32((a32),((b32) * (c32))) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define SKP_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define SKP_SMLATT(a32, b32, c32) SKP_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define SKP_SMLALBB(a64, b16, c16) SKP_ADD64((a64),(SKP_int64)((SKP_int32)(b16) * (SKP_int32)(c16))) + +// (a32 * b32) +#define SKP_SMULL(a32, b32) ((SKP_int64)(a32) * /*(SKP_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define SKP_ADD32_ovflw(a, b) ((SKP_int32)((SKP_uint32)(a) + (SKP_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define SKP_SUB32_ovflw(a, b) ((SKP_int32)((SKP_uint32)(a) - (SKP_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define SKP_MLA_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), (SKP_uint32)(b32) * (SKP_uint32)(c32)) +#ifndef SKP_SMLABB_ovflw + #define SKP_SMLABB_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULBB((b32),(c32))) +#endif +#define SKP_SMLATT_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULTT((b32),(c32))) +#define SKP_SMLAWB_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULWB((b32),(c32))) +#define SKP_SMLAWT_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULWT((b32),(c32))) +#define SKP_DIV32_16(a32, b16) ((SKP_int32)((a32) / (b16))) +#define SKP_DIV32(a32, b32) ((SKP_int32)((a32) / (b32))) + +#define SKP_ADD32(a, b) ((a) + (b)) +#define SKP_ADD64(a, b) ((a) + (b)) + +#define SKP_SUB32(a, b) ((a) - (b)) + +#define SKP_SAT16(a) ((a) > SKP_int16_MAX ? SKP_int16_MAX : \ + ((a) < SKP_int16_MIN ? SKP_int16_MIN : (a))) +#define SKP_SAT32(a) ((a) > SKP_int32_MAX ? SKP_int32_MAX : \ + ((a) < SKP_int32_MIN ? SKP_int32_MIN : (a))) + +#define SKP_CHECK_FIT16(a) (a) +#define SKP_CHECK_FIT32(a) (a) + +#define SKP_ADD_SAT16(a, b) (SKP_int16)SKP_SAT16( SKP_ADD32( (SKP_int32)(a), (b) ) ) + +/* Add with saturation for positive input values */ +#define SKP_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? SKP_int32_MAX : ((a)+(b))) + +#define SKP_LSHIFT32(a, shift) ((a)<<(shift)) // shift >= 0, shift < 32 +#define SKP_LSHIFT64(a, shift) ((a)<<(shift)) // shift >= 0, shift < 64 +#define SKP_LSHIFT(a, shift) SKP_LSHIFT32(a, shift) // shift >= 0, shift < 32 + +#define SKP_RSHIFT32(a, shift) ((a)>>(shift)) // shift >= 0, shift < 32 +#define SKP_RSHIFT64(a, shift) ((a)>>(shift)) // shift >= 0, shift < 64 +#define SKP_RSHIFT(a, shift) SKP_RSHIFT32(a, shift) // shift >= 0, shift < 32 + +/* saturates before shifting */ +#define SKP_LSHIFT_SAT32(a, shift) (SKP_LSHIFT32( SKP_LIMIT_32( (a), SKP_RSHIFT32( SKP_int32_MIN, (shift) ), \ + SKP_RSHIFT32( SKP_int32_MAX, (shift) ) ), (shift) )) + +#define SKP_LSHIFT_ovflw(a, shift) ((a)<<(shift)) // shift >= 0, allowed to overflow +#define SKP_LSHIFT_uint(a, shift) ((a)<<(shift)) // shift >= 0 +#define SKP_RSHIFT_uint(a, shift) ((a)>>(shift)) // shift >= 0 + +#define SKP_ADD_LSHIFT(a, b, shift) ((a) + SKP_LSHIFT((b), (shift))) // shift >= 0 +#define SKP_ADD_LSHIFT32(a, b, shift) SKP_ADD32((a), SKP_LSHIFT32((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT(a, b, shift) ((a) + SKP_RSHIFT((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT32(a, b, shift) SKP_ADD32((a), SKP_RSHIFT32((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT_uint(a, b, shift) ((a) + SKP_RSHIFT_uint((b), (shift))) // shift >= 0 +#define SKP_SUB_LSHIFT32(a, b, shift) SKP_SUB32((a), SKP_LSHIFT32((b), (shift))) // shift >= 0 +#define SKP_SUB_RSHIFT32(a, b, shift) SKP_SUB32((a), SKP_RSHIFT32((b), (shift))) // shift >= 0 + +/* Requires that shift > 0 */ +#define SKP_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define SKP_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define SKP_NSHIFT_MUL_32_32(a, b) ( -(31- (32-SKP_Silk_CLZ32(SKP_abs(a)) + (32-SKP_Silk_CLZ32(SKP_abs(b))))) ) + +#define SKP_min(a, b) (((a) < (b)) ? (a) : (b)) +#define SKP_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SKP_FIX_CONST( C, Q ) ((SKP_int32)((C) * ((SKP_int64)1 << (Q)) + 0.5)) + +/* SKP_min() versions with typecast in the function call */ +SKP_INLINE SKP_int SKP_min_int(SKP_int a, SKP_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +SKP_INLINE SKP_int32 SKP_min_32(SKP_int32 a, SKP_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* SKP_min() versions with typecast in the function call */ +SKP_INLINE SKP_int SKP_max_int(SKP_int a, SKP_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +SKP_INLINE SKP_int16 SKP_max_16(SKP_int16 a, SKP_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +SKP_INLINE SKP_int32 SKP_max_32(SKP_int32 a, SKP_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define SKP_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define SKP_LIMIT_int SKP_LIMIT +#define SKP_LIMIT_32 SKP_LIMIT + +//#define SKP_non_neg(a) ((a) & ((-(a)) >> (8 * sizeof(a) - 1))) /* doesn't seem faster than SKP_max(0, a); + +#define SKP_abs(a) (((a) > 0) ? (a) : -(a)) // Be careful, SKP_abs returns wrong when input equals to SKP_intXX_MIN +#define SKP_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. Do not just mask off */ +/* the lowest bits. */ +#define SKP_RAND(seed) (SKP_MLA_ovflw(907633515, (seed), 196314165)) + +// Add some multiplication functions that can be easily mapped to ARM. + +// SKP_SMMUL: Signed top word multiply. +// ARMv6 2 instruction cycles. +// ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM) +//#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT(SKP_SMLAL(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)), 16) +// the following seems faster on x86 +//#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + +#include "SKP_Silk_Inlines.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FLP.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FLP.h new file mode 100755 index 0000000..b972e5b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_SigProc_FLP.h @@ -0,0 +1,254 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#ifndef _SKP_SILK_SIGPROC_FLP_H_ +#define _SKP_SILK_SIGPROC_FLP_H_ + +#include "SKP_Silk_SigProc_FIX.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* first-order allpass filter */ +void SKP_Silk_allpass_int_FLP( + const SKP_float *in, /* I: input signal [len] */ + SKP_float *S, /* I/O: state [1] */ + SKP_float A, /* I: coefficient (0 <= A < 1) */ + SKP_float *out, /* O: output signal [len] */ + const SKP_int32 len /* I: number of samples */ +); + +/* downsample by a factor 2, coarser */ +void SKP_Silk_decimate2_coarse_FLP( + const SKP_float *in, /* I: signal [2*len] */ + SKP_float *S, /* I/O: state vector [2] */ + SKP_float *out, /* O: decimated signal [len] */ + SKP_float *scratch, /* I: scratch memory [3*len] */ + const SKP_int32 len /* I: number of OUTPUT samples */ +); + +/* downsample by a factor 2, coarsest */ +void SKP_Silk_decimate2_coarsest_FLP( + const SKP_float *in, /* I: signal [2*len] */ + SKP_float *S, /* I/O: state vector [2] */ + SKP_float *out, /* O: decimated signal [len] */ + SKP_float *scratch, /* I: scratch memory [3*len] */ + const SKP_int32 len /* I: number of OUTPUT samples */ +); + +/* Chirp (bw expand) LP AR filter */ +void SKP_Silk_bwexpander_FLP( + SKP_float *ar, /* io AR filter to be expanded (without leading 1) */ + const SKP_int d, /* i length of ar */ + const SKP_float chirp /* i chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on SKP_Silk_FLP_a2k() */ +SKP_int SKP_Silk_LPC_inverse_pred_gain_FLP( /* O: returns 1 if unstable, otherwise 0 */ + SKP_float *invGain, /* O: inverse prediction gain, energy domain */ + const SKP_float *A, /* I: prediction coefficients [order] */ + SKP_int32 order /* I: prediction order */ +); + +SKP_float SKP_Silk_schur_FLP( /* O returns residual energy */ + SKP_float refl_coef[], /* O reflection coefficients (length order) */ + const SKP_float auto_corr[], /* I autotcorrelation sequence (length order+1) */ + SKP_int order /* I order */ +); + +void SKP_Silk_k2a_FLP( + SKP_float *A, /* O: prediction coefficients [order] */ + const SKP_float *rc, /* I: reflection coefficients [order] */ + SKP_int32 order /* I: prediction order */ +); + +/* Solve the normal equations using the Levinson-Durbin recursion */ +SKP_float SKP_Silk_levinsondurbin_FLP( /* O prediction error energy */ + SKP_float A[], /* O prediction coefficients [order] */ + const SKP_float corr[], /* I input auto-correlations [order + 1] */ + const SKP_int order /* I prediction order */ +); + +/* compute autocorrelation */ +void SKP_Silk_autocorrelation_FLP( + SKP_float *results, /* o result (length correlationCount) */ + const SKP_float *inputData, /* i input data to correlate */ + SKP_int inputDataSize, /* i length of input */ + SKP_int correlationCount /* i number of correlation taps to compute */ +); + +/* Pitch estimator */ +#define SigProc_PITCH_EST_MIN_COMPLEX 0 +#define SigProc_PITCH_EST_MID_COMPLEX 1 +#define SigProc_PITCH_EST_MAX_COMPLEX 2 + +SKP_int SKP_Silk_pitch_analysis_core_FLP( /* O voicing estimate: 0 voiced, 1 unvoiced */ + const SKP_float *signal, /* I signal of length PITCH_EST_FRAME_LENGTH_MS*Fs_kHz */ + SKP_int *pitch_out, /* O 4 pitch lag values */ + SKP_int *lagIndex, /* O lag Index */ + SKP_int *contourIndex, /* O pitch contour Index */ + SKP_float *LTPCorr, /* I/O normalized correlation; input: value from previous frame */ + SKP_int prevLag, /* I last lag of previous frame; set to zero is unvoiced */ + const SKP_float search_thres1, /* I first stage threshold for lag candidates 0 - 1 */ + const SKP_float search_thres2, /* I final threshold for lag candidates 0 - 1 */ + const SKP_int Fs_kHz, /* I sample frequency (kHz) */ + const SKP_int complexity /* I Complexity setting, 0-2, where 2 is highest */ +); + +#define PI (3.1415926536f) + +void SKP_Silk_insertion_sort_decreasing_FLP( + SKP_float *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +void SKP_Silk_insertion_sort_increasing_FLP( + SKP_float *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +/* Laroia low complexity NLSF weights */ +void SKP_Silk_NLSF_VQ_weights_laroia_FLP( + SKP_float *pXW, /* 0: Pointer to input vector weights [D x 1] */ + const SKP_float *pX, /* I: Pointer to input vector [D x 1] */ + const SKP_int D /* I: Input vector dimension */ +); + +/* Compute reflection coefficients from input signal */ +SKP_float SKP_Silk_burg_modified_FLP( /* O returns residual energy */ + SKP_float A[], /* O prediction coefficients (length order) */ + const SKP_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ + const SKP_int nb_subfr, /* I number of subframes stacked in x */ + const SKP_float WhiteNoiseFrac, /* I fraction added to zero-lag autocorrelation */ + const SKP_int D /* I order */ +); + +/* multiply a vector by a constant */ +void SKP_Silk_scale_vector_FLP( + SKP_float *data1, + SKP_float gain, + SKP_int dataSize +); + +/* copy and multiply a vector by a constant */ +void SKP_Silk_scale_copy_vector_FLP( + SKP_float *data_out, + const SKP_float *data_in, + SKP_float gain, + SKP_int dataSize +); + +/* inner product of two SKP_float arrays, with result as double */ +double SKP_Silk_inner_product_FLP( + const SKP_float *data1, + const SKP_float *data2, + SKP_int dataSize +); + +/* sum of squares of a SKP_float array, with result as double */ +double SKP_Silk_energy_FLP( + const SKP_float *data, + SKP_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define SKP_min_float(a, b) (((a) < (b)) ? (a) : (b)) +#define SKP_max_float(a, b) (((a) > (b)) ? (a) : (b)) +#define SKP_abs_float(a) ((SKP_float)fabs(a)) + +#define SKP_LIMIT_float( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +/* sigmoid function */ +SKP_INLINE SKP_float SKP_sigmoid(SKP_float x) +{ + return (SKP_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +SKP_INLINE void SKP_float2short_array( + SKP_int16 *out, + const SKP_float *in, + SKP_int32 length +) +{ + SKP_int32 k; + for (k = length-1; k >= 0; k--) { +#if defined( _WIN32 ) && !defined( _WIN64 ) + double t = in[k] + 6755399441055744.0; + out[k] = (SKP_int16)SKP_SAT16(*(( SKP_int32 * )( &t ))); +#else + double x = in[k]; + out[k] = (SKP_int16)SKP_SAT16( ( x > 0 ) ? x + 0.5 : x - 0.5 ); +#endif + } +} + +/* floating-point to integer conversion (rounding) */ +SKP_INLINE SKP_int32 SKP_float2int(double x) +{ + return (SKP_int32)( ( x > 0 ) ? x + 0.5 : x - 0.5 ); +} + +/* integer to floating-point conversion */ +SKP_INLINE void SKP_short2float_array( + SKP_float *out, + const SKP_int16 *in, + SKP_int32 length +) +{ + SKP_int32 k; + for (k = length-1; k >= 0; k--) { + out[k] = (SKP_float)in[k]; + } +} + +#define SKP_round(x) (SKP_float)((x)>=0 ? (SKP_int64)((x)+0.5) : (SKP_int64)((x)-0.5)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VAD.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VAD.c new file mode 100755 index 0000000..d4ecebb --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VAD.c @@ -0,0 +1,320 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + * File Name: SKP_Silk_VAD.c + * Description: Silk VAD. + */ + +#include +#include "SKP_Silk_main.h" + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +SKP_int SKP_Silk_VAD_Init( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + SKP_int b, ret = 0; + + /* reset state memory */ + SKP_memset( psSilk_VAD, 0, sizeof( SKP_Silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = SKP_max_32( SKP_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = SKP_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = SKP_DIV32( SKP_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +const static SKP_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +SKP_int SKP_Silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD, /* I/O Silk VAD state */ + SKP_int *pSA_Q8, /* O Speech activity level in Q8 */ + SKP_int *pSNR_dB_Q7, /* O SNR for current frame in Q7 */ + SKP_int pQuality_Q15[ VAD_N_BANDS ], /* O Smoothed SNR for each band */ + SKP_int *pTilt_Q15, /* O current frame's frequency tilt */ + const SKP_int16 pIn[], /* I PCM input [framelength] */ + const SKP_int framelength /* I Input frame length */ +) +{ + SKP_int SA_Q15, input_tilt; + SKP_int32 scratch[ 3 * MAX_FRAME_LENGTH / 2 ]; + SKP_int decimated_framelength, dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + SKP_int32 sumSquared, smooth_coef_Q16; + SKP_int16 HPstateTmp; + + SKP_int16 X[ VAD_N_BANDS ][ MAX_FRAME_LENGTH / 2 ]; + SKP_int32 Xnrg[ VAD_N_BANDS ]; + SKP_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + SKP_int32 speech_nrg, x_tmp; + SKP_int ret = 0; + + /* Safety checks */ + SKP_assert( VAD_N_BANDS == 4 ); + SKP_assert( MAX_FRAME_LENGTH >= framelength ); + SKP_assert( framelength <= 512 ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + SKP_Silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], &X[ 0 ][ 0 ], &X[ 3 ][ 0 ], &scratch[ 0 ], framelength ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + SKP_Silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState1[ 0 ], &X[ 0 ][ 0 ], &X[ 2 ][ 0 ], &scratch[ 0 ], SKP_RSHIFT( framelength, 1 ) ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + SKP_Silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState2[ 0 ], &X[ 0 ][ 0 ], &X[ 1 ][ 0 ], &scratch[ 0 ], SKP_RSHIFT( framelength, 2 ) ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + decimated_framelength = SKP_RSHIFT( framelength, 3 ); + X[ 0 ][ decimated_framelength - 1 ] = SKP_RSHIFT( X[ 0 ][ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ 0 ][ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ 0 ][ i - 1 ] = SKP_RSHIFT( X[ 0 ][ i - 1 ], 1 ); + X[ 0 ][ i ] -= X[ 0 ][ i - 1 ]; + } + X[ 0 ][ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = SKP_RSHIFT( framelength, SKP_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = SKP_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( SKP_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = SKP_RSHIFT( X[ b ][ i + dec_subframe_offset ], 3 ); + sumSquared = SKP_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + SKP_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = SKP_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = SKP_ADD_POS_SAT32( Xnrg[ b ], SKP_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + SKP_Silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = SKP_DIV32( SKP_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = SKP_DIV32( Xnrg[ b ], SKP_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = SKP_Silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = SKP_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( 1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = SKP_SMULWB( SKP_LSHIFT( SKP_Silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = SKP_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = SKP_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + *pSNR_dB_Q7 = ( SKP_int16 )( 3 * SKP_Silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = SKP_Silk_sigm_Q15( SKP_SMULWB( VAD_SNR_FACTOR_Q16, *pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + *pTilt_Q15 = SKP_LSHIFT( SKP_Silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * SKP_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = SKP_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + /* square-root */ + speech_nrg = SKP_Silk_SQRT_APPROX( SKP_LSHIFT( speech_nrg, 15 ) ); + SA_Q15 = SKP_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 to *pSA_Q8 */ + *pSA_Q8 = SKP_min_int( SKP_RSHIFT( SA_Q15, 7 ), SKP_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = SKP_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, SKP_SMULWB( SA_Q15, SA_Q15 ) ); + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = SKP_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( SKP_Silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + pQuality_Q15[ b ] = SKP_Silk_sigm_Q15( SKP_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +void SKP_Silk_VAD_GetNoiseLevels( + const SKP_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + SKP_int k; + SKP_int32 nl, nrg, inv_nrg; + SKP_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = SKP_DIV32_16( SKP_int16_MAX, SKP_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + SKP_assert( nl >= 0 ); + + /* Add bias */ + nrg = SKP_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + SKP_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = SKP_DIV32( SKP_int32_MAX, nrg ); + SKP_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > SKP_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = SKP_SMULWB( SKP_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = SKP_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = SKP_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + SKP_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = SKP_DIV32( SKP_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + SKP_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = SKP_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } + + /* Increment frame counter */ + psSilk_VAD->counter++; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VQ_nearest_neighbor_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VQ_nearest_neighbor_FLP.c new file mode 100755 index 0000000..0eee6d9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_VQ_nearest_neighbor_FLP.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +#define Q14_CONVERSION_FAC 6.1035e-005f // 1 / 2^14 + +/* entropy constrained MATRIX-weighted VQ, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FLP( + SKP_int *ind, /* O Index of best codebook vector */ + SKP_float *rate_dist, /* O Best weighted quant. error + mu * rate */ + const SKP_float *in, /* I Input vector to be quantized */ + const SKP_float *W, /* I Weighting matrix */ + const SKP_int16 *cb, /* I Codebook */ + const SKP_int16 *cl_Q6, /* I Code length for each codebook vector */ + const SKP_float mu, /* I Tradeoff between WSSE and rate */ + const SKP_int L /* I Number of vectors in codebook */ +) +{ + SKP_int k; + SKP_float sum1; + SKP_float diff[ 5 ]; + const SKP_int16 *cb_row; + + /* Loop over codebook */ + *rate_dist = SKP_float_MAX; + *ind = 0; + cb_row = cb; + for( k = 0; k < L; k++ ) { + /* Calc difference between in vector and cbk vector */ + diff[ 0 ] = in[ 0 ] - ( SKP_float )cb_row[ 0 ] * Q14_CONVERSION_FAC; + diff[ 1 ] = in[ 1 ] - ( SKP_float )cb_row[ 1 ] * Q14_CONVERSION_FAC; + diff[ 2 ] = in[ 2 ] - ( SKP_float )cb_row[ 2 ] * Q14_CONVERSION_FAC; + diff[ 3 ] = in[ 3 ] - ( SKP_float )cb_row[ 3 ] * Q14_CONVERSION_FAC; + diff[ 4 ] = in[ 4 ] - ( SKP_float )cb_row[ 4 ] * Q14_CONVERSION_FAC; + + /* Weighted rate */ + sum1 = mu * cl_Q6[ k ] / 64.0f; + + /* Add weighted quantization error, assuming W is symmetric */ + /* first row of W */ + sum1 += diff[ 0 ] * ( W[ 0 ] * diff[ 0 ] + + 2.0f * ( W[ 1 ] * diff[ 1 ] + + W[ 2 ] * diff[ 2 ] + + W[ 3 ] * diff[ 3 ] + + W[ 4 ] * diff[ 4 ] ) ); + + /* second row of W */ + sum1 += diff[ 1 ] * ( W[ 6 ] * diff[ 1 ] + + 2.0f * ( W[ 7 ] * diff[ 2 ] + + W[ 8 ] * diff[ 3 ] + + W[ 9 ] * diff[ 4 ] ) ); + + /* third row of W */ + sum1 += diff[ 2 ] * ( W[ 12 ] * diff[ 2 ] + + 2.0f * ( W[ 13 ] * diff[ 3 ] + + W[ 14 ] * diff[ 4 ] ) ); + + /* fourth row of W */ + sum1 += diff[ 3 ] * ( W[ 18 ] * diff[ 3 ] + + 2.0f * ( W[ 19 ] * diff[ 4 ] ) ); + + /* last row of W */ + sum1 += diff[ 4 ] * ( W[ 24 ] * diff[ 4 ] ); + + /* find best */ + if( sum1 < *rate_dist ) { + *rate_dist = sum1; + *ind = k; + } + + /* Go to next cbk vector */ + cb_row += LTP_ORDER; + } + + /* If this breaks, we had a floating point wrap-around or similar */ + SKP_assert( ( *rate_dist ) < SKP_float_MAX ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int.c new file mode 100755 index 0000000..f707635 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_allpass_int.c * + * * + * First-order allpass filter with * + * transfer function: * + * * + * A + Z^(-1) * + * H(z) = ------------ * + * 1 + A*Z^(-1) * + * * + * Implemented using minimum multiplier filter design. * + * * + * Reference: http://www.univ.trieste.it/~ramponi/teaching/ * + * DSP/materiale/Ch6(2).pdf * + * * + * Copyright 2007 (c), Skype Limited * + * Date: 070525 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + + +/* First-order allpass filter */ +void SKP_Silk_allpass_int( + const SKP_int32 *in, /* I: Q25 input signal [len] */ + SKP_int32 *S, /* I/O: Q25 state [1] */ + SKP_int A, /* I: Q15 coefficient (0 <= A < 32768) */ + SKP_int32 *out, /* O: Q25 output signal [len] */ + const SKP_int32 len /* I: Number of samples */ +) +{ + SKP_int32 Y2, X2, S0; + SKP_int k; + + S0 = S[ 0 ]; + for( k = len - 1; k >= 0; k-- ) { + Y2 = *in - S0; + X2 = ( Y2 >> 15 ) * A + ( ( ( Y2 & 0x00007FFF ) * A ) >> 15 ); + ( *out++ ) = S0 + X2; + S0 = ( *in++ ) + X2; + } + S[ 0 ] = S0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int_FLP.c new file mode 100755 index 0000000..aa031d9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_allpass_int_FLP.c @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_allpass_int.c * + * * + * First-order allpass filter with * * + * transfer function: * + * * + * A + Z^(-1) * + * H(z) = ------------ * + * 1 + A*Z^(-1) * + * * + * Implemented using minimum multiplier filter design. * + * * + * Reference: http://www.univ.trieste.it/~ramponi/teaching/ * + * DSP/materiale/Ch6(2).pdf * + * * + * Copyright 2007 (c), Skype Limited * + * Date: 070525 * + * */ +#include "SKP_Silk_SigProc_FLP.h" + +/* first-order allpass filter */ +void SKP_Silk_allpass_int_FLP( + const SKP_float *in, /* I: input signal [len] */ + SKP_float *S, /* I/O: state [1] */ + SKP_float A, /* I: coefficient (0 <= A < 1) */ + SKP_float *out, /* O: output signal [len] */ + const SKP_int32 len /* I: number of samples */ +) +{ + SKP_float Y2, X2, S0; + SKP_int32 k; + + S0 = S[ 0 ]; + for ( k = len-1; k >= 0; k-- ) { + Y2 = *in - S0; + X2 = Y2 * A; + (*out++) = S0 + X2; + S0 = (*in++) + X2; + } + S[ 0 ] = S0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_ana_filt_bank_1.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_ana_filt_bank_1.c new file mode 100755 index 0000000..bc35a65 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_ana_filt_bank_1.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_ana_filt_bank_1.c * + * * + * Split signal into two decimated bands using first-order allpass filters * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +// old +static SKP_int16 A_fb1_20[ 1 ] = { 5394 << 1 }; +static SKP_int16 A_fb1_21[ 1 ] = { 20623 << 1 }; /* wrap-around to negative number is intentional */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void SKP_Silk_ana_filt_bank_1( + const SKP_int16 *in, /* I: Input signal [N] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *outL, /* O: Low band [N/2] */ + SKP_int16 *outH, /* O: High band [N/2] */ + SKP_int32 *scratch, /* I: Scratch memory [3*N/2] */ // todo: remove - no longer used + const SKP_int32 N /* I: Number of input samples */ +) +{ + SKP_int k, N2 = SKP_RSHIFT( N, 1 ); + SKP_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, A_fb1_21[ 0 ] ); + out_1 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, A_fb1_20[ 0 ] ); + out_2 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( SKP_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_apply_sine_window_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_apply_sine_window_FLP.c new file mode 100755 index 0000000..0d41b76 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_apply_sine_window_FLP.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void SKP_Silk_apply_sine_window_FLP( + SKP_float px_win[], /* O Pointer to windowed signal */ + const SKP_float px[], /* I Pointer to input signal */ + const SKP_int win_type, /* I Selects a window type */ + const SKP_int length /* I Window length, multiple of 4 */ +) +{ + SKP_int k; + SKP_float freq, c, S0, S1; + + SKP_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + SKP_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_autocorrelation_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_autocorrelation_FLP.c new file mode 100755 index 0000000..9e0029e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_autocorrelation_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_SigProc_FLP.h" + +/* compute autocorrelation */ +void SKP_Silk_autocorrelation_FLP( + SKP_float *results, /* O result (length correlationCount) */ + const SKP_float *inputData, /* I input data to correlate */ + SKP_int inputDataSize, /* I length of input */ + SKP_int correlationCount /* I number of correlation taps to compute */ +) +{ + SKP_int i; + + if ( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (SKP_float)SKP_Silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad.c new file mode 100755 index 0000000..9485292 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad.c @@ -0,0 +1,72 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_biquad.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Second order ARMA filter */ +/* Can handle slowly varying filter coefficients */ +void SKP_Silk_biquad( + const SKP_int16 *in, /* I: input signal */ + const SKP_int16 *B, /* I: MA coefficients, Q13 [3] */ + const SKP_int16 *A, /* I: AR coefficients, Q13 [2] */ + SKP_int32 *S, /* I/O: state vector [2] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length */ +) +{ + SKP_int k, in16; + SKP_int32 A0_neg, A1_neg, S0, S1, out32, tmp32; + + S0 = S[ 0 ]; + S1 = S[ 1 ]; + A0_neg = -A[ 0 ]; + A1_neg = -A[ 1 ]; + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q13 */ + in16 = in[ k ]; + out32 = SKP_SMLABB( S0, in16, B[ 0 ] ); + + S0 = SKP_SMLABB( S1, in16, B[ 1 ] ); + S0 += SKP_LSHIFT( SKP_SMULWB( out32, A0_neg ), 3 ); + + S1 = SKP_LSHIFT( SKP_SMULWB( out32, A1_neg ), 3 ); + S1 = SKP_SMLABB( S1, in16, B[ 2 ] ); + tmp32 = SKP_RSHIFT_ROUND( out32, 13 ) + 1; + out[ k ] = (SKP_int16)SKP_SAT16( tmp32 ); + } + S[ 0 ] = S0; + S[ 1 ] = S1; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad_alt.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad_alt.c new file mode 100755 index 0000000..1810046 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_biquad_alt.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ +#include "SKP_Silk_SigProc_FIX.h" + + +/* Second order ARMA filter, alternative implementation */ +void SKP_Silk_biquad_alt( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int32 *B_Q28, /* I: MA coefficients [3] */ + const SKP_int32 *A_Q28, /* I: AR coefficients [2] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len /* I: Signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + SKP_int k; + SKP_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = SKP_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = SKP_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = SKP_LSHIFT( SKP_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + SKP_RSHIFT_ROUND( SKP_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = SKP_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = SKP_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = SKP_RSHIFT_ROUND( SKP_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = SKP_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = SKP_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_burg_modified_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_burg_modified_FLP.c new file mode 100755 index 0000000..e91364f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_burg_modified_FLP.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_burg_modified.c * + * * + * Calculates the reflection coefficients from the input vector * + * Input vector contains nb_subfr sub vectors of length L_sub + D * + * * + * Copyright 2009 (c), Skype Limited * + * Date: 091130 * + */ + +#include "SKP_Silk_SigProc_FLP.h" + +#define MAX_FRAME_SIZE 544 // subfr_length * nb_subfr = ( 0.005 * 24000 + 16 ) * 4 = 544 +#define MAX_NB_SUBFR 4 + +/* Compute reflection coefficients from input signal */ +SKP_float SKP_Silk_burg_modified_FLP( /* O returns residual energy */ + SKP_float A[], /* O prediction coefficients (length order) */ + const SKP_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ + const SKP_int nb_subfr, /* I number of subframes stacked in x */ + const SKP_float WhiteNoiseFrac, /* I fraction added to zero-lag autocorrelation */ + const SKP_int D /* I order */ +) +{ + SKP_int k, n, s; + double C0, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const SKP_float *x_ptr; + double C_first_row[ SKP_Silk_MAX_ORDER_LPC ], C_last_row[ SKP_Silk_MAX_ORDER_LPC ]; + double CAf[ SKP_Silk_MAX_ORDER_LPC + 1 ], CAb[ SKP_Silk_MAX_ORDER_LPC + 1 ]; + double Af[ SKP_Silk_MAX_ORDER_LPC ]; + + SKP_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + SKP_assert( nb_subfr <= MAX_NB_SUBFR ); + + /* Compute autocorrelations, added over subframes */ + C0 = SKP_Silk_energy_FLP( x, nb_subfr * subfr_length ); + SKP_memset( C_first_row, 0, SKP_Silk_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += SKP_Silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + SKP_memcpy( C_last_row, C_first_row, SKP_Silk_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + WhiteNoiseFrac * C0 + 1e-9f; + + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + SKP_assert( subfr_length - n + k + s * subfr_length >= 0 ); + SKP_assert( subfr_length - n + k + s * subfr_length < nb_subfr * subfr_length ); + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + SKP_assert( nrg_f > 0.0 ); + SKP_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + SKP_assert( rc > -1.0 && rc < 1.0 ); + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + /* Return residual energy */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (SKP_float)(-Atmp); + } + nrg_f -= WhiteNoiseFrac * C0 * tmp1; + + return (SKP_float)nrg_f; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander.c new file mode 100755 index 0000000..530f271 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander( + SKP_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + SKP_int i; + SKP_int32 chirp_minus_one_Q16; + + chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use SKP_SMULWB, instead of SKP_RSHIFT_ROUND( SKP_MUL() , 16 ), below. */ + /* Bias in SKP_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (SKP_int16)SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (SKP_int16)SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_32.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_32.c new file mode 100755 index 0000000..8c669bb --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_32.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander_32( + SKP_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + SKP_int i; + SKP_int32 tmp_chirp_Q16; + + tmp_chirp_Q16 = chirp_Q16; + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = SKP_SMULWW( ar[ i ], tmp_chirp_Q16 ); + tmp_chirp_Q16 = SKP_SMULWW( chirp_Q16, tmp_chirp_Q16 ); + } + ar[ d - 1 ] = SKP_SMULWW( ar[ d - 1 ], tmp_chirp_Q16 ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_FLP.c new file mode 100755 index 0000000..06d38e1 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_bwexpander_FLP.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#include "SKP_Silk_SigProc_FLP.h" + + +/* Chirp (bw expand) LP AR filter */ +void SKP_Silk_bwexpander_FLP( + SKP_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I length of ar */ + const SKP_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + SKP_int i; + SKP_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_code_signs.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_code_signs.c new file mode 100755 index 0000000..bb037db --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_code_signs.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +//#define SKP_enc_map(a) ((a) > 0 ? 1 : 0) +//#define SKP_dec_map(a) ((a) > 0 ? 1 : -1) +/* shifting avoids if-statement */ +#define SKP_enc_map(a) ( SKP_RSHIFT( (a), 15 ) + 1 ) +#define SKP_dec_map(a) ( SKP_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void SKP_Silk_encode_signs( + SKP_Silk_range_coder_state *sRC, /* I/O Range coder state */ + const SKP_int8 q[], /* I Pulse signal */ + const SKP_int length, /* I Length of input */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate level index */ +) +{ + SKP_int i; + SKP_int inData; + SKP_uint16 cdf[ 3 ]; + + i = SKP_SMULBB( N_RATE_LEVELS - 1, SKP_LSHIFT( sigtype, 1 ) + QuantOffsetType ) + RateLevelIndex; + cdf[ 0 ] = 0; + cdf[ 1 ] = SKP_Silk_sign_CDF[ i ]; + cdf[ 2 ] = 65535; + + for( i = 0; i < length; i++ ) { + if( q[ i ] != 0 ) { + inData = SKP_enc_map( q[ i ] ); /* - = 0, + = 1 */ + SKP_Silk_range_encoder( sRC, inData, cdf ); + } + } +} + +/* Decodes signs of excitation */ +void SKP_Silk_decode_signs( + SKP_Silk_range_coder_state *sRC, /* I/O Range coder state */ + SKP_int q[], /* I/O pulse signal */ + const SKP_int length, /* I length of output */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +) +{ + SKP_int i; + SKP_int data; + SKP_uint16 cdf[ 3 ]; + + i = SKP_SMULBB( N_RATE_LEVELS - 1, SKP_LSHIFT( sigtype, 1 ) + QuantOffsetType ) + RateLevelIndex; + cdf[ 0 ] = 0; + cdf[ 1 ] = SKP_Silk_sign_CDF[ i ]; + cdf[ 2 ] = 65535; + + for( i = 0; i < length; i++ ) { + if( q[ i ] > 0 ) { + SKP_Silk_range_decoder( &data, sRC, cdf, 1 ); + /* attach sign */ + /* implementation with shift, subtraction, multiplication */ + q[ i ] *= SKP_dec_map( data ); + } + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_common_pitch_est_defines.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_common_pitch_est_defines.h new file mode 100755 index 0000000..cc8c20e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_common_pitch_est_defines.h @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROC_COMMON_PITCH_EST_DEFINES_H +#define SIGPROC_COMMON_PITCH_EST_DEFINES_H + +#include "SKP_Silk_SigProc_FIX.h" + +/************************************************************/ +/* Definitions For Fix pitch estimator */ +/************************************************************/ + +#define PITCH_EST_MAX_FS_KHZ 24 /* Maximum sampling frequency used */ + +#define PITCH_EST_FRAME_LENGTH_MS 40 /* 40 ms */ + +#define PITCH_EST_MAX_FRAME_LENGTH (PITCH_EST_FRAME_LENGTH_MS * PITCH_EST_MAX_FS_KHZ) +#define PITCH_EST_MAX_FRAME_LENGTH_ST_1 (PITCH_EST_MAX_FRAME_LENGTH >> 2) +#define PITCH_EST_MAX_FRAME_LENGTH_ST_2 (PITCH_EST_MAX_FRAME_LENGTH >> 1) +#define PITCH_EST_MAX_SF_FRAME_LENGTH (PITCH_EST_SUB_FRAME * PITCH_EST_MAX_FS_KHZ) + +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG (PITCH_EST_MAX_LAG_MS * PITCH_EST_MAX_FS_KHZ) +#define PITCH_EST_MIN_LAG (PITCH_EST_MIN_LAG_MS * PITCH_EST_MAX_FS_KHZ) + +#define PITCH_EST_NB_SUBFR 4 + +#define PITCH_EST_D_SRCH_LENGTH 24 + +#define PITCH_EST_MAX_DECIMATE_STATE_LENGTH 7 + +#define PITCH_EST_NB_STAGE3_LAGS 5 + +#define PITCH_EST_NB_CBKS_STAGE2 3 +#define PITCH_EST_NB_CBKS_STAGE2_EXT 11 + +#define PITCH_EST_CB_mn2 1 +#define PITCH_EST_CB_mx2 2 + +#define PITCH_EST_NB_CBKS_STAGE3_MAX 34 +#define PITCH_EST_NB_CBKS_STAGE3_MID 24 +#define PITCH_EST_NB_CBKS_STAGE3_MIN 16 + +extern const SKP_int16 SKP_Silk_CB_lags_stage2[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE2_EXT]; +extern const SKP_int16 SKP_Silk_CB_lags_stage3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX]; +extern const SKP_int16 SKP_Silk_Lag_range_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ] [ PITCH_EST_NB_SUBFR ][ 2 ]; +extern const SKP_int16 SKP_Silk_cbk_sizes_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ]; +extern const SKP_int16 SKP_Silk_cbk_offsets_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ]; + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_audio_bandwidth.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_audio_bandwidth.c new file mode 100755 index 0000000..c57baa6 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_audio_bandwidth.c @@ -0,0 +1,137 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Control internal sampling rate */ +SKP_int SKP_Silk_control_audio_bandwidth( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + const SKP_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + SKP_int fs_kHz; + + fs_kHz = psEncC->fs_kHz; + if( fs_kHz == 0 ) { + /* Encoder has just been initialized */ + if( TargetRate_bps >= SWB2WB_BITRATE_BPS ) { + fs_kHz = 24; + } else if( TargetRate_bps >= WB2MB_BITRATE_BPS ) { + fs_kHz = 16; + } else if( TargetRate_bps >= MB2NB_BITRATE_BPS ) { + fs_kHz = 12; + } else { + fs_kHz = 8; + } + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_kHz = SKP_min( fs_kHz, SKP_DIV32_16( psEncC->API_fs_Hz, 1000 ) ); + fs_kHz = SKP_min( fs_kHz, psEncC->maxInternal_fs_kHz ); + } else if( SKP_SMULBB( fs_kHz, 1000 ) > psEncC->API_fs_Hz || fs_kHz > psEncC->maxInternal_fs_kHz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed */ + fs_kHz = SKP_DIV32_16( psEncC->API_fs_Hz, 1000 ); + fs_kHz = SKP_min( fs_kHz, psEncC->maxInternal_fs_kHz ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->API_fs_Hz > 8000 ) { + /* Accumulate the difference between the target rate and limit for switching down */ + psEncC->bitrateDiff += SKP_MUL( psEncC->PacketSize_ms, TargetRate_bps - psEncC->bitrate_threshold_down ); + psEncC->bitrateDiff = SKP_min( psEncC->bitrateDiff, 0 ); + + if( psEncC->vadFlag == NO_VOICE_ACTIVITY ) { /* Low speech activity */ + /* Check if we should switch down */ +#if SWITCH_TRANSITION_FILTERING + if( ( psEncC->sLP.transition_frame_no == 0 ) && /* Transition phase not active */ + ( psEncC->bitrateDiff <= -ACCUM_BITS_DIFF_THRESHOLD || /* Bitrate threshold is met */ + ( psEncC->sSWBdetect.WB_detected * psEncC->fs_kHz == 24 ) ) ) { /* Forced down-switching due to WB input */ + psEncC->sLP.transition_frame_no = 1; /* Begin transition phase */ + psEncC->sLP.mode = 0; /* Switch down */ + } else if( + ( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES_DOWN ) && /* Transition phase complete */ + ( psEncC->sLP.mode == 0 ) ) { /* Ready to switch down */ + psEncC->sLP.transition_frame_no = 0; /* Ready for new transition phase */ +#else + if( psEncC->bitrateDiff <= -ACCUM_BITS_DIFF_THRESHOLD ) { /* Bitrate threshold is met */ +#endif + psEncC->bitrateDiff = 0; + + /* Switch to a lower sample frequency */ + if( psEncC->fs_kHz == 24 ) { + fs_kHz = 16; + } else if( psEncC->fs_kHz == 16 ) { + fs_kHz = 12; + } else { + SKP_assert( psEncC->fs_kHz == 12 ); + fs_kHz = 8; + } + } + + /* Check if we should switch up */ + if( ( ( psEncC->fs_kHz * 1000 < psEncC->API_fs_Hz ) && + ( TargetRate_bps >= psEncC->bitrate_threshold_up ) && + ( psEncC->sSWBdetect.WB_detected * psEncC->fs_kHz < 16 ) ) && + ( ( ( psEncC->fs_kHz == 16 ) && ( psEncC->maxInternal_fs_kHz >= 24 ) ) || + ( ( psEncC->fs_kHz == 12 ) && ( psEncC->maxInternal_fs_kHz >= 16 ) ) || + ( ( psEncC->fs_kHz == 8 ) && ( psEncC->maxInternal_fs_kHz >= 12 ) ) ) +#if SWITCH_TRANSITION_FILTERING + && ( psEncC->sLP.transition_frame_no == 0 ) ) { /* No transition phase running, ready to switch */ + psEncC->sLP.mode = 1; /* Switch up */ +#else + ) { +#endif + psEncC->bitrateDiff = 0; + + /* Switch to a higher sample frequency */ + if( psEncC->fs_kHz == 8 ) { + fs_kHz = 12; + } else if( psEncC->fs_kHz == 12 ) { + fs_kHz = 16; + } else { + SKP_assert( psEncC->fs_kHz == 16 ); + fs_kHz = 24; + } + } + } + } + +#if SWITCH_TRANSITION_FILTERING + /* After switching up, stop transition filter during speech inactivity */ + if( ( psEncC->sLP.mode == 1 ) && + ( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES_UP ) && + ( psEncC->vadFlag == NO_VOICE_ACTIVITY ) ) { + + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + SKP_memset( psEncC->sLP.In_LP_State, 0, 2 * sizeof( SKP_int32 ) ); + } +#endif + } + + + + return fs_kHz; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_codec_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_codec_FLP.c new file mode 100755 index 0000000..2eda36c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_control_codec_FLP.c @@ -0,0 +1,411 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_setup_complexity.h" + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int PacketSize_ms /* I Packet length (ms) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_fs( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_rate( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int32 TargetRate_bps /* I Target max bitrate */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR( + SKP_Silk_encoder_state_FLP *psEnc /* I/O Pointer to Silk encoder state FLP */ +); + +/* Control encoder */ +SKP_int SKP_Silk_control_encoder_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + const SKP_int PacketSize_ms, /* I Packet length (ms) */ + const SKP_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const SKP_int PacketLoss_perc, /* I Packet loss rate (in percent) */ + const SKP_int DTX_enabled, /* I Enable / disable DTX */ + const SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +) +{ + SKP_int fs_kHz, ret = 0; + + if( psEnc->sCmn.controlled_since_last_payload != 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += SKP_Silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = SKP_Silk_control_audio_bandwidth( &psEnc->sCmn, TargetRate_bps ); + + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += SKP_Silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set packet size */ + /********************************************/ + ret += SKP_Silk_setup_packetsize( psEnc, PacketSize_ms ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += SKP_Silk_setup_fs( psEnc, fs_kHz ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += SKP_Silk_setup_complexity( &psEnc->sCmn, Complexity ); + + /********************************************/ + /* Set bitrate/coding quality */ + /********************************************/ + ret += SKP_Silk_setup_rate( psEnc, TargetRate_bps ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + if( ( PacketLoss_perc < 0 ) || ( PacketLoss_perc > 100 ) ) { + ret = SKP_SILK_ENC_INVALID_LOSS_RATE; + } + psEnc->sCmn.PacketLoss_perc = PacketLoss_perc; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += SKP_Silk_setup_LBRR( psEnc ); + + /********************************************/ + /* Set DTX mode */ + /********************************************/ + if( DTX_enabled < 0 || DTX_enabled > 1 ) { + ret = SKP_SILK_ENC_INVALID_DTX_SETTING; + } + psEnc->sCmn.useDTX = DTX_enabled; + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +/* Control low bitrate redundancy usage */ +void SKP_Silk_LBRR_ctrl_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I Encoder state FLP */ + SKP_Silk_encoder_control *psEncCtrl /* I/O Encoder control */ +) +{ + SKP_int LBRR_usage; + + if( psEnc->sCmn.LBRR_enabled ) { + /* Control LBRR */ + + /* Usage Control based on sensitivity and packet loss caracteristics */ + /* For now only enable adding to next for active frames. Make more complex later */ + LBRR_usage = SKP_SILK_NO_LBRR; + if( psEnc->speech_activity > LBRR_SPEECH_ACTIVITY_THRES && psEnc->sCmn.PacketLoss_perc > LBRR_LOSS_THRES ) { // nb! maybe multiply loss prob and speech activity + LBRR_usage = SKP_SILK_ADD_LBRR_TO_PLUS1; + } + psEncCtrl->LBRR_usage = LBRR_usage; + } else { + psEncCtrl->LBRR_usage = SKP_SILK_NO_LBRR; + } +} + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) { + + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += SKP_Silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000 ); + } else { + /* Allocate space for worst case temporary upsampling, 8 to 48 kHz, so a factor 6 */ + SKP_int16 x_buf_API_fs_Hz[ ( 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ) * ( MAX_API_FS_KHZ / 8 ) ]; + SKP_int16 x_bufFIX[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ]; + + SKP_int32 nSamples_temp = 2 * psEnc->sCmn.frame_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz; + + SKP_float2short_array( x_bufFIX, psEnc->x_buf, nSamples_temp ); + + if( fs_kHz * 1000 < psEnc->sCmn.API_fs_Hz && psEnc->sCmn.fs_kHz != 0 ) { + /* Resample buffered data in x_buf to API_fs_Hz */ + + SKP_Silk_resampler_state_struct temp_resampler_state; + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ret += SKP_Silk_resampler_init( &temp_resampler_state, psEnc->sCmn.fs_kHz * 1000, psEnc->sCmn.API_fs_Hz ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ret += SKP_Silk_resampler( &temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, nSamples_temp ); + + /* Calculate number of samples that has been temporarily upsampled */ + nSamples_temp = SKP_DIV32_16( nSamples_temp * psEnc->sCmn.API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += SKP_Silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000 ); + + } else { + /* Copy data */ + SKP_memcpy( x_buf_API_fs_Hz, x_bufFIX, nSamples_temp * sizeof( SKP_int16 ) ); + } + + if( 1000 * fs_kHz != psEnc->sCmn.API_fs_Hz ) { + /* Correct resampler state (unless resampling by a factor 1) by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, nSamples_temp ); + } + SKP_short2float_array( psEnc->x_buf, x_bufFIX, ( 2 * FRAME_LENGTH_MS + LA_SHAPE_MS ) * fs_kHz ); + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + return ret; +} + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int PacketSize_ms /* I Packet length (ms) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Set packet size */ + if( ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) && + ( PacketSize_ms != 80 ) && + ( PacketSize_ms != 100 ) ) { + ret = SKP_SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } else { + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + + /* Packet length changes. Reset LBRR buffer */ + SKP_Silk_LBRR_reset( &psEnc->sCmn ); + } + } + return(ret); +} + +SKP_INLINE SKP_int SKP_Silk_setup_fs( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Set internal sampling frequency */ + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + SKP_memset( &psEnc->sShape, 0, sizeof( SKP_Silk_shape_state_FLP ) ); + SKP_memset( &psEnc->sPrefilt, 0, sizeof( SKP_Silk_prefilter_state_FLP ) ); + SKP_memset( &psEnc->sPred, 0, sizeof( SKP_Silk_predict_state_FLP ) ); + SKP_memset( &psEnc->sCmn.sNSQ, 0, sizeof( SKP_Silk_nsq_state ) ); + SKP_memset( psEnc->sCmn.sNSQ_LBRR.xq, 0, ( 2 * MAX_FRAME_LENGTH ) * sizeof( SKP_int16 ) ); + SKP_memset( psEnc->sCmn.LBRR_buffer, 0, MAX_LBRR_DELAY * sizeof( SKP_SILK_LBRR_struct ) ); +#if SWITCH_TRANSITION_FILTERING + SKP_memset( psEnc->sCmn.sLP.In_LP_State, 0, 2 * sizeof( SKP_int32 ) ); + if( psEnc->sCmn.sLP.mode == 1 ) { + /* Begin transition phase */ + psEnc->sCmn.sLP.transition_frame_no = 1; + } else { + /* End transition phase */ + psEnc->sCmn.sLP.transition_frame_no = 0; + } +#endif + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesInPayloadBuf = 0; + psEnc->sCmn.nBytesInPayloadBuf = 0; + psEnc->sCmn.oldest_LBRR_idx = 0; + psEnc->sCmn.TargetRate_bps = 0; /* Ensures that psEnc->SNR_dB is recomputed */ + + SKP_memset( psEnc->sPred.prev_NLSFq, 0, MAX_LPC_ORDER * sizeof( SKP_float ) ); + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.prev_sigtype = SIG_TYPE_UNVOICED; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sPrefilt.lagPrev = 100; + psEnc->sShape.LastGainIndex = 1; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_inv_gain_Q16 = 65536; + psEnc->sCmn.sNSQ_LBRR.prev_inv_gain_Q16 = 65536; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_10; + psEnc->sCmn.psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_10; + psEnc->psNLSF_CB_FLP[ 0 ] = &SKP_Silk_NLSF_CB0_10_FLP; + psEnc->psNLSF_CB_FLP[ 1 ] = &SKP_Silk_NLSF_CB1_10_FLP; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_16; + psEnc->sCmn.psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_16; + psEnc->psNLSF_CB_FLP[ 0 ] = &SKP_Silk_NLSF_CB0_16_FLP; + psEnc->psNLSF_CB_FLP[ 1 ] = &SKP_Silk_NLSF_CB1_16_FLP; + } + psEnc->sCmn.frame_length = FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.subfr_length = psEnc->sCmn.frame_length / NB_SUBFR; + psEnc->sCmn.la_pitch = LA_PITCH_MS * fs_kHz; + psEnc->sPred.min_pitch_lag = 3 * fs_kHz; + psEnc->sPred.max_pitch_lag = 18 * fs_kHz; + psEnc->sPred.pitch_LPC_win_length = FIND_PITCH_LPC_WIN_MS * fs_kHz; + if( psEnc->sCmn.fs_kHz == 24 ) { + psEnc->mu_LTP = MU_LTP_QUANT_SWB; + psEnc->sCmn.bitrate_threshold_up = SKP_int32_MAX; + psEnc->sCmn.bitrate_threshold_down = SWB2WB_BITRATE_BPS; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->mu_LTP = MU_LTP_QUANT_WB; + psEnc->sCmn.bitrate_threshold_up = WB2SWB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = WB2MB_BITRATE_BPS; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->mu_LTP = MU_LTP_QUANT_MB; + psEnc->sCmn.bitrate_threshold_up = MB2WB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = MB2NB_BITRATE_BPS; + } else { + psEnc->mu_LTP = MU_LTP_QUANT_NB; + psEnc->sCmn.bitrate_threshold_up = NB2MB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = 0; + } + psEnc->sCmn.fs_kHz_changed = 1; + + /* Check that settings are valid */ + SKP_assert( ( psEnc->sCmn.subfr_length * NB_SUBFR ) == psEnc->sCmn.frame_length ); + } + return ret; +} + +SKP_INLINE SKP_int SKP_Silk_setup_rate( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + SKP_int32 TargetRate_bps /* I Target max bitrate */ +) +{ + SKP_int k, ret = SKP_SILK_NO_ERROR; + SKP_float frac; + const SKP_int32 *rateTable; + + /* Set bitrate/coding quality */ + if( TargetRate_bps != psEnc->sCmn.TargetRate_bps ) { + psEnc->sCmn.TargetRate_bps = TargetRate_bps; + + /* If new TargetRate_bps, translate to SNR_dB value */ + if( psEnc->sCmn.fs_kHz == 8 ) { + rateTable = TargetRate_table_NB; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + rateTable = TargetRate_table_MB; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + rateTable = TargetRate_table_WB; + } else { + rateTable = TargetRate_table_SWB; + } + for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) { + /* Find bitrate interval in table and interpolate */ + if( TargetRate_bps <= rateTable[ k ] ) { + frac = (SKP_float)( TargetRate_bps - rateTable[ k - 1 ] ) / + (SKP_float)( rateTable[ k ] - rateTable[ k - 1 ] ); + psEnc->SNR_dB = 0.5f * ( SNR_table_Q1[ k - 1 ] + frac * ( SNR_table_Q1[ k ] - SNR_table_Q1[ k - 1 ] ) ); + break; + } + } + } + return( ret ); +} + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR( + SKP_Silk_encoder_state_FLP *psEnc /* I/O Pointer to Silk encoder state FLP */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + +#if USE_LBRR + SKP_int32 LBRRRate_thres_bps; + + if( psEnc->sCmn.useInBandFEC < 0 || psEnc->sCmn.useInBandFEC > 1 ) { + ret = SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + + psEnc->sCmn.LBRR_enabled = psEnc->sCmn.useInBandFEC; + if( psEnc->sCmn.fs_kHz == 8 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 9000; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 6000; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 3000; + } else { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS; + } + + if( psEnc->sCmn.TargetRate_bps >= LBRRRate_thres_bps ) { + /* Set gain increase / rate reduction for LBRR usage */ + /* Coarsely tuned with PESQ for now. */ + /* Linear regression coefs G = 8 - 0.5 * loss */ + /* Meaning that at 16% loss main rate and redundant rate is the same, -> G = 0 */ + psEnc->sCmn.LBRR_GainIncreases = SKP_max_int( 8 - SKP_RSHIFT( psEnc->sCmn.PacketLoss_perc, 1 ), 0 ); + + /* Set main stream rate compensation */ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.PacketLoss_perc > LBRR_LOSS_THRES ) { + /* Tuned to give approx same mean / weighted bitrate as no inband FEC */ + psEnc->inBandFEC_SNR_comp = 6.0f - 0.5f * psEnc->sCmn.LBRR_GainIncreases; + } else { + psEnc->inBandFEC_SNR_comp = 0.0f; + psEnc->sCmn.LBRR_enabled = 0; + } + } else { + psEnc->inBandFEC_SNR_comp = 0.0f; + psEnc->sCmn.LBRR_enabled = 0; + } +#else + if( INBandFEC_enabled != 0 ) { + ret = SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + psEnc->sCmn.LBRR_enabled = 0; +#endif + return ret; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_corrMatrix_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_corrMatrix_FLP.c new file mode 100755 index 0000000..64134cf --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_corrMatrix_FLP.c @@ -0,0 +1,89 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FLP( + const SKP_float *x, /* I x vector [L+order-1] used to create X */ + const SKP_float *t, /* I Target vector [L] */ + const SKP_int L, /* I Length of vecors */ + const SKP_int Order, /* I Max lag for correlation */ + SKP_float *Xt /* O X'*t correlation vector [order] */ +) +{ + SKP_int lag; + const SKP_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (SKP_float)SKP_Silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FLP( + const SKP_float *x, /* I x vector [ L+order-1 ] used to create X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int Order, /* I Max lag for correlation */ + SKP_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + SKP_int j, lag; + double energy; + const SKP_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = SKP_Silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( SKP_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( SKP_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = SKP_Silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( SKP_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( SKP_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( SKP_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( SKP_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_create_init_destroy.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_create_init_destroy.c new file mode 100755 index 0000000..aa6cea0 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_create_init_destroy.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + + +/************************/ +/* Init Decoder State */ +/************************/ +SKP_int SKP_Silk_init_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + SKP_memset( psDec, 0, sizeof( SKP_Silk_decoder_state ) ); + /* Set sampling rate to 24 kHz, and init non-zero values */ + SKP_Silk_decoder_set_fs( psDec, 24 ); + + /* Used to deactivate e.g. LSF interpolation and fluctuation reduction */ + psDec->first_frame_after_reset = 1; + psDec->prev_inv_gain_Q16 = 65536; + + /* Reset CNG state */ + SKP_Silk_CNG_Reset( psDec ); + + SKP_Silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_dec_API.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_dec_API.c new file mode 100755 index 0000000..1de13c6 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_dec_API.c @@ -0,0 +1,279 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SDK_API.h" +#include "SKP_Silk_main.h" + +/*********************/ +/* Decoder functions */ +/*********************/ + +SKP_int SKP_Silk_SDK_Get_Decoder_Size( SKP_int32 *decSizeBytes ) +{ + SKP_int ret = 0; + + *decSizeBytes = sizeof( SKP_Silk_decoder_state ); + + return ret; +} + +/* Reset decoder state */ +SKP_int SKP_Silk_SDK_InitDecoder( + void* decState /* I/O: State */ +) +{ + SKP_int ret = 0; + SKP_Silk_decoder_state *struc; + + struc = (SKP_Silk_decoder_state *)decState; + + ret = SKP_Silk_init_decoder( struc ); + + return ret; +} + +/* Decode a frame */ +SKP_int SKP_Silk_SDK_Decode( + void* decState, /* I/O: State */ + SKP_SILK_SDK_DecControlStruct* decControl, /* I/O: Control structure */ + SKP_int lostFlag, /* I: 0: no loss, 1 loss */ + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input Bytes */ + SKP_int16 *samplesOut, /* O: Decoded output speech vector */ + SKP_int16 *nSamplesOut /* I/O: Number of samples (vector/decoded) */ +) +{ + SKP_int ret = 0, used_bytes, prev_fs_kHz; + SKP_Silk_decoder_state *psDec; + SKP_int16 samplesOutInternal[ MAX_API_FS_KHZ * FRAME_LENGTH_MS ]; + SKP_int16 *pSamplesOutInternal; + + psDec = (SKP_Silk_decoder_state *)decState; + + /* We need this buffer to have room for an internal frame */ + pSamplesOutInternal = samplesOut; + if( psDec->fs_kHz * 1000 > decControl->API_sampleRate ) { + pSamplesOutInternal = samplesOutInternal; + } + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( psDec->moreInternalDecoderFrames == 0 ) { + /* First Frame in Payload */ + psDec->nFramesDecoded = 0; /* Used to count frames in packet */ + } + + if( psDec->moreInternalDecoderFrames == 0 && /* First frame in packet */ + lostFlag == 0 && /* Not packet loss */ + nBytesIn > MAX_ARITHM_BYTES ) { /* Too long payload */ + /* Avoid trying to decode a too large packet */ + lostFlag = 1; + ret = SKP_SILK_DEC_PAYLOAD_TOO_LARGE; + } + + /* Save previous sample frequency */ + prev_fs_kHz = psDec->fs_kHz; + + /* Call decoder for one frame */ + ret += SKP_Silk_decode_frame( psDec, pSamplesOutInternal, nSamplesOut, inData, nBytesIn, + lostFlag, &used_bytes ); + + if( used_bytes ) { /* Only Call if not a packet loss */ + if( psDec->nBytesLeft > 0 && psDec->FrameTermination == SKP_SILK_MORE_FRAMES && psDec->nFramesDecoded < 5 ) { + /* We have more frames in the Payload */ + psDec->moreInternalDecoderFrames = 1; + } else { + /* Last frame in Payload */ + psDec->moreInternalDecoderFrames = 0; + psDec->nFramesInPacket = psDec->nFramesDecoded; + + /* Track inband FEC usage */ + if( psDec->vadFlag == VOICE_ACTIVITY ) { + if( psDec->FrameTermination == SKP_SILK_LAST_FRAME ) { + psDec->no_FEC_counter++; + if( psDec->no_FEC_counter > NO_LBRR_THRES ) { + psDec->inband_FEC_offset = 0; + } + } else if( psDec->FrameTermination == SKP_SILK_LBRR_VER1 ) { + psDec->inband_FEC_offset = 1; /* FEC info with 1 packet delay */ + psDec->no_FEC_counter = 0; + } else if( psDec->FrameTermination == SKP_SILK_LBRR_VER2 ) { + psDec->inband_FEC_offset = 2; /* FEC info with 2 packets delay */ + psDec->no_FEC_counter = 0; + } + } + } + } + + if( MAX_API_FS_KHZ * 1000 < decControl->API_sampleRate || + 8000 > decControl->API_sampleRate ) { + ret = SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY; + return( ret ); + } + + /* Resample if needed */ + if( psDec->fs_kHz * 1000 != decControl->API_sampleRate ) { + SKP_int16 samplesOut_tmp[ MAX_API_FS_KHZ * FRAME_LENGTH_MS ]; + SKP_assert( psDec->fs_kHz <= MAX_API_FS_KHZ ); + + /* Copy to a tmp buffer as the resampling writes to samplesOut */ + SKP_memcpy( samplesOut_tmp, pSamplesOutInternal, *nSamplesOut * sizeof( SKP_int16 ) ); + + /* (Re-)initialize resampler state when switching internal sampling frequency */ + if( prev_fs_kHz != psDec->fs_kHz || psDec->prev_API_sampleRate != decControl->API_sampleRate ) { + ret = SKP_Silk_resampler_init( &psDec->resampler_state, SKP_SMULBB( psDec->fs_kHz, 1000 ), decControl->API_sampleRate ); + } + + /* Resample the output to API_sampleRate */ + ret += SKP_Silk_resampler( &psDec->resampler_state, samplesOut, samplesOut_tmp, *nSamplesOut ); + + /* Update the number of output samples */ + *nSamplesOut = SKP_DIV32( ( SKP_int32 )*nSamplesOut * decControl->API_sampleRate, psDec->fs_kHz * 1000 ); + } else if( prev_fs_kHz * 1000 > decControl->API_sampleRate ) { + SKP_memcpy( samplesOut, pSamplesOutInternal, *nSamplesOut * sizeof( SKP_int16 ) ); + } + + psDec->prev_API_sampleRate = decControl->API_sampleRate; + + /* Copy all parameters that are needed out of internal structure to the control stucture */ + decControl->frameSize = (SKP_uint16)( decControl->API_sampleRate / 50 ) ; + decControl->framesPerPacket = ( SKP_int )psDec->nFramesInPacket; + decControl->inBandFECOffset = ( SKP_int )psDec->inband_FEC_offset; + decControl->moreInternalDecoderFrames = ( SKP_int )psDec->moreInternalDecoderFrames; + + return ret; +} + +/* Function to find LBRR information in a packet */ +void SKP_Silk_SDK_search_for_LBRR( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input Bytes */ + SKP_int lost_offset, /* I: Offset from lost packet */ + SKP_uint8 *LBRRData, /* O: LBRR payload */ + SKP_int16 *nLBRRBytes /* O: Number of LBRR Bytes */ +) +{ + SKP_Silk_decoder_state sDec; // Local decoder state to avoid interfering with running decoder */ + SKP_Silk_decoder_control sDecCtrl; + SKP_int TempQ[ MAX_FRAME_LENGTH ]; + + if( lost_offset < 1 || lost_offset > MAX_LBRR_DELAY ) { + /* No useful FEC in this packet */ + *nLBRRBytes = 0; + return; + } + + sDec.nFramesDecoded = 0; + sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */ + sDec.lossCnt = 0; /* Avoid running bw expansion of the LPC parameters when searching for LBRR data */ + SKP_memset( sDec.prevNLSF_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + SKP_Silk_range_dec_init( &sDec.sRC, inData, ( SKP_int32 )nBytesIn ); + + while(1) { + SKP_Silk_decode_parameters( &sDec, &sDecCtrl, TempQ, 0 ); + + if( sDec.sRC.error ) { + /* Corrupt stream */ + *nLBRRBytes = 0; + return; + }; + if( ( sDec.FrameTermination - 1 ) & lost_offset && sDec.FrameTermination > 0 && sDec.nBytesLeft >= 0 ) { + /* The wanted FEC is present in the packet */ + *nLBRRBytes = sDec.nBytesLeft; + SKP_memcpy( LBRRData, &inData[ nBytesIn - sDec.nBytesLeft ], sDec.nBytesLeft * sizeof( SKP_uint8 ) ); + break; + } + if( sDec.nBytesLeft > 0 && sDec.FrameTermination == SKP_SILK_MORE_FRAMES ) { + sDec.nFramesDecoded++; + } else { + LBRRData = NULL; + *nLBRRBytes = 0; + break; + } + } +} + +/* Getting type of content for a packet */ +void SKP_Silk_SDK_get_TOC( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input bytes */ + SKP_Silk_TOC_struct *Silk_TOC /* O: Type of content */ +) +{ + SKP_Silk_decoder_state sDec; // Local Decoder state to avoid interfering with running decoder */ + SKP_Silk_decoder_control sDecCtrl; + SKP_int TempQ[ MAX_FRAME_LENGTH ]; + + sDec.nFramesDecoded = 0; + sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */ + SKP_Silk_range_dec_init( &sDec.sRC, inData, ( SKP_int32 )nBytesIn ); + + Silk_TOC->corrupt = 0; + while( 1 ) { + SKP_Silk_decode_parameters( &sDec, &sDecCtrl, TempQ, 0 ); + + Silk_TOC->vadFlags[ sDec.nFramesDecoded ] = sDec.vadFlag; + Silk_TOC->sigtypeFlags[ sDec.nFramesDecoded ] = sDecCtrl.sigtype; + + if( sDec.sRC.error ) { + /* Corrupt stream */ + Silk_TOC->corrupt = 1; + break; + }; + + if( sDec.nBytesLeft > 0 && sDec.FrameTermination == SKP_SILK_MORE_FRAMES ) { + sDec.nFramesDecoded++; + } else { + break; + } + } + if( Silk_TOC->corrupt || sDec.FrameTermination == SKP_SILK_MORE_FRAMES || + sDec.nFramesInPacket > SILK_MAX_FRAMES_PER_PACKET ) { + /* Corrupt packet */ + SKP_memset( Silk_TOC, 0, sizeof( SKP_Silk_TOC_struct ) ); + Silk_TOC->corrupt = 1; + } else { + Silk_TOC->framesInPacket = sDec.nFramesDecoded + 1; + Silk_TOC->fs_kHz = sDec.fs_kHz; + if( sDec.FrameTermination == SKP_SILK_LAST_FRAME ) { + Silk_TOC->inbandLBRR = sDec.FrameTermination; + } else { + Silk_TOC->inbandLBRR = sDec.FrameTermination - 1; + } + } +} + +/**************************/ +/* Get the version number */ +/**************************/ +/* Return a pointer to string specifying the version */ +const char *SKP_Silk_SDK_get_version() +{ + static const char version[] = "1.0.9"; + return version; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarse_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarse_FLP.c new file mode 100755 index 0000000..06c90a9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarse_FLP.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_decimate2_coarse.c * + * * + * downsample by a factor 2, coarser * + * */ +#include "SKP_Silk_SigProc_FLP.h" + +/* coefficients for coarser 2-fold resampling */ +static SKP_float A20c_FLP[ 2 ] = {0.064666748046875f, 0.508514404296875f}; +static SKP_float A21c_FLP[ 2 ] = {0.245666503906250f, 0.819732666015625f}; + +/* downsample by a factor 2, coarser */ +void SKP_Silk_decimate2_coarse_FLP( + const SKP_float *in, /* I: 16 kHz signal [2*len] */ + SKP_float *S, /* I/O: state vector [4] */ + SKP_float *out, /* O: 8 kHz signal [len] */ + SKP_float *scratch, /* I: scratch memory [3*len] */ + const SKP_int32 len /* I: number of OUTPUT samples */ +) +{ + SKP_int32 k; + + /* de-interleave allpass inputs */ + for ( k = 0; k < len; k++) { + scratch[ k ] = in[ 2 * k ]; + scratch[ k + len ] = in[ 2 * k + 1 ]; + } + + /* allpass filters */ + SKP_Silk_allpass_int_FLP( scratch, S + 0, A21c_FLP[ 0 ], scratch + 2 * len, len ); + SKP_Silk_allpass_int_FLP( scratch + 2 * len, S + 1, A21c_FLP[ 1 ], scratch, len ); + + SKP_Silk_allpass_int_FLP( scratch + len, S + 2, A20c_FLP[ 0 ], scratch + 2 * len, len ); + SKP_Silk_allpass_int_FLP( scratch + 2 * len, S + 3, A20c_FLP[ 1 ], scratch + len, len ); + + /* add two allpass outputs */ + for ( k = 0; k < len; k++ ) { + out[ k ] = 0.5f * ( scratch[ k ] + scratch[ k + len ] ); + } +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarsest_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarsest_FLP.c new file mode 100755 index 0000000..c65a2c7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decimate2_coarsest_FLP.c @@ -0,0 +1,67 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_decimate2_coarsest.c * + * * + * downsample by a factor 2, coarsest * + * */ +#include "SKP_Silk_SigProc_FLP.h" + +/* coefficients for coarsest 2-fold resampling */ +/* note that these differ from the interpolator with the same filter orders! */ +static float A20cst_FLP[ 1 ] = {0.289001464843750f}; +static float A21cst_FLP[ 1 ] = {0.780487060546875f}; + +/* downsample by a factor 2, coarsest */ +void SKP_Silk_decimate2_coarsest_FLP( + const SKP_float *in, /* I: 16 kHz signal [2*len] */ + SKP_float *S, /* I/O: state vector [2] */ + SKP_float *out, /* O: 8 kHz signal [len] */ + SKP_float *scratch, /* I: scratch memory [3*len] */ + const SKP_int32 len /* I: number of OUTPUT samples */ +) +{ + SKP_int32 k; + + /* de-interleave allpass inputs */ + for ( k = 0; k < len; k++ ) { + scratch[ k ] = in[ 2 * k + 0 ]; + scratch[ k + len ] = in[ 2 * k + 1 ]; + } + + /* allpass filters */ + SKP_Silk_allpass_int_FLP( scratch, S + 0, A21cst_FLP[ 0 ], scratch + 2 * len, len ); + SKP_Silk_allpass_int_FLP( scratch + len, S + 1, A20cst_FLP[ 0 ], scratch, len ); + + /* add two allpass outputs */ + for ( k = 0; k < len; k++ ) { + out[ k ] = 0.5f * ( scratch[ k ] + scratch[ k + 2 * len ] ); + } +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_core.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_core.c new file mode 100755 index 0000000..258195c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_core.c @@ -0,0 +1,242 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + + +void SKP_Silk_decode_short_term_prediction( +SKP_int32 *vec_Q10, +SKP_int32 *pres_Q10, +SKP_int32 *sLPC_Q14, +SKP_int16 *A_Q12_tmp, +SKP_int LPC_order, +SKP_int subfr_length +); + + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void SKP_Silk_decode_core( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 xq[], /* O Decoded speech */ + const SKP_int q[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +) +{ + SKP_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, sigtype; + SKP_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + SKP_int16 sLTP[ MAX_FRAME_LENGTH ]; + SKP_int32 LTP_pred_Q14, Gain_Q16, inv_gain_Q16, inv_gain_Q32, gain_adj_Q16, rand_seed, offset_Q10, dither; + SKP_int32 *pred_lag_ptr, *pexc_Q10, *pres_Q10; + SKP_int32 vec_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + SKP_int32 FiltState[ MAX_LPC_ORDER ]; + + SKP_assert( psDec->prev_inv_gain_Q16 != 0 ); + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psDecCtrl->sigtype ][ psDecCtrl->QuantOffsetType ]; + + if( psDecCtrl->NLSFInterpCoef_Q2 < ( 1 << 2 ) ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + + /* Decode excitation */ + rand_seed = psDecCtrl->Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = SKP_RAND( rand_seed ); + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( rand_seed, 31 ); + + psDec->exc_Q10[ i ] = SKP_LSHIFT( ( SKP_int32 )q[ i ], 10 ) + offset_Q10; + psDec->exc_Q10[ i ] = ( psDec->exc_Q10[ i ] ^ dither ) - dither; + + rand_seed += q[ i ]; + } + + + pexc_Q10 = psDec->exc_Q10; + pres_Q10 = psDec->res_Q10; + pxq = &psDec->outBuf[ psDec->frame_length ]; + sLTP_buf_idx = psDec->frame_length; + /* Loop over subframes */ + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( SKP_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + Gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + sigtype = psDecCtrl->sigtype; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gain_Q16, 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + + /* Calculate Gain adjustment factor */ + gain_adj_Q16 = ( SKP_int32 )1 << 16; + if( inv_gain_Q16 != psDec->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, psDec->prev_inv_gain_Q16, 16 ); + } + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prev_sigtype == SIG_TYPE_VOICED && + psDecCtrl->sigtype == SIG_TYPE_UNVOICED && k < ( NB_SUBFR >> 1 ) ) { + + SKP_memset( B_Q14, 0, LTP_ORDER * sizeof( SKP_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = ( SKP_int16 )1 << 12; /* 0.25 */ + + sigtype = SIG_TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + + lag = psDecCtrl->pitchL[ k ]; + /* Re-whitening */ + if( ( k & ( 3 - SKP_LSHIFT( NLSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->frame_length - lag - psDec->LPC_order - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psDec->frame_length - psDec->LPC_order ); + + SKP_memset( FiltState, 0, psDec->LPC_order * sizeof( SKP_int32 ) ); /* Not really necessary, but Valgrind and Coverity will complain otherwise */ + SKP_Silk_MA_Prediction( &psDec->outBuf[ start_idx + k * ( psDec->frame_length >> 2 ) ], + A_Q12, FiltState, sLTP + start_idx, psDec->frame_length - start_idx, psDec->LPC_order ); + + /* After rewhitening the LTP state is unscaled */ + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( k == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < (lag + LTP_ORDER/2); i++ ) { + psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] = SKP_SMULWB( inv_gain_Q32, sLTP[ psDec->frame_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != ( SKP_int32 )1 << 16 ) { + for( i = 0; i < ( lag + LTP_ORDER / 2 ); i++ ) { + psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] = SKP_SMULWW( gain_adj_Q16, psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + psDec->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDec->sLPC_Q14[ i ] ); + } + + /* Save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + psDec->prev_inv_gain_Q16 = inv_gain_Q16; + + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Setup pointer */ + pred_lag_ptr = &psDec->sLTP_Q16[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC residual */ + pres_Q10[ i ] = SKP_ADD32( pexc_Q10[ i ], SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); + + /* Update states */ + psDec->sLTP_Q16[ sLTP_buf_idx ] = SKP_LSHIFT( pres_Q10[ i ], 6 ); + sLTP_buf_idx++; + } + } else { + SKP_memcpy( pres_Q10, pexc_Q10, psDec->subfr_length * sizeof( SKP_int32 ) ); + } + + SKP_Silk_decode_short_term_prediction(vec_Q10, pres_Q10, psDec->sLPC_Q14,A_Q12_tmp,psDec->LPC_order,psDec->subfr_length); + + /* Scale with Gain */ + for( i = 0; i < psDec->subfr_length; i++ ) { + pxq[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( vec_Q10[ i ], Gain_Q16 ), 10 ) ); + } + + /* Update LPC filter state */ + SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + pexc_Q10 += psDec->subfr_length; + pres_Q10 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Copy to output */ + SKP_memcpy( xq, &psDec->outBuf[ psDec->frame_length ], psDec->frame_length * sizeof( SKP_int16 ) ); + +} + +void SKP_Silk_decode_short_term_prediction( +SKP_int32 *vec_Q10, +SKP_int32 *pres_Q10, +SKP_int32 *sLPC_Q14, +SKP_int16 *A_Q12_tmp, +SKP_int LPC_order, +SKP_int subfr_length +) +{ + SKP_int i; + SKP_int32 LPC_pred_Q10; + SKP_int j; + for( i = 0; i < subfr_length; i++ ) { + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + + for( j = 10; j < LPC_order; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - j - 1 ], A_Q12_tmp[ j ] ); + } + + /* Add prediction to LPC residual */ + vec_Q10[ i ] = SKP_ADD32( pres_Q10[ i ], LPC_pred_Q10 ); + + /* Update states */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT_ovflw( vec_Q10[ i ], 4 ); + } +} + + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_frame.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_frame.c new file mode 100755 index 0000000..13f27e0 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_frame.c @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +SKP_int SKP_Silk_decode_frame( + SKP_Silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + SKP_int16 pOut[], /* O Pointer to output speech frame */ + SKP_int16 *pN, /* O Pointer to size of output frame */ + const SKP_uint8 pCode[], /* I Pointer to payload */ + const SKP_int nBytes, /* I Payload length */ + SKP_int action, /* I Action from Jitter Buffer */ + SKP_int *decBytes /* O Used bytes to decode this frame */ +) +{ + SKP_Silk_decoder_control sDecCtrl; + SKP_int L, fs_Khz_old, ret = 0; + SKP_int Pulses[ MAX_FRAME_LENGTH ]; + + + L = psDec->frame_length; + sDecCtrl.LTP_scale_Q14 = 0; + + /* Safety checks */ + SKP_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + /********************************************/ + /* Decode Frame if packet is not lost */ + /********************************************/ + *decBytes = 0; + if( action == 0 ) { + /********************************************/ + /* Initialize arithmetic coder */ + /********************************************/ + fs_Khz_old = psDec->fs_kHz; + if( psDec->nFramesDecoded == 0 ) { + /* Initialize range decoder state */ + SKP_Silk_range_dec_init( &psDec->sRC, pCode, nBytes ); + } + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + SKP_Silk_decode_parameters( psDec, &sDecCtrl, Pulses, 1 ); + + + if( psDec->sRC.error ) { + psDec->nBytesLeft = 0; + + action = 1; /* PLC operation */ + /* revert fs if changed in decode_parameters */ + SKP_Silk_decoder_set_fs( psDec, fs_Khz_old ); + + /* Avoid crashing */ + *decBytes = psDec->sRC.bufferLength; + + if( psDec->sRC.error == RANGE_CODER_DEC_PAYLOAD_TOO_LONG ) { + ret = SKP_SILK_DEC_PAYLOAD_TOO_LARGE; + } else { + ret = SKP_SILK_DEC_PAYLOAD_ERROR; + } + } else { + *decBytes = psDec->sRC.bufferLength - psDec->nBytesLeft; + psDec->nFramesDecoded++; + + /* Update lengths. Sampling frequency could have changed */ + L = psDec->frame_length; + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + SKP_Silk_decode_core( psDec, &sDecCtrl, pOut, Pulses ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + SKP_Silk_PLC( psDec, &sDecCtrl, pOut, L, action ); + + psDec->lossCnt = 0; + psDec->prev_sigtype = sDecCtrl.sigtype; + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } + } + /*************************************************************/ + /* Generate Concealment frame if packet is lost, or corrupt */ + /*************************************************************/ + if( action == 1 ) { + /* Handle packet loss by extrapolation */ + SKP_Silk_PLC( psDec, &sDecCtrl, pOut, L, action ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + SKP_memcpy( psDec->outBuf, pOut, L * sizeof( SKP_int16 ) ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + SKP_Silk_PLC_glue_frames( psDec, &sDecCtrl, pOut, L ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + SKP_Silk_CNG( psDec, &sDecCtrl, pOut , L ); + + /********************************************/ + /* HP filter output */ + /********************************************/ + SKP_assert( ( ( psDec->fs_kHz == 12 ) && ( L % 3 ) == 0 ) || + ( ( psDec->fs_kHz != 12 ) && ( L % 2 ) == 0 ) ); + SKP_Silk_biquad( pOut, psDec->HP_B, psDec->HP_A, psDec->HPState, pOut, L ); + + /********************************************/ + /* set output frame length */ + /********************************************/ + *pN = ( SKP_int16 )L; + + /* Update some decoder state variables */ + psDec->lagPrev = sDecCtrl.pitchL[ NB_SUBFR - 1 ]; + + + return ret; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_parameters.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_parameters.c new file mode 100755 index 0000000..9dc6935 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_parameters.c @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Decode parameters from payload */ +void SKP_Silk_decode_parameters( + SKP_Silk_decoder_state *psDec, /* I/O State */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int fullDecoding /* I Flag to tell if only arithmetic decoding */ +) +{ + SKP_int i, k, Ix, fs_kHz_dec, nBytesUsed; + SKP_int Ixs[ NB_SUBFR ]; + SKP_int GainsIndices[ NB_SUBFR ]; + SKP_int NLSFIndices[ NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const SKP_int16 *cbk_ptr_Q14; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB = NULL; + SKP_Silk_range_coder_state *psRC = &psDec->sRC; + + /************************/ + /* Decode sampling rate */ + /************************/ + /* only done for first frame of packet */ + if( psDec->nFramesDecoded == 0 ) { + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_SamplingRates_CDF, SKP_Silk_SamplingRates_offset ); + + /* check that sampling rate is supported */ + if( Ix < 0 || Ix > 3 ) { + psRC->error = RANGE_CODER_ILLEGAL_SAMPLING_RATE; + return; + } + fs_kHz_dec = SKP_Silk_SamplingRates_table[ Ix ]; + SKP_Silk_decoder_set_fs( psDec, fs_kHz_dec ); + } + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( psDec->nFramesDecoded == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_type_offset_CDF, SKP_Silk_type_offset_CDF_offset ); + } else { + /* condidtional coding */ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_type_offset_joint_CDF[ psDec->typeOffsetPrev ], + SKP_Silk_type_offset_CDF_offset ); + } + psDecCtrl->sigtype = SKP_RSHIFT( Ix, 1 ); + psDecCtrl->QuantOffsetType = Ix & 1; + psDec->typeOffsetPrev = Ix; + + /****************/ + /* Decode gains */ + /****************/ + /* first subframe */ + if( psDec->nFramesDecoded == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_decoder( &GainsIndices[ 0 ], psRC, SKP_Silk_gain_CDF[ psDecCtrl->sigtype ], SKP_Silk_gain_CDF_offset ); + } else { + /* condidtional coding */ + SKP_Silk_range_decoder( &GainsIndices[ 0 ], psRC, SKP_Silk_delta_gain_CDF, SKP_Silk_delta_gain_CDF_offset ); + } + + /* remaining subframes */ + for( i = 1; i < NB_SUBFR; i++ ) { + SKP_Silk_range_decoder( &GainsIndices[ i ], psRC, SKP_Silk_delta_gain_CDF, SKP_Silk_delta_gain_CDF_offset ); + } + + /* Dequant Gains */ + SKP_Silk_gains_dequant( psDecCtrl->Gains_Q16, GainsIndices, &psDec->LastGainIndex, psDec->nFramesDecoded ); + /****************/ + /* Decode NLSFs */ + /****************/ + /* Set pointer to NLSF VQ CB for the current signal type */ + psNLSF_CB = psDec->psNLSF_CB[ psDecCtrl->sigtype ]; + + /* Range decode NLSF path */ + SKP_Silk_range_decoder_multi( NLSFIndices, psRC, psNLSF_CB->StartPtr, psNLSF_CB->MiddleIx, psNLSF_CB->nStages ); + + /* From the NLSF path, decode an NLSF vector */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, NLSFIndices, psDec->LPC_order ); + + /************************************/ + /* Decode NLSF interpolation factor */ + /************************************/ + SKP_Silk_range_decoder( &psDecCtrl->NLSFInterpCoef_Q2, psRC, SKP_Silk_NLSF_interpolation_factor_CDF, + SKP_Silk_NLSF_interpolation_factor_offset ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDecCtrl->NLSFInterpCoef_Q2 = 4; + } + + if( fullDecoding ) { + /* Convert NLSF parameters to AR prediction filter coefficients */ + SKP_Silk_NLSF2A_stable( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order ); + + if( psDecCtrl->NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + SKP_RSHIFT( SKP_MUL( psDecCtrl->NLSFInterpCoef_Q2, + ( pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ) ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + SKP_Silk_NLSF2A_stable( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order ); + } else { + /* Copy LPC coefficients for first half from second half */ + SKP_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], + psDec->LPC_order * sizeof( SKP_int16 ) ); + } + } + + SKP_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( SKP_int ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + SKP_Silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + SKP_Silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDecCtrl->sigtype == SIG_TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + if( psDec->fs_kHz == 8 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_NB_CDF, SKP_Silk_pitch_lag_NB_CDF_offset ); + } else if( psDec->fs_kHz == 12 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_MB_CDF, SKP_Silk_pitch_lag_MB_CDF_offset ); + } else if( psDec->fs_kHz == 16 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_WB_CDF, SKP_Silk_pitch_lag_WB_CDF_offset ); + } else { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_SWB_CDF, SKP_Silk_pitch_lag_SWB_CDF_offset ); + } + + /* Get countour index */ + if( psDec->fs_kHz == 8 ) { + /* Less codevectors used in 8 khz mode */ + SKP_Silk_range_decoder( &Ixs[ 1 ], psRC, SKP_Silk_pitch_contour_NB_CDF, SKP_Silk_pitch_contour_NB_CDF_offset ); + } else { + /* Joint for 12, 16, and 24 khz */ + SKP_Silk_range_decoder( &Ixs[ 1 ], psRC, SKP_Silk_pitch_contour_CDF, SKP_Silk_pitch_contour_CDF_offset ); + } + + /* Decode pitch values */ + SKP_Silk_decode_pitch( Ixs[ 0 ], Ixs[ 1 ], psDecCtrl->pitchL, psDec->fs_kHz ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + SKP_Silk_range_decoder( &psDecCtrl->PERIndex, psRC, SKP_Silk_LTP_per_index_CDF, + SKP_Silk_LTP_per_index_CDF_offset ); + + /* Decode Codebook Index */ + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ psDecCtrl->PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < NB_SUBFR; k++ ) { + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_LTP_gain_CDF_ptrs[ psDecCtrl->PERIndex ], + SKP_Silk_LTP_gain_CDF_offsets[ psDecCtrl->PERIndex ] ); + + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = cbk_ptr_Q14[ Ix * LTP_ORDER + i ]; + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_LTPscale_CDF, SKP_Silk_LTPscale_offset ); + psDecCtrl->LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ Ix ]; + } else { + SKP_assert( psDecCtrl->sigtype == SIG_TYPE_UNVOICED ); + SKP_memset( psDecCtrl->pitchL, 0, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * NB_SUBFR * sizeof( SKP_int16 ) ); + psDecCtrl->PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } + + /***************/ + /* Decode seed */ + /***************/ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_Seed_CDF, SKP_Silk_Seed_offset ); + psDecCtrl->Seed = ( SKP_int32 )Ix; + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + SKP_Silk_decode_pulses( psRC, psDecCtrl, q, psDec->frame_length ); + + /*********************************************/ + /* Decode VAD flag */ + /*********************************************/ + SKP_Silk_range_decoder( &psDec->vadFlag, psRC, SKP_Silk_vadflag_CDF, SKP_Silk_vadflag_offset ); + + /**************************************/ + /* Decode Frame termination indicator */ + /**************************************/ + SKP_Silk_range_decoder( &psDec->FrameTermination, psRC, SKP_Silk_FrameTermination_CDF, SKP_Silk_FrameTermination_offset ); + + /****************************************/ + /* get number of bytes used so far */ + /****************************************/ + SKP_Silk_range_coder_get_length( psRC, &nBytesUsed ); + psDec->nBytesLeft = psRC->bufferLength - nBytesUsed; + if( psDec->nBytesLeft < 0 ) { + psRC->error = RANGE_CODER_READ_BEYOND_BUFFER; + } + + /****************************************/ + /* check remaining bits in last byte */ + /****************************************/ + if( psDec->nBytesLeft == 0 ) { + SKP_Silk_range_coder_check_after_decoding( psRC ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pitch.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pitch.c new file mode 100755 index 0000000..6c18a94 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pitch.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +void SKP_Silk_decode_pitch( + SKP_int lagIndex, /* I */ + SKP_int contourIndex, /* O */ + SKP_int pitch_lags[], /* O 4 pitch values */ + SKP_int Fs_kHz /* I sampling frequency (kHz) */ +) +{ + SKP_int lag, i, min_lag; + + min_lag = SKP_SMULBB( PITCH_EST_MIN_LAG_MS, Fs_kHz ); + + /* Only for 24 / 16 kHz version for now */ + lag = min_lag + lagIndex; + if( Fs_kHz == 8 ) { + /* Only a small codebook for 8 khz */ + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + pitch_lags[ i ] = lag + SKP_Silk_CB_lags_stage2[ i ][ contourIndex ]; + } + } else { + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + pitch_lags[ i ] = lag + SKP_Silk_CB_lags_stage3[ i ][ contourIndex ]; + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pulses.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pulses.c new file mode 100755 index 0000000..19ad210 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decode_pulses.c @@ -0,0 +1,105 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void SKP_Silk_decode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int frame_length /* I Frame length (preliminary) */ +) +{ + SKP_int i, j, k, iter, abs_q, nLS, bit; + SKP_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + SKP_int *pulses_ptr; + const SKP_uint16 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + SKP_Silk_range_decoder( &psDecCtrl->RateLevelIndex, psRC, + SKP_Silk_rate_levels_CDF[ psDecCtrl->sigtype ], SKP_Silk_rate_levels_CDF_offset ); + + /* Calculate number of shell blocks */ + iter = frame_length / SHELL_CODEC_FRAME_LENGTH; + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = SKP_Silk_pulses_per_block_CDF[ psDecCtrl->RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + SKP_Silk_range_decoder( &sum_pulses[ i ], psRC, cdf_ptr, SKP_Silk_pulses_per_block_CDF_offset ); + + /* LSB indication */ + while( sum_pulses[ i ] == ( MAX_PULSES + 1 ) ) { + nLshifts[ i ]++; + SKP_Silk_range_decoder( &sum_pulses[ i ], psRC, + SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ], SKP_Silk_pulses_per_block_CDF_offset ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + SKP_Silk_shell_decoder( &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRC, sum_pulses[ i ] ); + } else { + SKP_memset( &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( SKP_int ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = SKP_LSHIFT( abs_q, 1 ); + SKP_Silk_range_decoder( &bit, psRC, SKP_Silk_lsb_CDF, 1 ); + abs_q += bit; + } + pulses_ptr[ k ] = abs_q; + } + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + SKP_Silk_decode_signs( psRC, q, frame_length, psDecCtrl->sigtype, + psDecCtrl->QuantOffsetType, psDecCtrl->RateLevelIndex); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decoder_set_fs.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decoder_set_fs.c new file mode 100755 index 0000000..4b15f27 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_decoder_set_fs.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Set decoder sampling rate */ +void SKP_Silk_decoder_set_fs( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state pointer */ + SKP_int fs_kHz /* I Sampling frequency (kHz) */ +) +{ + if( psDec->fs_kHz != fs_kHz ) { + psDec->fs_kHz = fs_kHz; + psDec->frame_length = SKP_SMULBB( FRAME_LENGTH_MS, fs_kHz ); + psDec->subfr_length = SKP_SMULBB( FRAME_LENGTH_MS / NB_SUBFR, fs_kHz ); + if( psDec->fs_kHz == 8 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_10; + psDec->psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_10; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_16; + psDec->psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_16; + } + /* Reset part of the decoder state */ + SKP_memset( psDec->sLPC_Q14, 0, MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + SKP_memset( psDec->outBuf, 0, MAX_FRAME_LENGTH * sizeof( SKP_int16 ) ); + SKP_memset( psDec->prevNLSF_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + + psDec->lagPrev = 100; + psDec->LastGainIndex = 1; + psDec->prev_sigtype = 0; + psDec->first_frame_after_reset = 1; + + if( fs_kHz == 24 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_24; + psDec->HP_B = SKP_Silk_Dec_B_HP_24; + } else if( fs_kHz == 16 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_16; + psDec->HP_B = SKP_Silk_Dec_B_HP_16; + } else if( fs_kHz == 12 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_12; + psDec->HP_B = SKP_Silk_Dec_B_HP_12; + } else if( fs_kHz == 8 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_8; + psDec->HP_B = SKP_Silk_Dec_B_HP_8; + } else { + /* unsupported sampling rate */ + SKP_assert( 0 ); + } + } + + /* Check that settings are valid */ + SKP_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_define.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_define.h new file mode 100755 index 0000000..ad6f7d5 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_define.h @@ -0,0 +1,306 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_DEFINE_H +#define SKP_SILK_DEFINE_H + +#include "SKP_Silk_errors.h" +#include "SKP_Silk_typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define MAX_FRAMES_PER_PACKET 5 + + + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 100000 + +/* Transition bitrates between modes */ +#define SWB2WB_BITRATE_BPS 25000 +#define WB2SWB_BITRATE_BPS 30000 +#define WB2MB_BITRATE_BPS 14000 +#define MB2WB_BITRATE_BPS 18000 +#define MB2NB_BITRATE_BPS 10000 +#define NB2MB_BITRATE_BPS 14000 + +/* Integration/hysteresis threshold for lowering internal sample frequency */ +/* 30000000 -> 6 sec if bitrate is 5000 bps below limit; 3 sec if bitrate is 10000 bps below limit */ +#define ACCUM_BITS_DIFF_THRESHOLD 30000000 +#define TARGET_RATE_TAB_SZ 8 + +/* DTX settings */ +#define NO_SPEECH_FRAMES_BEFORE_DTX 5 /* eq 100 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ + +#define USE_LBRR 1 + +/* Amount of concecutive no FEC packets before telling JB */ +#define NO_LBRR_THRES 10 + +/* Maximum delay between real packet and LBRR packet */ +#define MAX_LBRR_DELAY 2 +#define LBRR_IDX_MASK 1 + +#define INBAND_FEC_MIN_RATE_BPS 18000 /* Dont use inband FEC below this total target rate */ +#define LBRR_LOSS_THRES 1 /* Start adding LBRR at this loss rate */ + +/* LBRR usage defines */ +#define SKP_SILK_NO_LBRR 0 /* No LBRR information for this packet */ +#define SKP_SILK_ADD_LBRR_TO_PLUS1 1 /* Add LBRR for this packet to packet n + 1 */ +#define SKP_SILK_ADD_LBRR_TO_PLUS2 2 /* Add LBRR for this packet to packet n + 2 */ + +/* Frame termination indicator defines */ +#define SKP_SILK_LAST_FRAME 0 /* Last frames in packet */ +#define SKP_SILK_MORE_FRAMES 1 /* More frames to follow this one */ +#define SKP_SILK_LBRR_VER1 2 /* LBRR information from packet n - 1 */ +#define SKP_SILK_LBRR_VER2 3 /* LBRR information from packet n - 2 */ +#define SKP_SILK_EXT_LAYER 4 /* Extension layers added */ + +/* Number of Second order Sections for SWB detection HP filter */ +#define NB_SOS 3 +#define HP_8_KHZ_THRES 10 /* average energy per sample, above 8 kHz */ +#define CONCEC_SWB_SMPLS_THRES 480 * 15 /* 300 ms */ +#define WB_DETECT_ACTIVE_SPEECH_MS_THRES 15000 /* ms of active speech needed for WB detection */ + +/* Low complexity setting */ +#define LOW_COMPLEXITY_ONLY 0 + +/* Activate bandwidth transition filtering for mode switching */ +#define SWITCH_TRANSITION_FILTERING 1 + +/* Decoder Parameters */ +#define DEC_HP_ORDER 2 + +/* Maximum sampling frequency, should be 16 for some embedded platforms */ +#define MAX_FS_KHZ 24 +#define MAX_API_FS_KHZ 48 + +/* Signal Types used by silk */ +#define SIG_TYPE_VOICED 0 +#define SIG_TYPE_UNVOICED 1 + +/* VAD Types used by silk */ +#define NO_VOICE_ACTIVITY 0 +#define VOICE_ACTIVITY 1 + +/* Number of samples per frame */ +#define FRAME_LENGTH_MS 20 +#define MAX_FRAME_LENGTH ( FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +#define PITCH_EST_COMPLEXITY_HC_MODE SKP_Silk_PITCH_EST_MAX_COMPLEX +#define PITCH_EST_COMPLEXITY_MC_MODE SKP_Silk_PITCH_EST_MID_COMPLEX +#define PITCH_EST_COMPLEXITY_LC_MODE SKP_Silk_PITCH_EST_MIN_COMPLEX + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Max length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* Max number of bytes in payload output buffer (may contain multiple frames) */ +#define MAX_ARITHM_BYTES 1024 + +#define RANGE_CODER_WRITE_BEYOND_BUFFER -1 +#define RANGE_CODER_CDF_OUT_OF_RANGE -2 +#define RANGE_CODER_NORMALIZATION_FAILED -3 +#define RANGE_CODER_ZERO_INTERVAL_WIDTH -4 +#define RANGE_CODER_DECODER_CHECK_FAILED -5 +#define RANGE_CODER_READ_BEYOND_BUFFER -6 +#define RANGE_CODER_ILLEGAL_SAMPLING_RATE -7 +#define RANGE_CODER_DEC_PAYLOAD_TOO_LONG -8 + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 6 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 86 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 40 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 256 + +/* Maximum numbers of iterations used to stabilize a LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 20 + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Number of subframes */ +#define NB_SUBFR 4 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 16 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK (LTP_BUF_LENGTH - 1) + +#define DECISION_DELAY 32 +#define DECISION_DELAY_MASK (DECISION_DELAY - 1) + +/* number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define MAX_NB_SHELL_BLOCKS (MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH) + +/* number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* maximum sum of pulses per shell coding frame */ +#define MAX_PULSES 18 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +#if( MAX_LPC_ORDER > DECISION_DELAY ) +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER +#else +# define NSQ_LPC_BUF_LENGTH DECISION_DELAY +#endif + +/***********************/ +/* High pass filtering */ +/***********************/ +#define HIGH_PASS_INPUT 1 + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES (1 << VAD_INTERNAL_SUBFRAMES_LOG2) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/******************/ +/* NLSF quantizer */ +/******************/ +# define NLSF_MSVQ_MAX_CB_STAGES 10 /* Update manually when changing codebooks */ +# define NLSF_MSVQ_MAX_VECTORS_IN_STAGE 128 /* Update manually when changing codebooks */ +# define NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END 16 /* Update manually when changing codebooks */ + +#define NLSF_MSVQ_FLUCTUATION_REDUCTION 1 +#define MAX_NLSF_MSVQ_SURVIVORS 16 +#define MAX_NLSF_MSVQ_SURVIVORS_LC_MODE 2 +#define MAX_NLSF_MSVQ_SURVIVORS_MC_MODE 4 + +/* Based on above defines, calculate how much memory is necessary to allocate */ +#if( NLSF_MSVQ_MAX_VECTORS_IN_STAGE > ( MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END ) ) +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE NLSF_MSVQ_MAX_VECTORS_IN_STAGE +#else +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END +#endif + +#if( NLSF_MSVQ_MAX_VECTORS_IN_STAGE > ( MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END ) ) +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED NLSF_MSVQ_MAX_VECTORS_IN_STAGE +#else +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END +#endif + +#define NLSF_MSVQ_SURV_MAX_REL_RD 0.1f /* Must be < 0.5 */ + +/* Transition filtering for mode switching */ +#if SWITCH_TRANSITION_FILTERING +# define TRANSITION_TIME_UP_MS 5120 // 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4) +# define TRANSITION_TIME_DOWN_MS 2560 // 2560 = 32 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 32*(20*4) +# define TRANSITION_NB 3 /* Hardcoded in tables */ +# define TRANSITION_NA 2 /* Hardcoded in tables */ +# define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +# define TRANSITION_FRAMES_UP ( TRANSITION_TIME_UP_MS / FRAME_LENGTH_MS ) +# define TRANSITION_FRAMES_DOWN ( TRANSITION_TIME_DOWN_MS / FRAME_LENGTH_MS ) +# define TRANSITION_INT_STEPS_UP ( TRANSITION_FRAMES_UP / ( TRANSITION_INT_NUM - 1 ) ) +# define TRANSITION_INT_STEPS_DOWN ( TRANSITION_FRAMES_DOWN / ( TRANSITION_INT_NUM - 1 ) ) +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) *(Matrix_base_adr + ((row)*(N)+(column))) +#define matrix_adr(Matrix_base_adr, row, column, N) (Matrix_base_adr + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) *(Matrix_base_adr + ((row)+(M)*(column))) +#endif +#define matrix_c_adr(Matrix_base_adr, row, column, M) (Matrix_base_adr + ((row)+(M)*(column))) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_detect_SWB_input.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_detect_SWB_input.c new file mode 100755 index 0000000..87c80c7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_detect_SWB_input.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + * Detect SWB input by measuring energy above 8 kHz. + */ + +#include "SKP_Silk_main.h" + +void SKP_Silk_detect_SWB_input( + SKP_Silk_detect_SWB_state *psSWBdetect, /* (I/O) encoder state */ + const SKP_int16 samplesIn[], /* (I) input to encoder */ + SKP_int nSamplesIn /* (I) length of input */ +) +{ + SKP_int HP_8_kHz_len, i, shift; + SKP_int16 in_HP_8_kHz[ MAX_FRAME_LENGTH ]; + SKP_int32 energy_32; + + /* High pass filter with cutoff at 8 khz */ + HP_8_kHz_len = SKP_min_int( nSamplesIn, MAX_FRAME_LENGTH ); + HP_8_kHz_len = SKP_max_int( HP_8_kHz_len, 0 ); + + /* Cutoff around 9 khz */ + /* A = conv(conv([8192,14613, 6868], [8192,12883, 7337]), [8192,11586, 7911]); */ + /* B = conv(conv([575, -948, 575], [575, -221, 575]), [575, 104, 575]); */ + SKP_Silk_biquad( samplesIn, SKP_Silk_SWB_detect_B_HP_Q13[ 0 ], SKP_Silk_SWB_detect_A_HP_Q13[ 0 ], + psSWBdetect->S_HP_8_kHz[ 0 ], in_HP_8_kHz, HP_8_kHz_len ); + for( i = 1; i < NB_SOS; i++ ) { + SKP_Silk_biquad( in_HP_8_kHz, SKP_Silk_SWB_detect_B_HP_Q13[ i ], SKP_Silk_SWB_detect_A_HP_Q13[ i ], + psSWBdetect->S_HP_8_kHz[ i ], in_HP_8_kHz, HP_8_kHz_len ); + } + + /* Calculate energy in HP signal */ + SKP_Silk_sum_sqr_shift( &energy_32, &shift, in_HP_8_kHz, HP_8_kHz_len ); + + /* Count concecutive samples above threshold, after adjusting threshold for number of input samples and shift */ + if( energy_32 > SKP_RSHIFT( SKP_SMULBB( HP_8_KHZ_THRES, HP_8_kHz_len ), shift ) ) { + psSWBdetect->ConsecSmplsAboveThres += nSamplesIn; + if( psSWBdetect->ConsecSmplsAboveThres > CONCEC_SWB_SMPLS_THRES ) { + psSWBdetect->SWB_detected = 1; + } + } else { + psSWBdetect->ConsecSmplsAboveThres -= nSamplesIn; + psSWBdetect->ConsecSmplsAboveThres = SKP_max( psSWBdetect->ConsecSmplsAboveThres, 0 ); + } + + /* If sufficient speech activity and no SWB detected, we detect the signal as being WB */ + if( ( psSWBdetect->ActiveSpeech_ms > WB_DETECT_ACTIVE_SPEECH_MS_THRES ) && ( psSWBdetect->SWB_detected == 0 ) ) { + psSWBdetect->WB_detected = 1; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_enc_API.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_enc_API.c new file mode 100755 index 0000000..e558766 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_enc_API.c @@ -0,0 +1,247 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#include "SKP_Silk_define.h" +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_SDK_API.h" +#include "SKP_Silk_control.h" +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_structs.h" +#define SKP_Silk_EncodeControlStruct SKP_SILK_SDK_EncControlStruct + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +SKP_int SKP_Silk_SDK_Get_Encoder_Size( SKP_int32 *encSizeBytes ) +{ + SKP_int ret = 0; + + *encSizeBytes = sizeof( SKP_Silk_encoder_state_FLP ); + + return ret; +} + + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +SKP_int SKP_Silk_SDK_QueryEncoder( + const void *encState, /* I: State Vector */ + SKP_Silk_EncodeControlStruct *encStatus /* O: Control Structure */ +) +{ + SKP_Silk_encoder_state_FLP *psEnc; + SKP_int ret = 0; + + psEnc = ( SKP_Silk_encoder_state_FLP* )encState; + + encStatus->API_sampleRate = psEnc->sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = SKP_SMULBB( psEnc->sCmn.maxInternal_fs_kHz, 1000 ); + encStatus->packetSize = ( SKP_int )SKP_DIV32_16( psEnc->sCmn.API_fs_Hz * psEnc->sCmn.PacketSize_ms, 1000 ); /* convert samples -> ms */ + encStatus->bitRate = psEnc->sCmn.TargetRate_bps; + encStatus->packetLossPercentage = psEnc->sCmn.PacketLoss_perc; + encStatus->complexity = psEnc->sCmn.Complexity; + encStatus->useInBandFEC = psEnc->sCmn.useInBandFEC; + encStatus->useDTX = psEnc->sCmn.useDTX; + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitEncoder( + void *encState, /* I/O: State */ + SKP_Silk_EncodeControlStruct *encStatus /* O: Control structure */ +) +{ + SKP_Silk_encoder_state_FLP *psEnc; + SKP_int ret = 0; + + + psEnc = ( SKP_Silk_encoder_state_FLP* )encState; + + /* Reset Encoder */ + if( ret += SKP_Silk_init_encoder_FLP( psEnc ) ) { + SKP_assert( 0 ); + } + + /* Read control structure */ + if( ret += SKP_Silk_SDK_QueryEncoder( encState, encStatus ) ) { + SKP_assert( 0 ); + } + + + return ret; +} + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +SKP_int SKP_Silk_SDK_Encode( + void *encState, /* I/O: State */ + const SKP_Silk_EncodeControlStruct *encControl, /* I: Control structure */ + const SKP_int16 *samplesIn, /* I: Speech sample input vector */ + SKP_int nSamplesIn, /* I: Number of samples in input vector */ + SKP_uint8 *outData, /* O: Encoded output vector */ + SKP_int16 *nBytesOut /* I/O: Number of bytes in outData (input: Max bytes) */ +) +{ + SKP_int max_internal_fs_kHz, PacketSize_ms, PacketLoss_perc, UseInBandFEC, UseDTX, ret = 0; + SKP_int nSamplesToBuffer, Complexity, input_10ms, nSamplesFromInput = 0; + SKP_int32 TargetRate_bps, API_fs_Hz; + SKP_int16 MaxBytesOut; + SKP_Silk_encoder_state_FLP *psEnc = ( SKP_Silk_encoder_state_FLP* )encState; + + SKP_assert( encControl != NULL ); + + /* Check sampling frequency first, to avoid divide by zero later */ + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) && + ( encControl->maxInternalSampleRate != 24000 ) ) ) { + ret = SKP_SILK_ENC_FS_NOT_SUPPORTED; + SKP_assert( 0 ); + return( ret ); + } + + /* Set encoder parameters from control structure */ + API_fs_Hz = encControl->API_sampleRate; + max_internal_fs_kHz = (SKP_int)( encControl->maxInternalSampleRate >> 10 ) + 1; /* convert Hz -> kHz */ + PacketSize_ms = SKP_DIV32( 1000 * (SKP_int)encControl->packetSize, API_fs_Hz ); + TargetRate_bps = encControl->bitRate; + PacketLoss_perc = encControl->packetLossPercentage; + UseInBandFEC = encControl->useInBandFEC; + Complexity = encControl->complexity; + UseDTX = encControl->useDTX; + + /* Save values in state */ + psEnc->sCmn.API_fs_Hz = API_fs_Hz; + psEnc->sCmn.maxInternal_fs_kHz = max_internal_fs_kHz; + psEnc->sCmn.useInBandFEC = UseInBandFEC; + + /* Only accept input lengths that are a multiple of 10 ms */ + input_10ms = SKP_DIV32( 100 * nSamplesIn, API_fs_Hz ); + if( input_10ms * API_fs_Hz != 100 * nSamplesIn || nSamplesIn < 0 ) { + ret = SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + SKP_assert( 0 ); + return( ret ); + } + + TargetRate_bps = SKP_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS ); + if( ( ret = SKP_Silk_control_encoder_FLP( psEnc, PacketSize_ms, TargetRate_bps, + PacketLoss_perc, UseDTX, Complexity) ) != 0 ) { + SKP_assert( 0 ); + return( ret ); + } + + /* Make sure no more than one packet can be produced */ + if( 1000 * (SKP_int32)nSamplesIn > psEnc->sCmn.PacketSize_ms * API_fs_Hz ) { + ret = SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + SKP_assert( 0 ); + return( ret ); + } + +#if MAX_FS_KHZ > 16 + /* Detect energy above 8 kHz */ + if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 && + psEnc->sCmn.sSWBdetect.SWB_detected == 0 && + psEnc->sCmn.sSWBdetect.WB_detected == 0 ) { + SKP_Silk_detect_SWB_input( &psEnc->sCmn.sSWBdetect, samplesIn, ( SKP_int )nSamplesIn ); + } +#endif + + /* Input buffering/resampling and encoding */ + MaxBytesOut = 0; /* return 0 output bytes if no encoder called */ + while( 1 ) { + nSamplesToBuffer = psEnc->sCmn.frame_length - psEnc->sCmn.inputBufIx; + if( API_fs_Hz == SKP_SMULBB( 1000, psEnc->sCmn.fs_kHz ) ) { + nSamplesToBuffer = SKP_min_int( nSamplesToBuffer, nSamplesIn ); + nSamplesFromInput = nSamplesToBuffer; + /* Copy to buffer */ + SKP_memcpy( &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput * sizeof( SKP_int16 ) ); + } else { + nSamplesToBuffer = SKP_min( nSamplesToBuffer, 10 * input_10ms * psEnc->sCmn.fs_kHz ); + nSamplesFromInput = SKP_DIV32_16( nSamplesToBuffer * API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state, + &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput ); + } + samplesIn += nSamplesFromInput; + nSamplesIn -= nSamplesFromInput; + psEnc->sCmn.inputBufIx += nSamplesToBuffer; + + /* Silk encoder */ + if( psEnc->sCmn.inputBufIx >= psEnc->sCmn.frame_length ) { + SKP_assert( psEnc->sCmn.inputBufIx == psEnc->sCmn.frame_length ); + + /* Enough data in input buffer, so encode */ + if( MaxBytesOut == 0 ) { + /* No payload obtained so far */ + MaxBytesOut = *nBytesOut; + if( ( ret = SKP_Silk_encode_frame_FLP( psEnc, outData, &MaxBytesOut, psEnc->sCmn.inputBuf ) ) != 0 ) { + SKP_assert( 0 ); + } + } else { + /* outData already contains a payload */ + if( ( ret = SKP_Silk_encode_frame_FLP( psEnc, outData, nBytesOut, psEnc->sCmn.inputBuf ) ) != 0 ) { + SKP_assert( 0 ); + } + /* Check that no second payload was created */ + SKP_assert( *nBytesOut == 0 ); + } + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.controlled_since_last_payload = 0; + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + } + + *nBytesOut = MaxBytesOut; + if( psEnc->sCmn.useDTX && psEnc->sCmn.inDTX ) { + /* DTX simulation */ + *nBytesOut = 0; + } + + + + return ret; +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_frame_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_frame_FLP.c new file mode 100755 index 0000000..04f122c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_frame_FLP.c @@ -0,0 +1,398 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +/****************/ +/* Encode frame */ +/****************/ +SKP_int SKP_Silk_encode_frame_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_uint8 *pCode, /* O Payload */ + SKP_int16 *pnBytesOut, /* I/O Number of payload bytes; */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Input speech frame */ +) +{ + SKP_Silk_encoder_control_FLP sEncCtrl; + SKP_int k, nBytes, ret = 0; + SKP_float *x_frame, *res_pitch_frame; + SKP_int16 pIn_HP[ MAX_FRAME_LENGTH ]; + SKP_int16 pIn_HP_LP[ MAX_FRAME_LENGTH ]; + SKP_float xfw[ MAX_FRAME_LENGTH ]; + SKP_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + SKP_int LBRR_idx, frame_terminator; + + /* Low bitrate redundancy parameters */ + SKP_uint8 LBRRpayload[ MAX_ARITHM_BYTES ]; + SKP_int16 nBytesLBRR; + + const SKP_uint16 *FrameTermination_CDF; + + + sEncCtrl.sCmn.Seed = psEnc->sCmn.frameCounter++ & 3; + /**************************************************************/ + /* Setup Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.frame_length; // start of frame to encode + res_pitch_frame = res_pitch + psEnc->sCmn.frame_length; // start of pitch LPC residual frame + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + SKP_Silk_VAD_FLP( psEnc, &sEncCtrl, pIn ); + + /*******************************************/ + /* High-pass filtering of the input signal */ + /*******************************************/ +#if HIGH_PASS_INPUT + /* Variable high-pass filter */ + SKP_Silk_HP_variable_cutoff_FLP( psEnc, &sEncCtrl, pIn_HP, pIn ); +#else + SKP_memcpy( pIn_HP, pIn, psEnc->sCmn.frame_length * sizeof( SKP_int16 ) ); +#endif + +#if SWITCH_TRANSITION_FILTERING + /* Ensure smooth bandwidth transitions */ + SKP_Silk_LP_variable_cutoff( &psEnc->sCmn.sLP, pIn_HP_LP, pIn_HP, psEnc->sCmn.frame_length ); +#else + SKP_memcpy( pIn_HP_LP, pIn_HP, psEnc->sCmn.frame_length * sizeof( SKP_int16 ) ); +#endif + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + SKP_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, pIn_HP_LP, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( k = 0; k < 8; k++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + k * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( k & 2 ) ) * 1e-6f; + } + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + SKP_Silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + SKP_Silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + SKP_Silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + SKP_Silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch ); + + /****************************************/ + /* Process gains */ + /****************************************/ + SKP_Silk_process_gains_FLP( psEnc, &sEncCtrl ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + nBytesLBRR = MAX_ARITHM_BYTES; + SKP_Silk_LBRR_encode_FLP( psEnc, &sEncCtrl, LBRRpayload, &nBytesLBRR, xfw ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + SKP_Silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, xfw, psEnc->sCmn.q, 0 ); + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->speech_activity < SPEECH_ACTIVITY_DTX_THRES ) { + psEnc->sCmn.vadFlag = NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter > NO_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 1; + } + if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NO_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NO_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.vadFlag = VOICE_ACTIVITY; + } + + /****************************************/ + /* Initialize range coder */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + SKP_Silk_range_enc_init( &psEnc->sCmn.sRC ); + psEnc->sCmn.nBytesInPayloadBuf = 0; + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + SKP_Silk_encode_parameters( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sRC, psEnc->sCmn.q ); + FrameTermination_CDF = SKP_Silk_FrameTermination_CDF; + + /****************************************/ + /* Update Buffers and State */ + /****************************************/ + /* Update input buffer */ + SKP_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.frame_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( SKP_float ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prev_sigtype = sEncCtrl.sCmn.sigtype; + psEnc->sCmn.prevLag = sEncCtrl.sCmn.pitchL[ NB_SUBFR - 1]; + psEnc->sCmn.first_frame_after_reset = 0; + + if( psEnc->sCmn.sRC.error ) { + /* Encoder returned error: Clear payload buffer */ + psEnc->sCmn.nFramesInPayloadBuf = 0; + } else { + psEnc->sCmn.nFramesInPayloadBuf++; + } + + /****************************************/ + /* Finalize payload and copy to output */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf * FRAME_LENGTH_MS >= psEnc->sCmn.PacketSize_ms ) { + + LBRR_idx = ( psEnc->sCmn.oldest_LBRR_idx + 1 ) & LBRR_IDX_MASK; + + /* Check if FEC information should be added */ + frame_terminator = SKP_SILK_LAST_FRAME; + if( psEnc->sCmn.LBRR_buffer[ LBRR_idx ].usage == SKP_SILK_ADD_LBRR_TO_PLUS1 ) { + frame_terminator = SKP_SILK_LBRR_VER1; + } + if( psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].usage == SKP_SILK_ADD_LBRR_TO_PLUS2 ) { + frame_terminator = SKP_SILK_LBRR_VER2; + LBRR_idx = psEnc->sCmn.oldest_LBRR_idx; + } + + /* Add the frame termination info to stream */ + SKP_Silk_range_encoder( &psEnc->sCmn.sRC, frame_terminator, FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC, &nBytes ); + + /* Check that there is enough space in external output buffer, and move data */ + if( *pnBytesOut >= nBytes ) { + SKP_Silk_range_enc_wrap_up( &psEnc->sCmn.sRC ); + SKP_memcpy( pCode, psEnc->sCmn.sRC.buffer, nBytes * sizeof( SKP_uint8 ) ); + + if( frame_terminator > SKP_SILK_MORE_FRAMES && + *pnBytesOut >= nBytes + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes ) { + /* Get old packet and add to payload. */ + SKP_memcpy( &pCode[ nBytes ], + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].payload, + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes * sizeof( SKP_uint8 ) ); + nBytes += psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes; + } + *pnBytesOut = nBytes; + + /* Update FEC buffer */ + SKP_memcpy( psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].payload, LBRRpayload, + nBytesLBRR * sizeof( SKP_uint8 ) ); + psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].nBytes = nBytesLBRR; + /* The line below describes how FEC should be used */ + psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].usage = sEncCtrl.sCmn.LBRR_usage; + psEnc->sCmn.oldest_LBRR_idx = ( ( psEnc->sCmn.oldest_LBRR_idx + 1 ) & LBRR_IDX_MASK ); + + } else { + /* Not enough space: Payload will be discarded */ + *pnBytesOut = 0; + nBytes = 0; + ret = SKP_SILK_ENC_PAYLOAD_BUF_TOO_SHORT; + } + + /* Reset the number of frames in payload buffer */ + psEnc->sCmn.nFramesInPayloadBuf = 0; + } else { + /* No payload this time */ + *pnBytesOut = 0; + + /* Encode that more frames follows */ + frame_terminator = SKP_SILK_MORE_FRAMES; + SKP_Silk_range_encoder( &psEnc->sCmn.sRC, frame_terminator, FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC, &nBytes ); + } + + /* Check for arithmetic coder errors */ + if( psEnc->sCmn.sRC.error ) { + ret = SKP_SILK_ENC_INTERNAL_ERROR; + } + + /* Simulate number of ms buffered in channel because of exceeding TargetRate */ + psEnc->BufferedInChannel_ms += ( 8.0f * 1000.0f * ( nBytes - psEnc->sCmn.nBytesInPayloadBuf ) ) / psEnc->sCmn.TargetRate_bps; + psEnc->BufferedInChannel_ms -= FRAME_LENGTH_MS; + psEnc->BufferedInChannel_ms = SKP_LIMIT_float( psEnc->BufferedInChannel_ms, 0.0f, 100.0f ); + psEnc->sCmn.nBytesInPayloadBuf = nBytes; + + if( psEnc->speech_activity > WB_DETECT_ACTIVE_SPEECH_LEVEL_THRES ) { + psEnc->sCmn.sSWBdetect.ActiveSpeech_ms = SKP_ADD_POS_SAT32( psEnc->sCmn.sSWBdetect.ActiveSpeech_ms, FRAME_LENGTH_MS ); + } + + return( ret ); +} + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +void SKP_Silk_LBRR_encode_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_uint8 *pCode, /* O Payload */ + SKP_int16 *pnBytesOut, /* I/O Payload bytes; in: max; out: used */ + const SKP_float xfw[] /* I Input signal */ +) +{ + SKP_int32 Gains_Q16[ NB_SUBFR ]; + SKP_int k, TempGainsIndices[ NB_SUBFR ], frame_terminator; + SKP_int nBytes, nFramesInPayloadBuf; + SKP_float TempGains[ NB_SUBFR ]; + SKP_int typeOffset, LTP_scaleIndex, Rate_only_parameters = 0; + + /* Control use of inband LBRR */ + SKP_Silk_LBRR_ctrl_FLP( psEnc, &psEncCtrl->sCmn ); + + if( psEnc->sCmn.LBRR_enabled ) { + /* Save original gains */ + SKP_memcpy( TempGainsIndices, psEncCtrl->sCmn.GainsIndices, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memcpy( TempGains, psEncCtrl->Gains, NB_SUBFR * sizeof( SKP_float ) ); + + typeOffset = psEnc->sCmn.typeOffsetPrev; // Temp save as cannot be overwritten + LTP_scaleIndex = psEncCtrl->sCmn.LTP_scaleIndex; + + /* Set max rate where quant signal is encoded */ + if( psEnc->sCmn.fs_kHz == 8 ) { + Rate_only_parameters = 13500; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + Rate_only_parameters = 15500; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + Rate_only_parameters = 17500; + } else if( psEnc->sCmn.fs_kHz == 24 ) { + Rate_only_parameters = 19500; + } else { + SKP_assert( 0 ); + } + + if( psEnc->sCmn.Complexity > 0 && psEnc->sCmn.TargetRate_bps > Rate_only_parameters ) { + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + /* First frame in packet copy everything */ + SKP_memcpy( &psEnc->sCmn.sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( SKP_Silk_nsq_state ) ); + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + /* Increase Gains to get target LBRR rate */ + psEncCtrl->sCmn.GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psEncCtrl->sCmn.GainsIndices[ 0 ] = SKP_LIMIT_int( psEncCtrl->sCmn.GainsIndices[ 0 ], 0, N_LEVELS_QGAIN - 1 ); + } + /* Decode to get gains in sync with decoder */ + SKP_Silk_gains_dequant( Gains_Q16, psEncCtrl->sCmn.GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] / 65536.0f; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + SKP_Silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, xfw, psEnc->sCmn.q_LBRR, 1 ); + } else { + SKP_memset( psEnc->sCmn.q_LBRR, 0, psEnc->sCmn.frame_length * sizeof( SKP_int8 ) ); + psEncCtrl->sCmn.LTP_scaleIndex = 0; + } + /****************************************/ + /* Initialize arithmetic coder */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + SKP_Silk_range_enc_init( &psEnc->sCmn.sRC_LBRR ); + psEnc->sCmn.nBytesInPayloadBuf = 0; + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + SKP_Silk_encode_parameters( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sRC_LBRR, psEnc->sCmn.q_LBRR ); + + if( psEnc->sCmn.sRC_LBRR.error ) { + /* Encoder returned error: Clear payload buffer */ + nFramesInPayloadBuf = 0; + } else { + nFramesInPayloadBuf = psEnc->sCmn.nFramesInPayloadBuf + 1; + } + + /****************************************/ + /* Finalize payload and copy to output */ + /****************************************/ + if( nFramesInPayloadBuf * FRAME_LENGTH_MS >= psEnc->sCmn.PacketSize_ms ) { + + /* Check if FEC information should be added */ + frame_terminator = SKP_SILK_LAST_FRAME; + + /* Add the frame termination info to stream */ + SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC_LBRR, &nBytes ); + + /* Check that there is enough space in external output buffer and move data */ + if( *pnBytesOut >= nBytes ) { + SKP_Silk_range_enc_wrap_up( &psEnc->sCmn.sRC_LBRR ); + SKP_memcpy( pCode, psEnc->sCmn.sRC_LBRR.buffer, nBytes * sizeof( SKP_uint8 ) ); + + *pnBytesOut = nBytes; + } else { + /* Not enough space: Payload will be discarded */ + *pnBytesOut = 0; + SKP_assert( 0 ); + } + } else { + /* No payload this time */ + *pnBytesOut = 0; + + /* Encode that more frames follows */ + frame_terminator = SKP_SILK_MORE_FRAMES; + SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF ); + } + + /* Restore original Gains */ + SKP_memcpy( psEncCtrl->sCmn.GainsIndices, TempGainsIndices, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memcpy( psEncCtrl->Gains, TempGains, NB_SUBFR * sizeof( SKP_float ) ); + + /* Restore LTP scale index and typeoffset */ + psEncCtrl->sCmn.LTP_scaleIndex = LTP_scaleIndex; + psEnc->sCmn.typeOffsetPrev = typeOffset; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_parameters.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_parameters.c new file mode 100755 index 0000000..8ed0802 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_parameters.c @@ -0,0 +1,162 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*******************************************/ +/* Encode parameters to create the payload */ +/*******************************************/ +void SKP_Silk_encode_parameters( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder state */ + SKP_Silk_encoder_control *psEncCtrlC, /* I/O Encoder control */ + SKP_Silk_range_coder_state *psRC, /* I/O Range encoder state */ + const SKP_int8 *q /* I Quantization indices */ +) +{ + SKP_int i, k, typeOffset; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB; + + + /************************/ + /* Encode sampling rate */ + /************************/ + /* only done for first frame in packet */ + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* get sampling rate index */ + for( i = 0; i < 3; i++ ) { + if( SKP_Silk_SamplingRates_table[ i ] == psEncC->fs_kHz ) { + break; + } + } + SKP_Silk_range_encoder( psRC, i, SKP_Silk_SamplingRates_CDF ); + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psEncCtrlC->sigtype + psEncCtrlC->QuantOffsetType; + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_encoder( psRC, typeOffset, SKP_Silk_type_offset_CDF ); + } else { + /* condidtional coding */ + SKP_Silk_range_encoder( psRC, typeOffset, SKP_Silk_type_offset_joint_CDF[ psEncC->typeOffsetPrev ] ); + } + psEncC->typeOffsetPrev = typeOffset; + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ 0 ], SKP_Silk_gain_CDF[ psEncCtrlC->sigtype ] ); + } else { + /* condidtional coding */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ 0 ], SKP_Silk_delta_gain_CDF ); + } + + /* remaining subframes */ + for( i = 1; i < NB_SUBFR; i++ ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ i ], SKP_Silk_delta_gain_CDF ); + } + + + /****************/ + /* Encode NLSFs */ + /****************/ + /* Range encoding of the NLSF path */ + psNLSF_CB = psEncC->psNLSF_CB[ psEncCtrlC->sigtype ]; + SKP_Silk_range_encoder_multi( psRC, psEncCtrlC->NLSFIndices, psNLSF_CB->StartPtr, psNLSF_CB->nStages ); + + /* Encode NLSF interpolation factor */ + SKP_assert( psEncC->useInterpolatedNLSFs == 1 || psEncCtrlC->NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + SKP_Silk_range_encoder( psRC, psEncCtrlC->NLSFInterpCoef_Q2, SKP_Silk_NLSF_interpolation_factor_CDF ); + + + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /*********************/ + /* Encode pitch lags */ + /*********************/ + + + /* lag index */ + if( psEncC->fs_kHz == 8 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_NB_CDF ); + } else if( psEncC->fs_kHz == 12 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_MB_CDF ); + } else if( psEncC->fs_kHz == 16 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_WB_CDF ); + } else { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_SWB_CDF ); + } + + + /* countour index */ + if( psEncC->fs_kHz == 8 ) { + /* Less codevectors used in 8 khz mode */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->contourIndex, SKP_Silk_pitch_contour_NB_CDF ); + } else { + /* Joint for 12, 16, 24 khz */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->contourIndex, SKP_Silk_pitch_contour_CDF ); + } + + /********************/ + /* Encode LTP gains */ + /********************/ + + /* PERIndex value */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->PERIndex, SKP_Silk_LTP_per_index_CDF ); + + /* Codebook Indices */ + for( k = 0; k < NB_SUBFR; k++ ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->LTPIndex[ k ], SKP_Silk_LTP_gain_CDF_ptrs[ psEncCtrlC->PERIndex ] ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + SKP_Silk_range_encoder( psRC, psEncCtrlC->LTP_scaleIndex, SKP_Silk_LTPscale_CDF ); + } + + + /***************/ + /* Encode seed */ + /***************/ + SKP_Silk_range_encoder( psRC, psEncCtrlC->Seed, SKP_Silk_Seed_CDF ); + + /*********************************************/ + /* Encode quantization indices of excitation */ + /*********************************************/ + SKP_Silk_encode_pulses( psRC, psEncCtrlC->sigtype, psEncCtrlC->QuantOffsetType, q, psEncC->frame_length ); + + + /*********************************************/ + /* Encode VAD flag */ + /*********************************************/ + SKP_Silk_range_encoder( psRC, psEncC->vadFlag, SKP_Silk_vadflag_CDF ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_pulses.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_pulses.c new file mode 100755 index 0000000..3a711e8 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_encode_pulses.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +SKP_INLINE SKP_int combine_and_check( /* return ok */ + SKP_int *pulses_comb, /* O */ + const SKP_int *pulses_in, /* I */ + SKP_int max_pulses, /* I max value for sum of pulses */ + SKP_int len /* I number of output values */ +) +{ + SKP_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void SKP_Silk_encode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int sigtype, /* I Sigtype */ + const SKP_int QuantOffsetType,/* I QuantOffsetType */ + const SKP_int8 q[], /* I quantization indices */ + const SKP_int frame_length /* I Frame length */ +) +{ + SKP_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + SKP_int32 abs_q, minSumBits_Q6, sumBits_Q6; + SKP_int abs_pulses[ MAX_FRAME_LENGTH ]; + SKP_int sum_pulses[ MAX_NB_SHELL_BLOCKS ]; + SKP_int nRshifts[ MAX_NB_SHELL_BLOCKS ]; + SKP_int pulses_comb[ 8 ]; + SKP_int *abs_pulses_ptr; + const SKP_int8 *pulses_ptr; + const SKP_uint16 *cdf_ptr; + const SKP_int16 *nBits_ptr; + + SKP_memset( pulses_comb, 0, 8 * sizeof( SKP_int ) ); // Fixing Valgrind reported problem + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + iter = frame_length / SHELL_CODEC_FRAME_LENGTH; + + /* Take the absolute value of the pulses */ + for( i = 0; i < frame_length; i+=4 ) { + abs_pulses[i+0] = ( SKP_int )SKP_abs( q[ i + 0 ] ); + abs_pulses[i+1] = ( SKP_int )SKP_abs( q[ i + 1 ] ); + abs_pulses[i+2] = ( SKP_int )SKP_abs( q[ i + 2 ] ); + abs_pulses[i+3] = ( SKP_int )SKP_abs( q[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, SKP_Silk_max_pulses_table[ 0 ], 8 ); + + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, SKP_Silk_max_pulses_table[ 1 ], 4 ); + + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, SKP_Silk_max_pulses_table[ 2 ], 2 ); + + /* 8+8 -> 16 */ + sum_pulses[ i ] = pulses_comb[ 0 ] + pulses_comb[ 1 ]; + if( sum_pulses[ i ] > SKP_Silk_max_pulses_table[ 3 ] ) { + scale_down++; + } + + if( scale_down ) { + /* We need to down scale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = SKP_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q6 = SKP_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = SKP_Silk_pulses_per_block_BITS_Q6[ k ]; + sumBits_Q6 = SKP_Silk_rate_levels_BITS_Q6[sigtype][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q6 += nBits_ptr[ MAX_PULSES + 1 ]; + } else { + sumBits_Q6 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q6 < minSumBits_Q6 ) { + minSumBits_Q6 = sumBits_Q6; + RateLevelIndex = k; + } + } + SKP_Silk_range_encoder( psRC, RateLevelIndex, SKP_Silk_rate_levels_CDF[ sigtype ] ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = SKP_Silk_pulses_per_block_CDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + SKP_Silk_range_encoder( psRC, sum_pulses[ i ], cdf_ptr ); + } else { + SKP_Silk_range_encoder( psRC, MAX_PULSES + 1, cdf_ptr ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + SKP_Silk_range_encoder( psRC, MAX_PULSES + 1, SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ] ); + } + SKP_Silk_range_encoder( psRC, sum_pulses[ i ], SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ] ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + SKP_Silk_shell_encoder( psRC, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &q[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (SKP_int8)SKP_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = SKP_RSHIFT( abs_q, j ) & 1; + SKP_Silk_range_encoder( psRC, bit, SKP_Silk_lsb_CDF ); + } + bit = abs_q & 1; + SKP_Silk_range_encoder( psRC, bit, SKP_Silk_lsb_CDF ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + SKP_Silk_encode_signs( psRC, q, frame_length, sigtype, QuantOffsetType, RateLevelIndex ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_energy_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_energy_FLP.c new file mode 100755 index 0000000..071249a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_energy_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* sum of squares of a SKP_float array, with result as double */ +double SKP_Silk_energy_FLP( + const SKP_float *data, + SKP_int dataSize +) +{ + SKP_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0f; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data[ i + 0 ] * data[ i + 0 ] + + data[ i + 1 ] * data[ i + 1 ] + + data[ i + 2 ] * data[ i + 2 ] + + data[ i + 3 ] * data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * data[ i ]; + } + + SKP_assert( result >= 0.0 ); + return result; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LPC_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LPC_FLP.c new file mode 100755 index 0000000..4db1957 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LPC_FLP.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +void SKP_Silk_find_LPC_FLP( + SKP_float NLSF[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interp. index for NLSF interp. */ + const SKP_float prev_NLSFq[], /* I Previous NLSFs, for NLSF interpolation */ + const SKP_int useInterpNLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_float x[], /* I Input signal */ + const SKP_int subfr_length /* I Subframe length incl preceeding samples */ +) +{ + SKP_int k; + SKP_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + double res_nrg, res_nrg_2nd, res_nrg_interp; + SKP_float a_tmp[ MAX_LPC_ORDER ], NLSF0[ MAX_LPC_ORDER ]; + SKP_float LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + /* Default: No interpolation */ + *interpIndex = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = SKP_Silk_burg_modified_FLP( a, x, subfr_length, NB_SUBFR, FIND_LPC_COND_FAC, LPC_order ); + + SKP_Silk_bwexpander_FLP( a, LPC_order, FIND_LPC_CHIRP ); + + if( useInterpNLSFs == 1 ) { + + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= SKP_Silk_burg_modified_FLP( a_tmp, x + ( NB_SUBFR / 2 ) * subfr_length, + subfr_length, NB_SUBFR / 2, FIND_LPC_COND_FAC, LPC_order ); + + SKP_Silk_bwexpander_FLP( a_tmp, LPC_order, FIND_LPC_CHIRP ); + + /* Convert to NLSFs */ + SKP_Silk_A2NLSF_FLP( NLSF, a_tmp, LPC_order ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = SKP_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + SKP_Silk_interpolate_wrapper_FLP( NLSF0, prev_NLSFq, NLSF, 0.25f * k, LPC_order ); + + /* Convert to LPC for residual energy evaluation */ + SKP_Silk_NLSF2A_stable_FLP( a_tmp, NLSF0, LPC_order ); + + /* Calculate residual energy with LSF interpolation */ + SKP_Silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, LPC_order ); + res_nrg_interp = + SKP_Silk_energy_FLP( LPC_res + LPC_order, subfr_length - LPC_order ) + + SKP_Silk_energy_FLP( LPC_res + LPC_order + subfr_length, subfr_length - LPC_order ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + *interpIndex = k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( *interpIndex == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + SKP_Silk_A2NLSF_FLP( NLSF, a, LPC_order ); + } + +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LTP_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LTP_FLP.c new file mode 100755 index 0000000..9d88eb4 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_LTP_FLP.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +void SKP_Silk_find_LTP_FLP( + SKP_float b[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_float WLTP[NB_SUBFR*LTP_ORDER*LTP_ORDER], /* O Weight for LTP quantization */ + SKP_float *LTPredCodGain, /* O LTP coding gain */ + const SKP_float r_first[], /* I LPC residual, signal + state for 10 ms */ + const SKP_float r_last[], /* I LPC residual, signal + state for 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_float Wght[ NB_SUBFR ], /* I Weights */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int mem_offset /* I Number of samples in LTP memory */ +) +{ + SKP_int i, k; + SKP_float *b_ptr, temp, *WLTP_ptr; + SKP_float LPC_res_nrg, LPC_LTP_res_nrg; + SKP_float d[ NB_SUBFR ], m, g, delta_b[ LTP_ORDER ]; + SKP_float w[ NB_SUBFR ], nrg[ NB_SUBFR ], regu; + SKP_float Rr[ LTP_ORDER ], rr[ NB_SUBFR ]; + const SKP_float *r_ptr, *lag_ptr; + + b_ptr = b; + WLTP_ptr = WLTP; + r_ptr = &r_first[ mem_offset ]; + for( k = 0; k < NB_SUBFR; k++ ) { + if( k == ( NB_SUBFR >> 1 ) ) { /* Shift residual for last 10 ms */ + r_ptr = &r_last[ mem_offset ]; + } + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + SKP_Silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr ); + SKP_Silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr ); + + rr[ k ] = ( SKP_float )SKP_Silk_energy_FLP( r_ptr, subfr_length ); + regu = 1.0f + rr[ k ] + + matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) + + matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ); + regu *= LTP_DAMPING / 3; + SKP_Silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER ); + SKP_Silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = SKP_Silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER ); + + temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); + SKP_Silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER ); + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER ); + + r_ptr += subfr_length; + b_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Compute LTP coding gain */ + if( LTPredCodGain != NULL ) { + LPC_LTP_res_nrg = 1e-6f; + LPC_res_nrg = 0.0f; + for( k = 0; k < NB_SUBFR; k++ ) { + LPC_res_nrg += rr[ k ] * Wght[ k ]; + LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ]; + } + + SKP_assert( LPC_LTP_res_nrg > 0 ); + *LTPredCodGain = 3.0f * SKP_Silk_log2( LPC_res_nrg / LPC_LTP_res_nrg ); + } + + /* Smoothing */ + /* d = sum( B, 1 ); */ + b_ptr = b; + for( k = 0; k < NB_SUBFR; k++ ) { + d[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d[ k ] += b_ptr[ i ]; + } + b_ptr += LTP_ORDER; + } + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + temp = 1e-3f; + for( k = 0; k < NB_SUBFR; k++ ) { + temp += w[ k ]; + } + m = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + m += d[ k ] * w[ k ]; + } + m = m / temp; + + b_ptr = b; + for( k = 0; k < NB_SUBFR; k++ ) { + g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] ); + temp = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b[ i ] = SKP_max_float( b_ptr[ i ], 0.1f ); + temp += delta_b[ i ]; + } + temp = g / temp; + for( i = 0; i < LTP_ORDER; i++ ) { + b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp; + } + b_ptr += LTP_ORDER; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pitch_lags_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pitch_lags_FLP.c new file mode 100755 index 0000000..63447a8 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pitch_lags_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +void SKP_Silk_find_pitch_lags_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_float res[], /* O Residual */ + const SKP_float x[] /* I Speech signal */ +) +{ + SKP_Silk_predict_state_FLP *psPredSt = &psEnc->sPred; + SKP_int buf_len; + SKP_float thrhld, res_nrg; + const SKP_float *x_buf_ptr, *x_buf; + SKP_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + SKP_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + SKP_float *Wsig_ptr; + + /******************************************/ + /* Setup buffer lengths etc based on Fs */ + /******************************************/ + buf_len = 2 * psEnc->sCmn.frame_length + psEnc->sCmn.la_pitch; + + /* Safty check */ + SKP_assert( buf_len >= psPredSt->pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.frame_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psPredSt->pitch_LPC_win_length; + Wsig_ptr = Wsig; + SKP_Silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + SKP_memcpy( Wsig_ptr, x_buf_ptr, ( psPredSt->pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( SKP_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psPredSt->pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psPredSt->pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + SKP_Silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + SKP_Silk_autocorrelation_FLP( auto_corr, Wsig, psPredSt->pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = SKP_Silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / SKP_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + SKP_Silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + SKP_Silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWITH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + SKP_Silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + SKP_memset( res, 0, psEnc->sCmn.pitchEstimationLPCOrder * sizeof( SKP_float ) ); + + /* Threshold for pitch estimator */ + thrhld = 0.45f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->speech_activity; + thrhld += 0.15f * psEnc->sCmn.prev_sigtype; + thrhld -= 0.1f * psEncCtrl->input_tilt; + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + psEncCtrl->sCmn.sigtype = SKP_Silk_pitch_analysis_core_FLP( res, psEncCtrl->sCmn.pitchL, &psEncCtrl->sCmn.lagIndex, + &psEncCtrl->sCmn.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pred_coefs_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pred_coefs_FLP.c new file mode 100755 index 0000000..22a570c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_find_pred_coefs_FLP.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + + +void SKP_Silk_find_pred_coefs_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float res_pitch[] /* I Residual from pitch analysis */ +) +{ + SKP_int i; + SKP_float WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + SKP_float invGains[ NB_SUBFR ], Wght[ NB_SUBFR ]; + SKP_float NLSF[ MAX_LPC_ORDER ]; + const SKP_float *x_ptr; + SKP_float *x_pre_ptr, LPC_in_pre[ NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + + + /* Weighting for weighted least squares */ + for( i = 0; i < NB_SUBFR; i++ ) { + SKP_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + Wght[ i ] = invGains[ i ] * invGains[ i ]; + } + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + SKP_assert( psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->sCmn.pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + SKP_Silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch, + res_pitch + ( psEnc->sCmn.frame_length >> 1 ), psEncCtrl->sCmn.pitchL, Wght, + psEnc->sCmn.subfr_length, psEnc->sCmn.frame_length ); + + + /* Quantize LTP gain parameters */ + SKP_Silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEncCtrl->sCmn.LTPIndex, &psEncCtrl->sCmn.PERIndex, + WLTP, psEnc->mu_LTP, psEnc->sCmn.LTPQuantLowComplexity ); + + /* Control LTP scaling */ + SKP_Silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl ); + + /* Create LTP residual */ + SKP_Silk_LTP_analysis_filter_FLP( LPC_in_pre, psEnc->x_buf + psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder, + psEncCtrl->LTPCoef, psEncCtrl->sCmn.pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = psEnc->x_buf + psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < NB_SUBFR; i++ ) { + SKP_Silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + SKP_memset( psEncCtrl->LTPCoef, 0, NB_SUBFR * LTP_ORDER * sizeof( SKP_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + SKP_Silk_find_LPC_FLP( NLSF, &psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sPred.prev_NLSFq, + psEnc->sCmn.useInterpolatedNLSFs * ( 1 - psEnc->sCmn.first_frame_after_reset ), psEnc->sCmn.predictLPCOrder, + LPC_in_pre, psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + + + /* Quantize LSFs */ + SKP_Silk_process_NLSFs_FLP( psEnc, psEncCtrl, NLSF ); + + /* Calculate residual energy using quantized LPC coefficients */ + SKP_Silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for fluctuation reduction */ + SKP_memcpy( psEnc->sPred.prev_NLSFq, NLSF, psEnc->sCmn.predictLPCOrder * sizeof( SKP_float ) ); + + +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_gain_quant.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_gain_quant.c new file mode 100755 index 0000000..d9c1867 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_gain_quant.c @@ -0,0 +1,94 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void SKP_Silk_gains_quant( + SKP_int ind[ NB_SUBFR ], /* O gain indices */ + SKP_int32 gain_Q16[ NB_SUBFR ], /* I/O gains (quantized out) */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +) +{ + SKP_int k; + + for( k = 0; k < NB_SUBFR; k++ ) { + /* Add half of previous quantization error, convert to log scale, scale, floor() */ + ind[ k ] = SKP_SMULWB( SCALE_Q16, SKP_Silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = SKP_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + ind[ k ] = SKP_max_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = SKP_LIMIT_int( ind[ k ] - *prev_ind, MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + /* Accumulate deltas */ + *prev_ind += ind[ k ]; + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Convert to linear scale and scale */ + gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3968 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void SKP_Silk_gains_dequant( + SKP_int32 gain_Q16[ NB_SUBFR ], /* O quantized gains */ + const SKP_int ind[ NB_SUBFR ], /* I gain indices */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +) +{ + SKP_int k; + + for( k = 0; k < NB_SUBFR; k++ ) { + if( k == 0 && conditional == 0 ) { + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + *prev_ind += ind[ k ] + MIN_DELTA_GAIN_QUANT; + } + + /* Convert to linear scale and scale */ + gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3968 = 31 in Q7 */ + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_init_encoder_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_init_encoder_FLP.c new file mode 100755 index 0000000..ba2fa76 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_init_encoder_FLP.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include +#include "SKP_Silk_main_FLP.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +SKP_int SKP_Silk_init_encoder_FLP( + SKP_Silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +) { + SKP_int ret = 0; + + /* Clear the entire encoder state */ + SKP_memset( psEnc, 0, sizeof( SKP_Silk_encoder_state_FLP ) ); + +#if HIGH_PASS_INPUT + psEnc->variable_HP_smth1 = SKP_Silk_log2( 70.0 ); + psEnc->variable_HP_smth2 = SKP_Silk_log2( 70.0 ); +#endif + + /* Used to deactivate e.g. LSF interpolation and fluctuation reduction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += SKP_Silk_VAD_Init( &psEnc->sCmn.sVAD ); + + /* Initialize NSQ */ + psEnc->sCmn.sNSQ.prev_inv_gain_Q16 = 65536; + psEnc->sCmn.sNSQ_LBRR.prev_inv_gain_Q16 = 65536; + + return( ret ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_inner_product_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_inner_product_FLP.c new file mode 100755 index 0000000..4741d14 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_inner_product_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* inner product of two SKP_float arrays, with result as double */ +double SKP_Silk_inner_product_FLP( /* O result */ + const SKP_float *data1, /* I vector 1 */ + const SKP_float *data2, /* I vector 2 */ + SKP_int dataSize /* I length of vectors */ +) +{ + SKP_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0f; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data1[ i + 0 ] * data2[ i + 0 ] + + data1[ i + 1 ] * data2[ i + 1 ] + + data1[ i + 2 ] * data2[ i + 2 ] + + data1[ i + 3 ] * data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * data2[ i ]; + } + + return result; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_interpolate.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_interpolate.c new file mode 100755 index 0000000..de8ac51 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_interpolate.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Interpolate two vectors */ +void SKP_Silk_interpolate( + SKP_int xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const SKP_int x0[ MAX_LPC_ORDER ], /* I first vector */ + const SKP_int x1[ MAX_LPC_ORDER ], /* I second vector */ + const SKP_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const SKP_int d /* I number of parameters */ +) +{ + SKP_int i; + + SKP_assert( ifact_Q2 >= 0 ); + SKP_assert( ifact_Q2 <= ( 1 << 2 ) ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = ( SKP_int )( ( SKP_int32 )x0[ i ] + SKP_RSHIFT( SKP_MUL( ( SKP_int32 )x1[ i ] - ( SKP_int32 )x0[ i ], ifact_Q2 ), 2 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_k2a_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_k2a_FLP.c new file mode 100755 index 0000000..72f8725 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_k2a_FLP.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_k2a.c * + * * + * step up function, converts reflection coefficients to prediction * + * coefficients * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a_FLP( + SKP_float *A, /* O: prediction coefficients [order] */ + const SKP_float *rc, /* I: reflection coefficients [order] */ + SKP_int32 order /* I: prediction order */ +) +{ + SKP_int k, n; + SKP_float Atmp[ SKP_Silk_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ){ + for( n = 0; n < k; n++ ){ + Atmp[ n ] = A[ n ]; + } + for( n = 0; n < k; n++ ) { + A[ n ] += Atmp[ k - n - 1 ] * rc[ k ]; + } + A[ k ] = -rc[ k ]; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_levinsondurbin_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_levinsondurbin_FLP.c new file mode 100755 index 0000000..b9092da --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_levinsondurbin_FLP.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* Solve the normal equations using the Levinson-Durbin recursion */ +SKP_float SKP_Silk_levinsondurbin_FLP( /* O prediction error energy */ + SKP_float A[], /* O prediction coefficients [order] */ + const SKP_float corr[], /* I input auto-correlations [order + 1] */ + const SKP_int order /* I prediction order */ +) +{ + SKP_int i, mHalf, m; + SKP_float min_nrg, nrg, t, km, Atmp1, Atmp2; + + min_nrg = 1e-12f * corr[ 0 ] + 1e-9f; + nrg = corr[ 0 ]; + nrg = SKP_max_float(min_nrg, nrg); + A[ 0 ] = corr[ 1 ] / nrg; + nrg -= A[ 0 ] * corr[ 1 ]; + nrg = SKP_max_float(min_nrg, nrg); + + for( m = 1; m < order; m++ ) + { + t = corr[ m + 1 ]; + for( i = 0; i < m; i++ ) { + t -= A[ i ] * corr[ m - i ]; + } + + /* reflection coefficient */ + km = t / nrg; + + /* residual energy */ + nrg -= km * t; + nrg = SKP_max_float(min_nrg, nrg); + + mHalf = m >> 1; + for( i = 0; i < mHalf; i++ ) { + Atmp1 = A[ i ]; + Atmp2 = A[ m - i - 1 ]; + A[ m - i - 1 ] -= km * Atmp1; + A[ i ] -= km * Atmp2; + } + if( m & 1 ) { + A[ mHalf ] -= km * A[ mHalf ]; + } + A[ m ] = km; + } + + /* return the residual energy */ + return nrg; +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lin2log.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lin2log.c new file mode 100755 index 0000000..cf30908 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lin2log.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_lin2log.c * + * * + * Convert input to a log scale * + * Approximation of 128 * log2() * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of approx 2^() below) */ +/* Convert input to a log scale */ +SKP_int32 SKP_Silk_lin2log( const SKP_int32 inLin ) /* I: Input in linear scale */ +{ + SKP_int32 lz, frac_Q7; + + SKP_Silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return( SKP_LSHIFT( 31 - lz, 7 ) + SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), 179 ) ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_log2lin.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_log2lin.c new file mode 100755 index 0000000..ee73b2a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_log2lin.c @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_log2lin.c * + * * + * Convert input to a linear scale * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of SKP_Silk_lin2log()) */ +/* Convert input to a linear scale */ +SKP_int32 SKP_Silk_log2lin( const SKP_int32 inLog_Q7 ) /* I: Input on log scale */ +{ + SKP_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return( 0 ); + } else if( inLog_Q7 >= ( 31 << 7 ) ) { + /* Saturate, and prevent wrap-around */ + return( SKP_int32_MAX ); + } + + out = SKP_LSHIFT( 1, SKP_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = SKP_ADD_RSHIFT( out, SKP_MUL( out, SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = SKP_MLA( out, SKP_RSHIFT( out, 7 ), SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_int.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_int.c new file mode 100755 index 0000000..0f29be9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_int.c @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_lowpass_int.c * + * * + * First order low-pass filter, with input as SKP_int32, running at * + * 48 kHz * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* First order low-pass filter, with input as SKP_int32, running at 48 kHz */ +void SKP_Silk_lowpass_int( + const SKP_int32 *in, /* I: Q25 48 kHz signal; length = len */ + SKP_int32 *S, /* I/O: Q25 state; length = 1 */ + SKP_int32 *out, /* O: Q25 48 kHz signal; length = len */ + const SKP_int32 len /* I: Number of samples */ +) +{ + SKP_int k; + SKP_int32 in_tmp, out_tmp, state; + + state = S[ 0 ]; + for( k = len; k > 0; k-- ) { + in_tmp = *in++; + in_tmp -= SKP_RSHIFT( in_tmp, 2 ); /* multiply by 0.75 */ + out_tmp = state + in_tmp; /* zero at nyquist */ + state = in_tmp - SKP_RSHIFT( out_tmp, 1 ); /* pole */ + *out++ = out_tmp; + } + S[ 0 ] = state; +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_short.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_short.c new file mode 100755 index 0000000..ed70dfa --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_lowpass_short.c @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_lowpass_short.c * + * * + * First order low-pass filter, with input as SKP_int16, running at * + * 48 kHz * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + + +/* First order low-pass filter, with input as SKP_int16, running at 48 kHz */ +void SKP_Silk_lowpass_short( + const SKP_int16 *in, /* I: Q15 48 kHz signal; [len] */ + SKP_int32 *S, /* I/O: Q25 state; length = 1 */ + SKP_int32 *out, /* O: Q25 48 kHz signal; [len] */ + const SKP_int32 len /* O: Signal length */ +) +{ + SKP_int k; + SKP_int32 in_tmp, out_tmp, state; + + state = S[ 0 ]; + for( k = 0; k < len; k++ ) { + in_tmp = SKP_MUL( 768, (SKP_int32)in[k] ); /* multiply by 0.75, going from Q15 to Q25 */ + out_tmp = state + in_tmp; /* zero at nyquist */ + state = in_tmp - SKP_RSHIFT( out_tmp, 1 ); /* pole */ + out[ k ] = out_tmp; + } + S[ 0 ] = state; +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_macros.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_macros.h new file mode 100755 index 0000000..c845195 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_macros.h @@ -0,0 +1,125 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef _SKP_SILK_API_C_H_ +#define _SKP_SILK_API_C_H_ + +// This is an inline header file for general platform. + +// (a32 * (SKP_int32)((SKP_int16)(b32))) >> 16 output have to be 32bit int +#define SKP_SMULWB(a32, b32) ((((a32) >> 16) * (SKP_int32)((SKP_int16)(b32))) + ((((a32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(b32))) >> 16)) + +// a32 + (b32 * (SKP_int32)((SKP_int16)(c32))) >> 16 output have to be 32bit int +#define SKP_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (SKP_int32)((SKP_int16)(c32))) + ((((b32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(c32))) >> 16))) + +// (a32 * (b32 >> 16)) >> 16 +#define SKP_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) + +// a32 + (b32 * (c32 >> 16)) >> 16 +#define SKP_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) + +// (SKP_int32)((SKP_int16)(a3))) * (SKP_int32)((SKP_int16)(b32)) output have to be 32bit int +#define SKP_SMULBB(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * (SKP_int32)((SKP_int16)(b32))) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (SKP_int32)((SKP_int16)(c32)) output have to be 32bit int +#define SKP_SMLABB(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * (SKP_int32)((SKP_int16)(c32))) + +// (SKP_int32)((SKP_int16)(a32)) * (b32 >> 16) +#define SKP_SMULBT(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * ((b32) >> 16)) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (c32 >> 16) +#define SKP_SMLABT(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * ((c32) >> 16)) + +// a64 + (b32 * c32) +#define SKP_SMLAL(a64, b32, c32) (SKP_ADD64((a64), ((SKP_int64)(b32) * (SKP_int64)(c32)))) + +// (a32 * b32) >> 16 +#define SKP_SMULWW(a32, b32) SKP_MLA(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)) + +// a32 + ((b32 * c32) >> 16) +#define SKP_SMLAWW(a32, b32, c32) SKP_MLA(SKP_SMLAWB((a32), (b32), (c32)), (b32), SKP_RSHIFT_ROUND((c32), 16)) + +// (SKP_int32)(((SKP_int64)a32 * b32) >> 32) +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + +/* add/subtract with output saturated */ +#define SKP_ADD_SAT32(a, b) ((((a) + (b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? SKP_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? SKP_int32_MAX : (a)+(b)) ) + +#define SKP_SUB_SAT32(a, b) ((((a)-(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? SKP_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? SKP_int32_MAX : (a)-(b)) ) + +SKP_INLINE SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16) +{ + SKP_int32 out32 = 0; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32) +{ + /* test highest 16 bits and convert to SKP_int16 */ + if( in32 & 0xFFFF0000 ) { + return SKP_Silk_CLZ16((SKP_int16)(in32 >> 16)); + } else { + return SKP_Silk_CLZ16((SKP_int16)in32) + 16; + } +} + +#endif //_SKP_SILK_API_C_H_ + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main.h new file mode 100755 index 0000000..fa01317 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main.h @@ -0,0 +1,388 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_MAIN_H +#define SKP_SILK_MAIN_H + +#include "SKP_Silk_SigProc_FIX.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "SKP_Silk_define.h" +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables.h" +#include "SKP_Silk_PLC.h" + + +/* Encodes signs of excitation */ +void SKP_Silk_encode_signs( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int8 q[], /* I pulse signal */ + const SKP_int length, /* I length of input */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +); + +/* Decodes signs of excitation */ +void SKP_Silk_decode_signs( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_int q[], /* I/O pulse signal */ + const SKP_int length, /* I length of output */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +); + +/* Control internal sampling rate */ +SKP_int SKP_Silk_control_audio_bandwidth( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + const SKP_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void SKP_Silk_encode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int sigtype, /* I Sigtype */ + const SKP_int QuantOffsetType, /* I QuantOffsetType */ + const SKP_int8 q[], /* I quantization indices */ + const SKP_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_decoder( + SKP_int *pulses0, /* O data: nonnegative pulse amplitudes */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/***************/ +/* Range coder */ +/***************/ +/* Range encoder for one symbol */ +void SKP_Silk_range_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data, /* I uncompressed data */ + const SKP_uint16 prob[] /* I cumulative density functions */ +); + +/* Range encoder for multiple symbols */ +void SKP_Silk_range_encoder_multi( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data[], /* I uncompressed data [nSymbols] */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int nSymbols /* I number of data symbols */ +); + +/* Range decoder for one symbol */ +void SKP_Silk_range_decoder( + SKP_int data[], /* O uncompressed data */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 prob[], /* I cumulative density function */ + SKP_int probIx /* I initial (middle) entry of cdf */ +); + +/* Range decoder for multiple symbols */ +void SKP_Silk_range_decoder_multi( + SKP_int data[], /* O uncompressed data [nSymbols] */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int probStartIx[], /* I initial (middle) entries of cdfs [nSymbols] */ + const SKP_int nSymbols /* I number of data symbols */ +); + +/* Initialize range coder structure for encoder */ +void SKP_Silk_range_enc_init( + SKP_Silk_range_coder_state *psRC /* O compressor data structure */ +); + +/* Initialize range coder structure for decoder */ +void SKP_Silk_range_dec_init( + SKP_Silk_range_coder_state *psRC, /* O compressor data structure */ + const SKP_uint8 buffer[], /* I buffer for compressed data [bufferLength] */ + const SKP_int32 bufferLength /* I buffer length (in bytes) */ +); + +/* Determine length of bitstream */ +SKP_int SKP_Silk_range_coder_get_length( /* O returns number of BITS in stream */ + const SKP_Silk_range_coder_state *psRC, /* I compressed data structure */ + SKP_int *nBytes /* O number of BYTES in stream */ +); + +/* Write decodable stream to buffer, and determine its length */ +void SKP_Silk_range_enc_wrap_up( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +); + +/* Check that any remaining bits in the last byte are set to 1 */ +void SKP_Silk_range_coder_check_after_decoding( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void SKP_Silk_gains_quant( + SKP_int ind[ NB_SUBFR ], /* O gain indices */ + SKP_int32 gain_Q16[ NB_SUBFR ], /* I/O gains (quantized out) */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void SKP_Silk_gains_dequant( + SKP_int32 gain_Q16[ NB_SUBFR ], /* O quantized gains */ + const SKP_int ind[ NB_SUBFR ], /* I gain indices */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +); + +/* Convert NLSF parameters to stable AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable( + SKP_int16 pAR_Q12[ MAX_LPC_ORDER ], /* O Stabilized AR coefs [LPC_order] */ + const SKP_int pNLSF[ MAX_LPC_ORDER ], /* I NLSF vector [LPC_order] */ + const SKP_int LPC_order /* I LPC/LSF order */ +); + +/* Interpolate two vectors */ +void SKP_Silk_interpolate( + SKP_int xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const SKP_int x0[ MAX_LPC_ORDER ], /* I first vector */ + const SKP_int x1[ MAX_LPC_ORDER ], /* I second vector */ + const SKP_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const SKP_int d /* I number of parameters */ +); + +/***********************************/ +/* Noise shaping quantization (NSQ)*/ +/***********************************/ +void SKP_Silk_NSQ( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I prefiltered input signal */ + SKP_int8 q[], /* O quantized qulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefficients */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I Long term prediction coefficients */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/* Noise shaping using delayed decision */ +void SKP_Silk_NSQ_del_dec( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Prediction coefs */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I LT prediction coefs */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +SKP_int SKP_Silk_VAD_Init( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Silk VAD noise level estimation */ +void SKP_Silk_VAD_GetNoiseLevels( + const SKP_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +SKP_int SKP_Silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD, /* I/O Silk VAD state */ + SKP_int *pSA_Q8, /* O Speech activity level in Q8 */ + SKP_int *pSNR_dB_Q7, /* O SNR for current frame in Q7 */ + SKP_int pQuality_Q15[ VAD_N_BANDS ], /* O Smoothed SNR for each band */ + SKP_int *pTilt_Q15, /* O current frame's frequency tilt */ + const SKP_int16 pIn[], /* I PCM input [framelength] */ + const SKP_int framelength /* I Input frame length */ +); + +/* Detect signal in 8 - 12 khz range */ +void SKP_Silk_detect_SWB_input( + SKP_Silk_detect_SWB_state *psSWBdetect, /* I/O Encoder state */ + const SKP_int16 samplesIn[], /* I Input to encoder */ + SKP_int nSamplesIn /* I Length of input */ +); + +#if SWITCH_TRANSITION_FILTERING +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void SKP_Silk_LP_variable_cutoff( + SKP_Silk_LP_state *psLP, /* I/O LP filter state */ + SKP_int16 *out, /* O Low-pass filtered output signal */ + const SKP_int16 *in, /* I Input signal */ + const SKP_int frame_length /* I Frame length */ +); +#endif + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +SKP_int SKP_Silk_create_decoder( + SKP_Silk_decoder_state **ppsDec /* I/O Decoder state pointer pointer */ +); + +SKP_int SKP_Silk_free_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +SKP_int SKP_Silk_init_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +void SKP_Silk_decoder_set_fs( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state pointer */ + SKP_int fs_kHz /* I Sampling frequency (kHz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +SKP_int SKP_Silk_decode_frame( + SKP_Silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + SKP_int16 pOut[], /* O Pointer to output speech frame */ + SKP_int16 *pN, /* O Pointer to size of output frame */ + const SKP_uint8 pCode[], /* I Pointer to payload */ + const SKP_int nBytes, /* I Payload length */ + SKP_int action, /* I Action from Jitter Buffer */ + SKP_int *decBytes /* O Used bytes to decode this frame */ +); + +/* Decode parameters from payload */ +void SKP_Silk_decode_parameters( + SKP_Silk_decoder_state *psDec, /* I/O State */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int fullDecoding /* I Flag to tell if only arithmetic decoding */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void SKP_Silk_decode_core( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 xq[], /* O Decoded speech */ + const SKP_int q[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +); + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode( + SKP_int *pNLSF_Q15, /* O Pointer to decoded output [LPC_ORDER x 1] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Pointer to NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I Pointer to NLSF indices [nStages x 1] */ + const SKP_int LPC_order /* I LPC order */ +); + +/**********************/ +/* Arithmetic coding */ +/*********************/ + +/* Decode quantization indices of excitation (Shell coding) */ +void SKP_Silk_decode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int frame_length /* I Frame length (preliminary) */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void SKP_Silk_CNG_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void SKP_Silk_CNG( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O Signal */ + SKP_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void SKP_Silk_encode_parameters( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder state */ + SKP_Silk_encoder_control *psEncCtrlC, /* I/O Encoder control */ + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int8 *q /* I Quantization indices */ +); + +/* Extract lowest layer encoding */ +void SKP_Silk_get_low_layer_internal( + const SKP_uint8 *indata, /* I: Encoded input vector */ + const SKP_int16 nBytesIn, /* I: Number of input Bytes */ + SKP_uint8 *Layer0data, /* O: Layer0 payload */ + SKP_int16 *nLayer0Bytes /* O: Number of FEC Bytes */ +); + +/* Resets LBRR buffer, used if packet size changes */ +void SKP_Silk_LBRR_reset( + SKP_Silk_encoder_state *psEncC /* I/O Pointer to Silk encoder state */ +); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main_FLP.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main_FLP.h new file mode 100755 index 0000000..c8bb262 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_main_FLP.h @@ -0,0 +1,433 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_MAIN_FLP_H +#define SKP_SILK_MAIN_FLP_H + +#include "SKP_Silk_SigProc_FLP.h" +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_structs_FLP.h" +#include "SKP_Silk_tables_FLP.h" +#include "SKP_Silk_main.h" + +/* uncomment to compile without SSE optimizations */ +//#undef SKP_USE_SSE + +#ifdef __cplusplus +extern "C" +{ +#endif + +void SKP_Silk_LBRR_ctrl_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I Encoder state FLP */ + SKP_Silk_encoder_control *psEncCtrl /* I/O Encoder control */ +); + +void SKP_Silk_LTP_scale_ctrl_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl /* I/O Encoder control FLP */ +); + +void SKP_Silk_quant_LTP_gains_FLP( + SKP_float B[ NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + SKP_int cbk_index[ NB_SUBFR ], /* O Codebook index */ + SKP_int *periodicity_index, /* O Periodicity index */ + const SKP_float W[ NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error weights */ + const SKP_float mu, /* I Mu value (R/D tradeoff) */ + const SKP_int lowComplexity /* I Flag for low complexity */ +); + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_int16 *out, /* O High-pass filtered output signal */ + const SKP_int16 *in /* I Input signal */ +); + +/* Encoder main function */ +SKP_int SKP_Silk_encode_frame_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_uint8 *pCode, /* O Payload */ + SKP_int16 *pnBytesOut, /* I/O Number of payload bytes; */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Input speech frame */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void SKP_Silk_process_NLSFs_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_float *pNLSF /* I/O NLSFs (quantized output) */ +); + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +void SKP_Silk_LBRR_encode_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_uint8 *pCode, /* O Payload */ + SKP_int16 *pnBytesOut, /* I/O Payload bytes; in: max; out: used */ + const SKP_float xfw[] /* I Input signal */ +); + +/* Initializes the Silk encoder state */ +SKP_int SKP_Silk_init_encoder_FLP( + SKP_Silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +); + +/* Control the Silk encoder */ +SKP_int SKP_Silk_control_encoder_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + const SKP_int PacketSize_ms, /* I Packet length (ms) */ + const SKP_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const SKP_int PacketLoss_perc, /* I Packet loss rate (in percent) */ + const SKP_int DTX_enabled, /* I Enable / disable DTX */ + const SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +); + +/****************/ +/* Prefiltering */ +/****************/ +void SKP_Silk_prefilter_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const SKP_Silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + SKP_float xw[], /* O Weighted signal */ + const SKP_float x[] /* I Speech signal */ +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void SKP_Silk_noise_shape_analysis_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FLP( + SKP_float *corr, /* O Result [order + 1] */ + const SKP_float *input, /* I Input data to correlate */ + const SKP_float warping, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +); + +/**************/ +/* Find pitch */ +/**************/ +void SKP_Silk_find_pitch_lags_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_float res[], /* O Residual */ + const SKP_float x[] /* I Speech signal */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* NLSF vector encoder */ +void SKP_Silk_NLSF_MSVQ_encode_FLP( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_float *pNLSF, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP, /* I Codebook object */ + const SKP_float *pNLSF_q_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_float *pW, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_float NLSF_mu, /* I Rate weight for the RD optimization */ + const SKP_float NLSF_mu_fluc_red, /* I Fluctuation reduction error weight */ + const SKP_int NLSF_MSVQ_Survivors,/* I Max survivors from each stage */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int deactivate_fluc_red /* I Deactivate fluctuation reduction */ +); + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode_FLP( + SKP_float *pNLSF, /* O Decoded output vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP, /* I NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I NLSF indices [ nStages ] */ + const SKP_int LPC_order /* I LPC order used */ +); + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FLP( + SKP_float *pRD, /* O Rate-distortion values [psNLSF_CBS_FLP->nVectors*N] */ + const SKP_Silk_NLSF_CBS_FLP *psNLSF_CBS_FLP, /* I NLSF codebook stage struct */ + const SKP_float *in, /* I Input vectors to be quantized */ + const SKP_float *w, /* I Weight vector */ + const SKP_float *rate_acc, /* I Accumulated rates from previous stage */ + const SKP_float mu, /* I Weight between weighted error and rate */ + const SKP_int N, /* I Number of input vectors to be quantized */ + const SKP_int LPC_order /* I LPC order */ +); + +/* compute weighted quantization errors for LPC_order element input vectors, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FLP( + SKP_float *err, /* O Weighted quantization errors [ N * K ] */ + const SKP_float *in, /* I Input vectors [ N * LPC_order ] */ + const SKP_float *w, /* I Weighting vectors [ N * LPC_order ] */ + const SKP_float *pCB, /* I Codebook vectors [ K * LPC_order ] */ + const SKP_int N, /* I Number of input vectors */ + const SKP_int K, /* I Number of codebook vectors */ + const SKP_int LPC_order /* I LPC order */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_float SKP_Silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const SKP_float *c, /* I Filter coefficients */ + SKP_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const SKP_float *wXx, /* I Weighted correlation vector */ + const SKP_float wxx, /* I Weighted correlation value */ + const SKP_int D /* I Dimension */ +); + +/* Entropy constrained MATRIX-weighted VQ, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FLP( + SKP_int *ind, /* O Index of best codebook vector */ + SKP_float *rate_dist, /* O Best weighted quant. error + mu * rate */ + const SKP_float *in, /* I Input vector to be quantized */ + const SKP_float *W, /* I Weighting matrix */ + const SKP_int16 *cb, /* I Codebook */ + const SKP_int16 *cl_Q6, /* I Code length for each codebook vector */ + const SKP_float mu, /* I Tradeoff between WSSE and rate */ + const SKP_int L /* I Number of vectors in codebook */ +); + +/* Processing of gains */ +void SKP_Silk_process_gains_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl /* I/O Encoder control FLP */ +); + +void SKP_Silk_find_LTP_FLP( + SKP_float b[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_float WLTP[NB_SUBFR*LTP_ORDER*LTP_ORDER], /* O Weight for LTP quantization */ + SKP_float *LTPredCodGain, /* O LTP coding gain */ + const SKP_float r_first[], /* I LPC residual, signal + state for 10 ms */ + const SKP_float r_last[], /* I LPC residual, signal + state for 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_float Wght[ NB_SUBFR ], /* I Weights */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int mem_offset /* I Number of samples in LTP memory */ +); + +void SKP_Silk_find_LPC_FLP( + SKP_float NLSF[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interp. index for NLSF interp. */ + const SKP_float prev_NLSFq[], /* I Previous NLSFs, for NLSF interpolation */ + const SKP_int useInterpNLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_float x[], /* I Input signal */ + const SKP_int subfr_length /* I Subframe length incl preceeding samples */ +); + +void SKP_Silk_LTP_analysis_filter_FLP( + SKP_float *LTP_res, /* O LTP res NB_SUBFR*(pre_lgth+subfr_lngth) */ + const SKP_float *x, /* I Input signal, with preceeding samples */ + const SKP_float B[ LTP_ORDER * NB_SUBFR ], /* I LTP coefficients for each subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I Pitch lags */ + const SKP_float invGains[ NB_SUBFR ], /* I Inverse quantization gains */ + const SKP_int subfr_length, /* I Length of each subframe */ + const SKP_int pre_length /* I Preceeding samples for each subframe */ +); + +void SKP_Silk_residual_energy_FLP( + SKP_float nrgs[ NB_SUBFR ], /* O Residual energy per subframe */ + const SKP_float x[], /* I Input signal */ + SKP_float a[ 2 ][ MAX_LPC_ORDER ],/* I AR coefs for each frame half */ + const SKP_float gains[], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +); + +void SKP_Silk_find_pred_coefs_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float res_pitch[] /* I Residual from pitch analysis */ +); + +/* 16th order LPC analysis filter */ +void SKP_Silk_LPC_analysis_filter_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length, /* I Length of input signal */ + const SKP_int Order /* I LPC order */ +); + +/* 16th order LPC analysis filter, does not write first 16 samples */ +void SKP_Silk_LPC_analysis_filter16_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +); + +/* 12th order LPC analysis filter, does not write first 12 samples */ +void SKP_Silk_LPC_analysis_filter12_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +); + +/* 10th order LPC analysis filter, does not write first 10 samples */ +void SKP_Silk_LPC_analysis_filter10_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +); + +/* 8th order LPC analysis filter, does not write first 8 samples */ +void SKP_Silk_LPC_analysis_filter8_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +); + +/* 6th order LPC analysis filter, does not write first 6 samples */ +void SKP_Silk_LPC_analysis_filter6_FLP( + SKP_float r_LPC[], /* O LPC residual signal */ + const SKP_float PredCoef[], /* I LPC coefficients */ + const SKP_float s[], /* I Input signal */ + const SKP_int length /* I Length of input signal */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FLP( + const SKP_float *x, /* I x vector [ L+order-1 ] used to create X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int Order, /* I Max lag for correlation */ + SKP_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FLP( + const SKP_float *x, /* I x vector [L+order-1] used to create X */ + const SKP_float *t, /* I Target vector [L] */ + const SKP_int L, /* I Length of vecors */ + const SKP_int Order, /* I Max lag for correlation */ + SKP_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Add noise to matrix diagonal */ +void SKP_Silk_regularize_correlations_FLP( + SKP_float *XX, /* I/O Correlation matrices */ + SKP_float *xx, /* I/O Correlation values */ + const SKP_float noise, /* I Noise energy to add */ + const SKP_int D /* I Dimension of XX */ +); + +/* Function to solve linear equation Ax = b, when A is an MxM symmetric square matrix */ +void SKP_Silk_solve_LDL_FLP( + SKP_float *A, /* I/O Symmetric square matrix, out: reg. */ + const SKP_int M, /* I Size of matrix */ + const SKP_float *b, /* I Pointer to b vector */ + SKP_float *x /* O Pointer to x solution vector */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void SKP_Silk_apply_sine_window_FLP( + SKP_float px_win[], /* O Pointer to windowed signal */ + const SKP_float px[], /* I Pointer to input signal */ + const SKP_int win_type, /* I Selects a window type */ + const SKP_int length /* I Window length, multiple of 4 */ +); + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void SKP_Silk_A2NLSF_FLP( + SKP_float *pNLSF, /* O NLSF vector [ LPC_order ] */ + const SKP_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const SKP_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable_FLP( + SKP_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const SKP_float *pNLSF, /* I NLSF vector [ LPC_order ] */ + const SKP_int LPC_order /* I LPC order */ +); + +/* NLSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize_FLP( + SKP_float *pNLSF, /* I/O (Un)stable NLSF vector [ LPC_order ] */ + const SKP_float *pNDelta_min, /* I Normalized delta min vector[LPC_order+1]*/ + const SKP_int LPC_order /* I LPC order */ +); + +/* Interpolation function with fixed point rounding */ +void SKP_Silk_interpolate_wrapper_FLP( + SKP_float xi[], /* O Interpolated vector */ + const SKP_float x0[], /* I First vector */ + const SKP_float x1[], /* I Second vector */ + const SKP_float ifact, /* I Interp. factor, weight on second vector */ + const SKP_int d /* I Number of parameters */ +); + +/****************************************/ +/* Floating-point Silk VAD wrapper */ +/****************************************/ +SKP_int SKP_Silk_VAD_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_int16 *pIn /* I Input signal */ +); + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void SKP_Silk_NSQ_wrapper_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int useLBRR /* I LBRR flag */ +); + +/* using log2() helps the fixed-point conversion */ +SKP_INLINE SKP_float SKP_Silk_log2( double x ) { return ( SKP_float )( 3.32192809488736 * log10( x ) ); } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_noise_shape_analysis_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_noise_shape_analysis_FLP.c new file mode 100755 index 0000000..2208b9e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_noise_shape_analysis_FLP.c @@ -0,0 +1,382 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +SKP_INLINE SKP_float warped_gain( + const SKP_float *coefs, + SKP_float lambda, + SKP_int order +) { + SKP_int i; + SKP_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (SKP_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +SKP_INLINE void warped_true2monic_coefs( + SKP_float *coefs_syn, + SKP_float *coefs_ana, + SKP_float lambda, + SKP_float limit, + SKP_int order +) { + SKP_int i, iter, ind = 0; + SKP_float tmp, maxabs, chirp, gain_syn, gain_ana; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = SKP_max( SKP_abs_float( coefs_syn[ i ] ), SKP_abs_float( coefs_ana[ i ] ) ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ]; + } + gain_syn = 1.0f / gain_syn; + gain_ana = 1.0f / gain_ana; + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + SKP_Silk_bwexpander_FLP( coefs_syn, order, chirp ); + SKP_Silk_bwexpander_FLP( coefs_ana, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + } + SKP_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void SKP_Silk_noise_shape_analysis_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + SKP_Silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + SKP_int k, nSamples; + SKP_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt; + SKP_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation; + SKP_float delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping; + SKP_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + SKP_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + const SKP_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* CONTROL SNR */ + /****************/ + /* Reduce SNR_dB values if recent bitstream has exceeded TargetRate */ + psEncCtrl->current_SNR_dB = psEnc->SNR_dB - 0.05f * psEnc->BufferedInChannel_ms; + + /* Reduce SNR_dB if inband FEC used */ + if( psEnc->speech_activity > LBRR_SPEECH_ACTIVITY_THRES ) { + psEncCtrl->current_SNR_dB -= psEnc->inBandFEC_SNR_comp; + } + + /****************/ + /* GAIN CONTROL */ + /****************/ + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEncCtrl->input_quality_bands[ 0 ] + psEncCtrl->input_quality_bands[ 1 ] ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = SKP_sigmoid( 0.25f * ( psEncCtrl->current_SNR_dB - 18.0f ) ); + + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->speech_activity; + SNR_adj_dB = psEncCtrl->current_SNR_dB - + BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEncCtrl->current_SNR_dB + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Initally set to 0; may be overruled in process_gains(..) */ + psEncCtrl->sCmn.QuantOffsetType = 0; + psEncCtrl->sparseness = 0.0f; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + for( k = 0; k < FRAME_LENGTH_MS / 2; k++ ) { + nrg = ( SKP_float )nSamples + ( SKP_float )SKP_Silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = SKP_Silk_log2( nrg ); + if( k > 0 ) { + energy_variation += SKP_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + psEncCtrl->sparseness = SKP_sigmoid( 0.4f * ( energy_variation - 5.0f ) ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality ); + BWExp1 -= delta; + BWExp2 += delta; + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1 /= BWExp2; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (SKP_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + } else { + warping = 0.0f; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < NB_SUBFR; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + SKP_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 5; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + SKP_Silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + SKP_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(SKP_float) ); + shift += flat_part; + SKP_Silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + SKP_Silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + SKP_Silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = SKP_Silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( SKP_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + SKP_Silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 ); + + /* Compute noise shaping filter coefficients */ + SKP_memcpy( + &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], + psEnc->sCmn.shapingLPCOrder * sizeof( SKP_float ) ); + + /* Bandwidth expansion for analysis filter shaping */ + SKP_Silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 ); + + /* Ratio of prediction gains, in energy domain */ + SKP_Silk_LPC_inverse_pred_gain_FLP( &pre_nrg, &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + SKP_Silk_LPC_inverse_pred_gain_FLP( &nrg, &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult = ( SKP_float )pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = ( SKP_float )pow( 2.0f, 0.16f * NOISE_FLOOR_dB ) + + ( SKP_float )pow( 2.0f, 0.16f * RELATIVE_MIN_GAIN_dB ) * psEnc->avgGain; + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + psEnc->avgGain += psEnc->speech_activity * GAIN_SMOOTHING_COEF * ( psEncCtrl->Gains[ k ] - psEnc->avgGain ); + } + + /************************************************/ + /* Decrease level during fricatives (de-essing) */ + /************************************************/ + gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT; + if( psEncCtrl->input_tilt <= 0.0f && psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED ) { + SKP_float essStrength = -psEncCtrl->input_tilt * psEnc->speech_activity * ( 1.0f - psEncCtrl->sparseness ); + if( psEnc->sCmn.fs_kHz == 24 ) { + gain_mult *= ( SKP_float )pow( 2.0f, -0.16f * DE_ESSER_COEF_SWB_dB * essStrength ); + } else if( psEnc->sCmn.fs_kHz == 16 ) { + gain_mult *= (SKP_float)pow( 2.0f, -0.16f * DE_ESSER_COEF_WB_dB * essStrength ); + } else { + SKP_assert( psEnc->sCmn.fs_kHz == 12 || psEnc->sCmn.fs_kHz == 8 ); + } + } + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->GainsPre[ k ] *= gain_mult; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEncCtrl->input_quality_bands[ 0 ] - 1.0f ) ); + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < NB_SUBFR; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->sCmn.pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->speech_activity; + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < NB_SUBFR; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr; + + /* More harmonic boost for noisy input signals */ + HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality ); + + if( USE_HARM_SHAPING && psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( SKP_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth ); + psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth; + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_analysis_core_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_analysis_core_FLP.c new file mode 100755 index 0000000..3362648 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_analysis_core_FLP.c @@ -0,0 +1,625 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/***************************************************************************** +* +* Pitch analyser function +* +******************************************************************************/ +#include "SKP_Silk_SigProc_FLP.h" +#include "SKP_Silk_SigProc_FIX.h" +#include "./SKP_Silk_pitch_est_defines_FLP.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Definitions */ +/************************************************************/ +#define eps 1.192092896e-07f + +/* using log2() helps the fixed-point conversion */ +SKP_INLINE SKP_float SKP_P_log2(double x) { return (SKP_float)(3.32192809488736 * log10(x)); } + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void SKP_P_Ana_calc_corr_st3( + SKP_float cross_corr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const SKP_float signal[], /* I vector to correlate */ + SKP_int start_lag, /* I start lag */ + SKP_int sf_length, /* I sub frame length */ + SKP_int complexity /* I Complexity setting */ +); + +static void SKP_P_Ana_calc_energy_st3( + SKP_float energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const SKP_float signal[], /* I vector to correlate */ + SKP_int start_lag, /* I start lag */ + SKP_int sf_length, /* I sub frame length */ + SKP_int complexity /* I Complexity setting */ +); + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//% CORE PITCH ANALYSIS FUNCTION % +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +SKP_int SKP_Silk_pitch_analysis_core_FLP( /* O voicing estimate: 0 voiced, 1 unvoiced */ + const SKP_float *signal, /* I signal of length PITCH_EST_FRAME_LENGTH_MS*Fs_kHz */ + SKP_int *pitch_out, /* O 4 pitch lag values */ + SKP_int *lagIndex, /* O lag Index */ + SKP_int *contourIndex, /* O pitch contour Index */ + SKP_float *LTPCorr, /* I/O normalized correlation; input: value from previous frame */ + SKP_int prevLag, /* I last lag of previous frame; set to zero is unvoiced */ + const SKP_float search_thres1, /* I first stage threshold for lag candidates 0 - 1 */ + const SKP_float search_thres2, /* I final threshold for lag candidates 0 - 1 */ + const SKP_int Fs_kHz, /* I sample frequency (kHz) */ + const SKP_int complexity /* I Complexity setting, 0-2, where 2 is highest */ +) +{ + SKP_float signal_8kHz[ PITCH_EST_FRAME_LENGTH_MS * 8 ]; + SKP_float signal_4kHz[ PITCH_EST_FRAME_LENGTH_MS * 4 ]; + SKP_float scratch_mem[ PITCH_EST_MAX_FRAME_LENGTH * 3 ]; + SKP_float filt_state[ PITCH_EST_MAX_DECIMATE_STATE_LENGTH ]; + SKP_int i, k, d, j; + SKP_float threshold, contour_bias; + SKP_float C[PITCH_EST_NB_SUBFR][(PITCH_EST_MAX_LAG >> 1) + 5]; /* use to be +2 but then valgrind reported errors for SWB */ + SKP_float CC[PITCH_EST_NB_CBKS_STAGE2_EXT]; + const SKP_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + SKP_int d_srch[PITCH_EST_D_SRCH_LENGTH]; + SKP_int16 d_comp[(PITCH_EST_MAX_LAG >> 1) + 5]; + SKP_int length_d_srch, length_d_comp; + SKP_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + SKP_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + SKP_int cbk_offset, cbk_size; + SKP_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + SKP_float energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + SKP_float cross_corr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + + SKP_int diff, lag_counter; + SKP_int frame_length, frame_length_8kHz, frame_length_4kHz; + SKP_int sf_length, sf_length_8kHz; + SKP_int min_lag, min_lag_8kHz, min_lag_4kHz; + SKP_int max_lag, max_lag_8kHz, max_lag_4kHz; + + SKP_int nb_cbks_stage2; + + /* Check for valid sampling frequency */ + SKP_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 || Fs_kHz == 24 ); + + /* Check for valid complexity setting */ + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + SKP_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + SKP_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Setup frame lengths max / min lag for the sampling frequency */ + frame_length = PITCH_EST_FRAME_LENGTH_MS * Fs_kHz; + frame_length_4kHz = PITCH_EST_FRAME_LENGTH_MS * 4; + frame_length_8kHz = PITCH_EST_FRAME_LENGTH_MS * 8; + sf_length = SKP_RSHIFT( frame_length, 3 ); + sf_length_8kHz = SKP_RSHIFT( frame_length_8kHz, 3 ); + min_lag = PITCH_EST_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PITCH_EST_MIN_LAG_MS * 4; + min_lag_8kHz = PITCH_EST_MIN_LAG_MS * 8; + max_lag = PITCH_EST_MAX_LAG_MS * Fs_kHz; + max_lag_4kHz = PITCH_EST_MAX_LAG_MS * 4; + max_lag_8kHz = PITCH_EST_MAX_LAG_MS * 8; + + SKP_memset(C, 0, sizeof(SKP_float) * PITCH_EST_NB_SUBFR * ((PITCH_EST_MAX_LAG >> 1) + 5)); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 12 ) { + SKP_int16 signal_12[ 12 * PITCH_EST_FRAME_LENGTH_MS ]; + SKP_int16 signal_8[ 8 * PITCH_EST_FRAME_LENGTH_MS ]; + SKP_int32 R23[ 6 ]; + + /* Resample to 12 -> 8 khz */ + SKP_memset( R23, 0, 6 * sizeof( SKP_int32 ) ); + SKP_float2short_array( signal_12, signal, PITCH_EST_FRAME_LENGTH_MS * 12); + SKP_Silk_resampler_down2_3( R23, signal_8, signal_12, PITCH_EST_FRAME_LENGTH_MS * 12 ); + SKP_short2float_array( signal_8kHz, signal_8, frame_length_8kHz ); + } else if( Fs_kHz == 16 ) { + if( complexity == SKP_Silk_PITCH_EST_MAX_COMPLEX ) { + SKP_assert( 4 <= PITCH_EST_MAX_DECIMATE_STATE_LENGTH ); + SKP_memset( filt_state, 0, 4 * sizeof(SKP_float) ); + + SKP_Silk_decimate2_coarse_FLP( signal, filt_state, signal_8kHz, + scratch_mem, frame_length_8kHz ); + } else { + SKP_assert( 2 <= PITCH_EST_MAX_DECIMATE_STATE_LENGTH ); + SKP_memset( filt_state, 0, 2 * sizeof(SKP_float) ); + + SKP_Silk_decimate2_coarsest_FLP( signal, filt_state, signal_8kHz, + scratch_mem, frame_length_8kHz ); + } + } else if( Fs_kHz == 24 ) { + SKP_int16 signal_24[ PITCH_EST_MAX_FRAME_LENGTH ]; + SKP_int16 signal_8[ 8 * PITCH_EST_FRAME_LENGTH_MS ]; + SKP_int32 filt_state_fix[ 8 ]; + + /* Resample to 24 -> 8 khz */ + SKP_float2short_array( signal_24, signal, 24 * PITCH_EST_FRAME_LENGTH_MS ); + SKP_memset( filt_state_fix, 0, 8 * sizeof(SKP_int32) ); + SKP_Silk_resampler_down3( filt_state_fix, signal_8, signal_24, 24 * PITCH_EST_FRAME_LENGTH_MS ); + SKP_short2float_array( signal_8kHz, signal_8, frame_length_8kHz ); + } else { + SKP_assert( Fs_kHz == 8 ); + SKP_memcpy( signal_8kHz, signal, frame_length_8kHz * sizeof(SKP_float) ); + } + + /* Decimate again to 4 kHz. Set mem to zero */ + if( complexity == SKP_Silk_PITCH_EST_MAX_COMPLEX ) { + SKP_assert( 4 <= PITCH_EST_MAX_DECIMATE_STATE_LENGTH ); + SKP_memset( filt_state, 0, 4 * sizeof(SKP_float) ); + SKP_Silk_decimate2_coarse_FLP( signal_8kHz, filt_state, + signal_4kHz, scratch_mem, frame_length_4kHz ); + } else { + SKP_assert( 2 <= PITCH_EST_MAX_DECIMATE_STATE_LENGTH ); + SKP_memset( filt_state, 0, 2 * sizeof(SKP_float) ); + SKP_Silk_decimate2_coarsest_FLP( signal_8kHz, filt_state, + signal_4kHz, scratch_mem, frame_length_4kHz ); + } + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + signal_4kHz[ i ] += signal_4kHz[ i - 1 ]; + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &signal_4kHz[ SKP_RSHIFT( frame_length_4kHz, 1 ) ]; + for( k = 0; k < 2; k++ ) { + /* Check that we are within range of the array */ + SKP_assert( target_ptr >= signal_4kHz ); + SKP_assert( target_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + SKP_assert( basis_ptr >= signal_4kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + /* Calculate first vector products before loop */ + cross_corr = SKP_Silk_inner_product_FLP( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = SKP_Silk_energy_FLP( basis_ptr, sf_length_8kHz ) + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (SKP_float)(cross_corr / sqrt(normalizer)); + + /* From now on normalizer is computed recursively */ + for(d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++) { + basis_ptr--; + + /* Check that we are within range of the array */ + SKP_assert( basis_ptr >= signal_4kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + cross_corr = SKP_Silk_inner_product_FLP(target_ptr, basis_ptr, sf_length_8kHz); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (SKP_float)(cross_corr / sqrt( normalizer )); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + SKP_assert( 3 * length_d_srch <= PITCH_EST_D_SRCH_LENGTH ); + SKP_Silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + target_ptr = &signal_4kHz[ SKP_RSHIFT( frame_length_4kHz, 1 ) ]; + energy = 1000.0f; + for( i = 0; i < SKP_RSHIFT( frame_length_4kHz, 1 ); i++ ) { + energy += target_ptr[i] * target_ptr[i]; + } + threshold = Cmax * Cmax; + if( energy / 16.0f > threshold ) { + SKP_memset(pitch_out, 0, PITCH_EST_NB_SUBFR * sizeof(SKP_int)); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = SKP_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + SKP_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + SKP_memset( C, 0, PITCH_EST_NB_SUBFR*((PITCH_EST_MAX_LAG >> 1) + 5) * sizeof(SKP_float)); // Is this needed? + + target_ptr = &signal_8kHz[ frame_length_4kHz ]; /* point to middle of frame */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ){ + + /* Check that we are within range of the array */ + SKP_assert( target_ptr >= signal_8kHz ); + SKP_assert( target_ptr + sf_length_8kHz <= signal_8kHz + frame_length_8kHz ); + + energy_tmp = SKP_Silk_energy_FLP( target_ptr, sf_length_8kHz ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + SKP_assert( basis_ptr >= signal_8kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_8kHz + frame_length_8kHz ); + + cross_corr = SKP_Silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + energy = SKP_Silk_energy_FLP( basis_ptr, sf_length_8kHz ); + if (cross_corr > 0.0f) { + C[ k ][ d ] = (SKP_float)(cross_corr * cross_corr / (energy * energy_tmp + eps)); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = SKP_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = SKP_RSHIFT( prevLag, 1 ); + } else if( Fs_kHz == 24 ) { + prevLag = prevLag / 3; + } + prevLag_log2 = SKP_P_log2((double)prevLag); + } else { + prevLag_log2 = 0; + } + + /* If input is 8 khz use a larger codebook here because it is last stage */ + if( Fs_kHz == 8 && complexity > SKP_Silk_PITCH_EST_MIN_COMPLEX ) { + nb_cbks_stage2 = PITCH_EST_NB_CBKS_STAGE2_EXT; + } else { + nb_cbks_stage2 = PITCH_EST_NB_CBKS_STAGE2; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbks_stage2; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + SKP_Silk_CB_lags_stage2[ i ][ j ] ]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbks_stage2; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + CCmax_new = SKP_max_float(CCmax_new, 0.0f); /* To avoid taking square root of negative number later */ + CCmax_new_b = CCmax_new; + + /* Bias towards shorter lags */ + lag_log2 = SKP_P_log2((double)d); + CCmax_new_b -= PITCH_EST_FLP_SHORTLAG_BIAS * PITCH_EST_NB_SUBFR * lag_log2; + + /* Bias towards previous lag */ + if ( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PITCH_EST_FLP_PREVLAG_BIAS * PITCH_EST_NB_SUBFR * (*LTPCorr) * delta_lag_log2_sqr / (delta_lag_log2_sqr + 0.5f); + } + + if ( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > PITCH_EST_NB_SUBFR * search_thres2 * search_thres2 && /* Correlation needs to be high enough to be voiced */ + SKP_Silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= min_lag_8kHz /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + SKP_memset( pitch_out, 0, PITCH_EST_NB_SUBFR * sizeof(SKP_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + SKP_assert( lag == SKP_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = SKP_RSHIFT_ROUND( SKP_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = SKP_LSHIFT( lag, 1 ); + } else { + lag = SKP_SMULBB( lag, 3 ); + } + + lag = SKP_LIMIT_int( lag, min_lag, max_lag ); + start_lag = SKP_max_int( lag - 2, min_lag ); + end_lag = SKP_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + SKP_assert( CCmax >= 0.0f ); + *LTPCorr = (SKP_float)sqrt( CCmax / PITCH_EST_NB_SUBFR ); // Output normalized correlation + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + SKP_P_Ana_calc_corr_st3( cross_corr_st3, signal, start_lag, sf_length, complexity ); + SKP_P_Ana_calc_energy_st3( energies_st3, signal, start_lag, sf_length, complexity ); + + lag_counter = 0; + SKP_assert( lag == SKP_SAT16( lag ) ); + contour_bias = PITCH_EST_FLP_FLATCONTOUR_BIAS / lag; + + /* Setup cbk parameters acording to complexity setting */ + cbk_size = (SKP_int)SKP_Silk_cbk_sizes_stage3[ complexity ]; + cbk_offset = (SKP_int)SKP_Silk_cbk_offsets_stage3[ complexity ]; + + for( d = start_lag; d <= end_lag; d++ ) { + for( j = cbk_offset; j < ( cbk_offset + cbk_size ); j++ ) { + cross_corr = 0.0; + energy = eps; + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + energy += energies_st3[ k ][ j ][ lag_counter ]; + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (SKP_float)(cross_corr * cross_corr / energy); + /* Reduce depending on flatness of contour */ + diff = j - ( PITCH_EST_NB_CBKS_STAGE3_MAX >> 1 ); + CCmax_new *= ( 1.0f - contour_bias * diff * diff ); + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && + ( d + (SKP_int)SKP_Silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[k] = lag_new + (SKP_int)SKP_Silk_CB_lags_stage3[ k ][ CBimax ]; + } + *lagIndex = lag_new - min_lag; + *contourIndex = CBimax; + } else { + /* Save Lags and correlation */ + SKP_assert( CCmax >= 0.0f ); + *LTPCorr = (SKP_float)sqrt(CCmax / PITCH_EST_NB_SUBFR); /* Output normalized correlation */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[ k ] = lag + SKP_Silk_CB_lags_stage2[ k ][ CBimax ]; + } + *lagIndex = lag - min_lag; + *contourIndex = CBimax; + } + SKP_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +static void SKP_P_Ana_calc_corr_st3( + SKP_float cross_corr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const SKP_float signal[], /* I vector to correlate */ + SKP_int start_lag, /* I start lag */ + SKP_int sf_length, /* I sub frame length */ + SKP_int complexity /* I Complexity setting */ +) + /*********************************************************************** + Calculates the correlations used in stage 3 search. In order to cover + the whole lag codebook for all the searched offset lags (lag +- 2), + the following correlations are needed in each sub frame: + + sf1: lag range [-8,...,7] total 16 correlations + sf2: lag range [-4,...,4] total 9 correlations + sf3: lag range [-3,....4] total 8 correltions + sf4: lag range [-6,....8] total 15 correlations + + In total 48 correlations. The direct implementation computed in worst case + 4*12*5 = 240 correlations, but more likely around 120. + **********************************************************************/ +{ + const SKP_float *target_ptr, *basis_ptr; + SKP_int i, j, k, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_float scratch_mem[ SCRATCH_SIZE ]; + + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + cbk_offset = SKP_Silk_cbk_offsets_stage3[ complexity ]; + cbk_size = SKP_Silk_cbk_sizes_stage3[ complexity ]; + + target_ptr = &signal[ SKP_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + for( j = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; j <= SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 1 ]; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = (SKP_float)SKP_Silk_inner_product_FLP( target_ptr, basis_ptr, sf_length ); + lag_counter++; + } + + delta = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; + for( i = cbk_offset; i < ( cbk_offset + cbk_size ); i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = SKP_Silk_CB_lags_stage3[ k ][ i ] - delta; + for( j = 0; j < PITCH_EST_NB_STAGE3_LAGS; j++ ) { + SKP_assert( idx + j < SCRATCH_SIZE ); + SKP_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +static void SKP_P_Ana_calc_energy_st3( + SKP_float energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const SKP_float signal[], /* I vector to correlate */ + SKP_int start_lag, /* I start lag */ + SKP_int sf_length, /* I sub frame length */ + SKP_int complexity /* I Complexity setting */ +) +/**************************************************************** +Calculate the energies for first two subframes. The energies are +calculated recursively. +****************************************************************/ +{ + const SKP_float *target_ptr, *basis_ptr; + double energy; + SKP_int k, i, j, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_float scratch_mem[ SCRATCH_SIZE ]; + + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + cbk_offset = SKP_Silk_cbk_offsets_stage3[ complexity ]; + cbk_size = SKP_Silk_cbk_sizes_stage3[ complexity ]; + + target_ptr = &signal[ SKP_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ] ); + energy = SKP_Silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + SKP_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (SKP_float)energy; + lag_counter++; + + for( i = 1; i < ( SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 1 ] - SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ] + 1 ); i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * basis_ptr[sf_length - i]; + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * basis_ptr[ -i ]; + + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = ( SKP_float )SKP_max_float( energy, 1e-3 ); + lag_counter++; + } + + delta = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; + for( i = cbk_offset; i < ( cbk_offset + cbk_size ); i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = SKP_Silk_CB_lags_stage3[ k ][ i ] - delta; + for(j = 0; j < PITCH_EST_NB_STAGE3_LAGS; j++){ + SKP_assert( idx + j < SCRATCH_SIZE ); + SKP_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + SKP_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines.h new file mode 100755 index 0000000..380f220 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines.h @@ -0,0 +1,40 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFIX_PITCH_EST_DEFINES_H +#define SIGPROCFIX_PITCH_EST_DEFINES_H + +/************************************************************/ +/* Definitions For Fix pitch estimator */ +/************************************************************/ + +#define PITCH_EST_SHORTLAG_BIAS_Q15 6554 /* 0.2f. for logarithmic weighting */ +#define PITCH_EST_PREVLAG_BIAS_Q15 6554 /* Prev lag bias */ +#define PITCH_EST_FLATCONTOUR_BIAS_Q20 52429 /* 0.05f */ + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines_FLP.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines_FLP.h new file mode 100755 index 0000000..5944846 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_defines_FLP.h @@ -0,0 +1,40 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFLP_PITCH_EST_DEFINES_H +#define SIGPROCFLP_PITCH_EST_DEFINES_H + +/************************************************************/ +/* Definitions For FLP pitch estimator */ +/************************************************************/ + +#define PITCH_EST_FLP_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PITCH_EST_FLP_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PITCH_EST_FLP_FLATCONTOUR_BIAS 0.05f + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_tables.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_tables.c new file mode 100755 index 0000000..6c54795 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_pitch_est_tables.c @@ -0,0 +1,89 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +/********************************************************/ +/* Auto Generated File from generate_pitch_est_tables.m */ +/********************************************************/ + +const SKP_int16 SKP_Silk_CB_lags_stage2[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE2_EXT] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const SKP_int16 SKP_Silk_CB_lags_stage3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX] = +{ + {-9,-7,-6,-5,-5,-4,-4,-3,-3,-2,-2,-2,-1,-1,-1, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 5, 6, 8}, + {-3,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 2, 2, 2, 2, 3}, + { 3, 3, 2, 2, 2, 2, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,-1, 0, 0,-1,-1,-1,-1,-1,-2,-2,-2}, + { 9, 8, 6, 5, 6, 5, 4, 4, 3, 3, 2, 2, 2, 1, 0, 1, 1, 0, 0, 0,-1,-1,-1,-2,-2,-2,-3,-3,-4,-4,-5,-5,-6,-7} + }; + +const SKP_int16 SKP_Silk_Lag_range_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ] [ PITCH_EST_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-2,6}, + {-1,5}, + {-1,5}, + {-2,7} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-4,8}, + {-1,6}, + {-1,6}, + {-4,9} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const SKP_int16 SKP_Silk_cbk_sizes_stage3[SKP_Silk_PITCH_EST_MAX_COMPLEX + 1] = +{ + PITCH_EST_NB_CBKS_STAGE3_MIN, + PITCH_EST_NB_CBKS_STAGE3_MID, + PITCH_EST_NB_CBKS_STAGE3_MAX +}; + +const SKP_int16 SKP_Silk_cbk_offsets_stage3[SKP_Silk_PITCH_EST_MAX_COMPLEX + 1] = +{ + ((PITCH_EST_NB_CBKS_STAGE3_MAX - PITCH_EST_NB_CBKS_STAGE3_MIN) >> 1), + ((PITCH_EST_NB_CBKS_STAGE3_MAX - PITCH_EST_NB_CBKS_STAGE3_MID) >> 1), + 0 +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_prefilter_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_prefilter_FLP.c new file mode 100755 index 0000000..dfcf120 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_prefilter_FLP.c @@ -0,0 +1,202 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +/* +* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal +*/ +SKP_INLINE void SKP_Silk_prefilt_FLP( + SKP_Silk_prefilter_state_FLP *P,/* I/O state */ + SKP_float st_res[], /* I */ + SKP_float xw[], /* O */ + SKP_float *HarmShapeFIR, /* I */ + SKP_float Tilt, /* I */ + SKP_float LF_MA_shp, /* I */ + SKP_float LF_AR_shp, /* I */ + SKP_int lag, /* I */ + SKP_int length /* I */ +); + +void SKP_Silk_warped_LPC_analysis_filter_FLP( + SKP_float state[], /* I/O State [order + 1] */ + SKP_float res[], /* O Residual signal [length] */ + const SKP_float coef[], /* I Coefficients [order] */ + const SKP_float input[], /* I Input signal [length] */ + const SKP_float lambda, /* I Warping factor */ + const SKP_int length, /* I Length of input signal */ + const SKP_int order /* I Filter order (even) */ +) +{ + SKP_int n, i; + SKP_float acc, tmp1, tmp2; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = state[ 0 ] + lambda * state[ 1 ]; + state[ 0 ] = input[ n ]; + /* Output of allpass section */ + tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 ); + state[ 1 ] = tmp2; + acc = coef[ 0 ] * tmp2; + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + acc += coef[ i - 1 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + acc += coef[ i ] * tmp2; + } + state[ order ] = tmp1; + acc += coef[ order - 1 ] * tmp1; + res[ n ] = input[ n ] - acc; + } +} + +/* +* SKP_Silk_prefilter. Main prefilter function +*/ +void SKP_Silk_prefilter_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const SKP_Silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + SKP_float xw[], /* O Weighted signal */ + const SKP_float x[] /* I Speech signal */ +) +{ + SKP_Silk_prefilter_state_FLP *P = &psEnc->sPrefilt; + SKP_int j, k, lag; + SKP_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp; + SKP_float B[ 2 ]; + const SKP_float *AR1_shp; + const SKP_float *px; + SKP_float *pxw; + SKP_float HarmShapeFIR[ 3 ]; + SKP_float st_res[ MAX_FRAME_LENGTH / NB_SUBFR + MAX_SHAPE_LPC_ORDER ]; + + /* Set up pointers */ + px = x; + pxw = xw; + lag = P->lagPrev; + for( k = 0; k < NB_SUBFR; k++ ) { + /* Update Variables that change per sub frame */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + lag = psEncCtrl->sCmn.pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] ); + HarmShapeFIR[ 0 ] = SKP_Silk_HarmShapeFIR_FLP[ 0 ] * HarmShapeGain; + HarmShapeFIR[ 1 ] = SKP_Silk_HarmShapeFIR_FLP[ 1 ] * HarmShapeGain; + HarmShapeFIR[ 2 ] = SKP_Silk_HarmShapeFIR_FLP[ 2 ] * HarmShapeGain; + Tilt = psEncCtrl->Tilt[ k ]; + LF_MA_shp = psEncCtrl->LF_MA_shp[ k ]; + LF_AR_shp = psEncCtrl->LF_AR_shp[ k ]; + AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering */ + SKP_Silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px, + (SKP_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B[ 0 ] = psEncCtrl->GainsPre[ k ]; + B[ 1 ] = -psEncCtrl->GainsPre[ k ] * + ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT ); + pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP; + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ]; + } + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + SKP_Silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + P->lagPrev = psEncCtrl->sCmn.pitchL[ NB_SUBFR - 1 ]; +} + +/* +* Prefilter for finding Quantizer input signal +*/ +SKP_INLINE void SKP_Silk_prefilt_FLP( + SKP_Silk_prefilter_state_FLP *P,/* I/O state */ + SKP_float st_res[], /* I */ + SKP_float xw[], /* O */ + SKP_float *HarmShapeFIR, /* I */ + SKP_float Tilt, /* I */ + SKP_float LF_MA_shp, /* I */ + SKP_float LF_AR_shp, /* I */ + SKP_int lag, /* I */ + SKP_int length /* I */ +) +{ + SKP_int i; + SKP_int idx, LTP_shp_buf_idx; + SKP_float n_Tilt, n_LF, n_LTP; + SKP_float sLF_AR_shp, sLF_MA_shp; + SKP_float *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp = P->sLF_AR_shp; + sLF_MA_shp = P->sLF_MA_shp; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + SKP_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ]; + } else { + n_LTP = 0; + } + + n_Tilt = sLF_AR_shp * Tilt; + n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp; + + sLF_AR_shp = st_res[ i ] - n_Tilt; + sLF_MA_shp = sLF_AR_shp - n_LF; + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp; + + xw[ i ] = sLF_MA_shp - n_LTP; + } + /* Copy temp variable back to state */ + P->sLF_AR_shp = sLF_AR_shp; + P->sLF_MA_shp = sLF_MA_shp; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_NLSFs_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_NLSFs_FLP.c new file mode 100755 index 0000000..bf67df9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_NLSFs_FLP.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include +#include "SKP_Silk_main_FLP.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void SKP_Silk_process_NLSFs_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SKP_float *pNLSF /* I/O NLSFs (quantized output) */ +) +{ + SKP_int doInterpolate; + SKP_float pNLSFW[ MAX_LPC_ORDER ]; + SKP_float NLSF_mu, NLSF_mu_fluc_red, i_sqr, NLSF_interpolation_factor = 0.0f; + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP; + + /* Used only for NLSF interpolation */ + SKP_float pNLSF0_temp[ MAX_LPC_ORDER ]; + SKP_float pNLSFW0_temp[ MAX_LPC_ORDER ]; + SKP_int i; + + SKP_assert( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED || psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + NLSF_mu = 0.002f - 0.001f * psEnc->speech_activity; + NLSF_mu_fluc_red = 0.1f - 0.05f * psEnc->speech_activity; + } else { + NLSF_mu = 0.005f - 0.004f * psEnc->speech_activity; + NLSF_mu_fluc_red = 0.2f - 0.1f * ( psEnc->speech_activity + psEncCtrl->sparseness ); + } + + /* Calculate NLSF weights */ + SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW, pNLSF, psEnc->sCmn.predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEnc->sCmn.useInterpolatedNLSFs == 1 ) && ( psEncCtrl->sCmn.NLSFInterpCoef_Q2 < ( 1 << 2 ) ); + if( doInterpolate ) { + + /* Calculate the interpolated NLSF vector for the first half */ + NLSF_interpolation_factor = 0.25f * psEncCtrl->sCmn.NLSFInterpCoef_Q2; + SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc->sPred.prev_NLSFq, pNLSF, + NLSF_interpolation_factor, psEnc->sCmn.predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW0_temp, pNLSF0_temp, psEnc->sCmn.predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr = NLSF_interpolation_factor * NLSF_interpolation_factor; + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + pNLSFW[ i ] = 0.5f * ( pNLSFW[ i ] + i_sqr * pNLSFW0_temp[ i ] ); + } + } + + /* Set pointer to the NLSF codebook for the current signal type and LPC order */ + psNLSF_CB_FLP = psEnc->psNLSF_CB_FLP[ psEncCtrl->sCmn.sigtype ]; + + /* Quantize NLSF parameters given the trained NLSF codebooks */ + SKP_Silk_NLSF_MSVQ_encode_FLP( psEncCtrl->sCmn.NLSFIndices, pNLSF, psNLSF_CB_FLP, psEnc->sPred.prev_NLSFq, pNLSFW, NLSF_mu, + NLSF_mu_fluc_red, psEnc->sCmn.NLSF_MSVQ_Survivors, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.first_frame_after_reset ); + + /* Convert quantized NLSFs back to LPC coefficients */ + SKP_Silk_NLSF2A_stable_FLP( psEncCtrl->PredCoef[ 1 ], pNLSF, psEnc->sCmn.predictLPCOrder ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized NLSF vector for the first half */ + SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc->sPred.prev_NLSFq, pNLSF, + NLSF_interpolation_factor, psEnc->sCmn.predictLPCOrder ); + + /* Convert back to LPC coefficients */ + SKP_Silk_NLSF2A_stable_FLP( psEncCtrl->PredCoef[ 0 ], pNLSF0_temp, psEnc->sCmn.predictLPCOrder ); + + } else { + /* Copy LPC coefficients for first half from second half */ + SKP_memcpy( psEncCtrl->PredCoef[ 0 ], psEncCtrl->PredCoef[ 1 ], psEnc->sCmn.predictLPCOrder * sizeof( SKP_float ) ); + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_gains_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_gains_FLP.c new file mode 100755 index 0000000..1e7cc16 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_process_gains_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Processing of gains */ +void SKP_Silk_process_gains_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl /* I/O Encoder control FLP */ +) +{ + SKP_Silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + SKP_int k; + SKP_int32 pGains_Q16[ NB_SUBFR ]; + SKP_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + s = 1.0f - 0.5f * SKP_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( SKP_float )( pow( 2.0f, 0.33f * ( 21.0f - psEncCtrl->current_SNR_dB ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < NB_SUBFR; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( SKP_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = SKP_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < NB_SUBFR; k++ ) { + pGains_Q16[ k ] = ( SKP_int32 ) ( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Noise shaping quantization */ + SKP_Silk_gains_quant( psEncCtrl->sCmn.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEncCtrl->input_tilt > 1.0f ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrl->sCmn.sigtype ][ psEncCtrl->sCmn.QuantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->speech_activity + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + SKP_assert( psEncCtrl->Lambda > 0.0f ); + SKP_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_quant_LTP_gains_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_quant_LTP_gains_FLP.c new file mode 100755 index 0000000..8bd7201 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_quant_LTP_gains_FLP.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +#define Q14_CONVERSION_FAC 6.1035e-005f // 1 / 2^14 + +void SKP_Silk_quant_LTP_gains_FLP( + SKP_float B[ NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + SKP_int cbk_index[ NB_SUBFR ], /* O Codebook index */ + SKP_int *periodicity_index, /* O Periodicity index */ + const SKP_float W[ NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error weights */ + const SKP_float mu, /* I Mu value (R/D tradeoff) */ + const SKP_int lowComplexity /* I Flag for low complexity */ +) +{ + SKP_int j, k, temp_idx[ NB_SUBFR ], cbk_size; + const SKP_int16 *cl_ptr; + const SKP_int16 *cbk_ptr_Q14; + const SKP_float *b_ptr, *W_ptr; + SKP_float rate_dist_subfr, rate_dist, min_rate_dist; + + + + /***************************************************/ + /* Iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist = SKP_float_MAX; + for( k = 0; k < 3; k++ ) { + cl_ptr = SKP_Silk_LTP_gain_BITS_Q6_ptrs[ k ]; + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ k ]; + cbk_size = SKP_Silk_LTP_vq_sizes[ k ]; + + /* Setup pointer to first subframe */ + W_ptr = W; + b_ptr = B; + + rate_dist = 0.0f; + for( j = 0; j < NB_SUBFR; j++ ) { + + SKP_Silk_VQ_WMat_EC_FLP( + &temp_idx[ j ], /* O index of best codebook vector */ + &rate_dist_subfr, /* O best weighted quantization error + mu * rate */ + b_ptr, /* I input vector to be quantized */ + W_ptr, /* I weighting matrix */ + cbk_ptr_Q14, /* I codebook */ + cl_ptr, /* I code length for each codebook vector */ + mu, /* I tradeoff between weighted error and rate */ + cbk_size /* I number of vectors in codebook */ + ); + + rate_dist += rate_dist_subfr; + + b_ptr += LTP_ORDER; + W_ptr += LTP_ORDER * LTP_ORDER; + } + + if( rate_dist < min_rate_dist ) { + min_rate_dist = rate_dist; + SKP_memcpy( cbk_index, temp_idx, NB_SUBFR * sizeof( SKP_int ) ); + *periodicity_index = k; + } + + /* Break early in low-complexity mode if rate distortion is below threshold */ + if( lowComplexity && ( rate_dist * 16384.0f < ( SKP_float )SKP_Silk_LTP_gain_middle_avg_RD_Q14 ) ) { + break; + } + } + + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ *periodicity_index ]; + for( j = 0; j < NB_SUBFR; j++ ) { + SKP_short2float_array( &B[ j * LTP_ORDER ], + &cbk_ptr_Q14[ cbk_index[ j ] * LTP_ORDER ], + LTP_ORDER ); + } + + for( j = 0; j < NB_SUBFR * LTP_ORDER; j++ ) { + B[ j ] *= Q14_CONVERSION_FAC; + } + +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_range_coder.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_range_coder.c new file mode 100755 index 0000000..20e633f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_range_coder.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Range encoder for one symbol */ +void SKP_Silk_range_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data, /* I uncompressed data */ + const SKP_uint16 prob[] /* I cumulative density functions */ +) +{ + SKP_uint32 low_Q16, high_Q16; + SKP_uint32 base_tmp, range_Q32; + + /* Copy structure data */ + SKP_uint32 base_Q32 = psRC->base_Q32; + SKP_uint32 range_Q16 = psRC->range_Q16; + SKP_int32 bufferIx = psRC->bufferIx; + SKP_uint8 *buffer = psRC->buffer; + + if( psRC->error ) { + return; + } + + /* Update interval */ + low_Q16 = prob[ data ]; + high_Q16 = prob[ data + 1 ]; + base_tmp = base_Q32; /* save current base, to test for carry */ + base_Q32 += SKP_MUL_uint( range_Q16, low_Q16 ); + range_Q32 = SKP_MUL_uint( range_Q16, high_Q16 - low_Q16 ); + + /* Check for carry */ + if( base_Q32 < base_tmp ) { + /* Propagate carry in buffer */ + SKP_int bufferIx_tmp = bufferIx; + while( ( ++buffer[ --bufferIx_tmp ] ) == 0 ); + } + + /* Check normalization */ + if( range_Q32 & 0xFF000000 ) { + /* No normalization */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 16 ); + } else { + if( range_Q32 & 0xFFFF0000 ) { + /* Normalization of 8 bits shift */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 8 ); + } else { + /* Normalization of 16 bits shift */ + range_Q16 = range_Q32; + /* Make sure not to write beyond buffer */ + if( bufferIx >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_WRITE_BEYOND_BUFFER; + return; + } + /* Write one byte to buffer */ + buffer[ bufferIx++ ] = (SKP_uint8)( SKP_RSHIFT_uint( base_Q32, 24 ) ); + base_Q32 = SKP_LSHIFT_ovflw( base_Q32, 8 ); + } + /* Make sure not to write beyond buffer */ + if( bufferIx >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_WRITE_BEYOND_BUFFER; + return; + } + /* Write one byte to buffer */ + buffer[ bufferIx++ ] = (SKP_uint8)( SKP_RSHIFT_uint( base_Q32, 24 ) ); + base_Q32 = SKP_LSHIFT_ovflw( base_Q32, 8 ); + } + + /* Copy structure data back */ + psRC->base_Q32 = base_Q32; + psRC->range_Q16 = range_Q16; + psRC->bufferIx = bufferIx; +} + +/* Range encoder for multiple symbols */ +void SKP_Silk_range_encoder_multi( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data[], /* I uncompressed data [nSymbols] */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int nSymbols /* I number of data symbols */ +) +{ + SKP_int k; + for( k = 0; k < nSymbols; k++ ) { + SKP_Silk_range_encoder( psRC, data[ k ], prob[ k ] ); + } +} + +/* Range decoder for one symbol */ +void SKP_Silk_range_decoder( + SKP_int data[], /* O uncompressed data */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 prob[], /* I cumulative density function */ + SKP_int probIx /* I initial (middle) entry of cdf */ +) +{ + SKP_uint32 low_Q16, high_Q16; + SKP_uint32 base_tmp, range_Q32; + + /* Copy structure data */ + SKP_uint32 base_Q32 = psRC->base_Q32; + SKP_uint32 range_Q16 = psRC->range_Q16; + SKP_int32 bufferIx = psRC->bufferIx; + SKP_uint8 *buffer = &psRC->buffer[ 4 ]; + + if( psRC->error ) { + /* Set output to zero */ + *data = 0; + return; + } + + high_Q16 = prob[ probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, high_Q16 ); + if( base_tmp > base_Q32 ) { + while( 1 ) { + low_Q16 = prob[ --probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, low_Q16 ); + if( base_tmp <= base_Q32 ) { + break; + } + high_Q16 = low_Q16; + /* Test for out of range */ + if( high_Q16 == 0 ) { + psRC->error = RANGE_CODER_CDF_OUT_OF_RANGE; + /* Set output to zero */ + *data = 0; + return; + } + } + } else { + while( 1 ) { + low_Q16 = high_Q16; + high_Q16 = prob[ ++probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, high_Q16 ); + if( base_tmp > base_Q32 ) { + probIx--; + break; + } + /* Test for out of range */ + if( high_Q16 == 0xFFFF ) { + psRC->error = RANGE_CODER_CDF_OUT_OF_RANGE; + /* Set output to zero */ + *data = 0; + return; + } + } + } + *data = probIx; + base_Q32 -= SKP_MUL_uint( range_Q16, low_Q16 ); + range_Q32 = SKP_MUL_uint( range_Q16, high_Q16 - low_Q16 ); + + /* Check normalization */ + if( range_Q32 & 0xFF000000 ) { + /* No normalization */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 16 ); + } else { + if( range_Q32 & 0xFFFF0000 ) { + /* Normalization of 8 bits shift */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 8 ); + /* Check for errors */ + if( SKP_RSHIFT_uint( base_Q32, 24 ) ) { + psRC->error = RANGE_CODER_NORMALIZATION_FAILED; + /* Set output to zero */ + *data = 0; + return; + } + } else { + /* Normalization of 16 bits shift */ + range_Q16 = range_Q32; + /* Check for errors */ + if( SKP_RSHIFT( base_Q32, 16 ) ) { + psRC->error = RANGE_CODER_NORMALIZATION_FAILED; + /* Set output to zero */ + *data = 0; + return; + } + /* Update base */ + base_Q32 = SKP_LSHIFT_uint( base_Q32, 8 ); + /* Make sure not to read beyond buffer */ + if( bufferIx < psRC->bufferLength ) { + /* Read one byte from buffer */ + base_Q32 |= (SKP_uint32)buffer[ bufferIx++ ]; + } + } + /* Update base */ + base_Q32 = SKP_LSHIFT_uint( base_Q32, 8 ); + /* Make sure not to read beyond buffer */ + if( bufferIx < psRC->bufferLength ) { + /* Read one byte from buffer */ + base_Q32 |= (SKP_uint32)buffer[ bufferIx++ ]; + } + } + + /* Check for zero interval length */ + if( range_Q16 == 0 ) { + psRC->error = RANGE_CODER_ZERO_INTERVAL_WIDTH; + /* Set output to zero */ + *data = 0; + return; + } + + /* Copy structure data back */ + psRC->base_Q32 = base_Q32; + psRC->range_Q16 = range_Q16; + psRC->bufferIx = bufferIx; +} + +/* Range decoder for multiple symbols */ +void SKP_Silk_range_decoder_multi( + SKP_int data[], /* O uncompressed data [nSymbols] */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int probStartIx[], /* I initial (middle) entries of cdfs [nSymbols] */ + const SKP_int nSymbols /* I number of data symbols */ +) +{ + SKP_int k; + for( k = 0; k < nSymbols; k++ ) { + SKP_Silk_range_decoder( &data[ k ], psRC, prob[ k ], probStartIx[ k ] ); + } +} + +/* Initialize range encoder */ +void SKP_Silk_range_enc_init( + SKP_Silk_range_coder_state *psRC /* O compressor data structure */ +) +{ + /* Initialize structure */ + psRC->bufferLength = MAX_ARITHM_BYTES; + psRC->range_Q16 = 0x0000FFFF; + psRC->bufferIx = 0; + psRC->base_Q32 = 0; + psRC->error = 0; +} + +/* Initialize range decoder */ +void SKP_Silk_range_dec_init( + SKP_Silk_range_coder_state *psRC, /* O compressor data structure */ + const SKP_uint8 buffer[], /* I buffer for compressed data [bufferLength] */ + const SKP_int32 bufferLength /* I buffer length (in bytes) */ +) +{ + /* check input */ + if( ( bufferLength > MAX_ARITHM_BYTES ) || ( bufferLength < 0 ) ) { + psRC->error = RANGE_CODER_DEC_PAYLOAD_TOO_LONG; + return; + } + /* Initialize structure */ + /* Copy to internal buffer */ + SKP_memcpy( psRC->buffer, buffer, bufferLength * sizeof( SKP_uint8 ) ); + psRC->bufferLength = bufferLength; + psRC->bufferIx = 0; + psRC->base_Q32 = + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 0 ], 24 ) | + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 1 ], 16 ) | + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 2 ], 8 ) | + (SKP_uint32)buffer[ 3 ]; + psRC->range_Q16 = 0x0000FFFF; + psRC->error = 0; +} + +/* Determine length of bitstream */ +SKP_int SKP_Silk_range_coder_get_length( /* O returns number of BITS in stream */ + const SKP_Silk_range_coder_state *psRC, /* I compressed data structure */ + SKP_int *nBytes /* O number of BYTES in stream */ +) +{ + SKP_int nBits; + + /* Number of bits in stream */ + nBits = SKP_LSHIFT( psRC->bufferIx, 3 ) + SKP_Silk_CLZ32( psRC->range_Q16 - 1 ) - 14; + + *nBytes = SKP_RSHIFT( nBits + 7, 3 ); + + /* Return number of bits in bitstream */ + return nBits; +} + +/* Write shortest uniquely decodable stream to buffer, and determine its length */ +void SKP_Silk_range_enc_wrap_up( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +) +{ + SKP_int bufferIx_tmp, bits_to_store, bits_in_stream, nBytes, mask; + SKP_uint32 base_Q24; + + /* Lower limit of interval, shifted 8 bits to the right */ + base_Q24 = SKP_RSHIFT_uint( psRC->base_Q32, 8 ); + + bits_in_stream = SKP_Silk_range_coder_get_length( psRC, &nBytes ); + + /* Number of additional bits (1..9) required to be stored to stream */ + bits_to_store = bits_in_stream - SKP_LSHIFT( psRC->bufferIx, 3 ); + /* Round up to required resolution */ + base_Q24 += SKP_RSHIFT_uint( 0x00800000, bits_to_store - 1 ); + base_Q24 &= SKP_LSHIFT_ovflw( 0xFFFFFFFF, 24 - bits_to_store ); + + /* Check for carry */ + if( base_Q24 & 0x01000000 ) { + /* Propagate carry in buffer */ + bufferIx_tmp = psRC->bufferIx; + while( ( ++( psRC->buffer[ --bufferIx_tmp ] ) ) == 0 ); + } + + /* Store to stream, making sure not to write beyond buffer */ + if( psRC->bufferIx < psRC->bufferLength ) { + psRC->buffer[ psRC->bufferIx++ ] = (SKP_uint8)SKP_RSHIFT_uint( base_Q24, 16 ); + if( bits_to_store > 8 ) { + if( psRC->bufferIx < psRC->bufferLength ) { + psRC->buffer[ psRC->bufferIx++ ] = (SKP_uint8)SKP_RSHIFT_uint( base_Q24, 8 ); + } + } + } + + /* Fill up any remaining bits in the last byte with 1s */ + if( bits_in_stream & 7 ) { + mask = SKP_RSHIFT( 0xFF, bits_in_stream & 7 ); + if( nBytes - 1 < psRC->bufferLength ) { + psRC->buffer[ nBytes - 1 ] |= mask; + } + } +} + +/* Check that any remaining bits in the last byte are set to 1 */ +void SKP_Silk_range_coder_check_after_decoding( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +) +{ + SKP_int bits_in_stream, nBytes, mask; + + bits_in_stream = SKP_Silk_range_coder_get_length( psRC, &nBytes ); + + /* Make sure not to read beyond buffer */ + if( nBytes - 1 >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_DECODER_CHECK_FAILED; + return; + } + + /* Test any remaining bits in last byte */ + if( bits_in_stream & 7 ) { + mask = SKP_RSHIFT( 0xFF, bits_in_stream & 7 ); + if( ( psRC->buffer[ nBytes - 1 ] & mask ) != mask ) { + psRC->error = RANGE_CODER_DECODER_CHECK_FAILED; + return; + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_regularize_correlations_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_regularize_correlations_FLP.c new file mode 100755 index 0000000..46cf9c1 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_regularize_correlations_FLP.c @@ -0,0 +1,43 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +void SKP_Silk_regularize_correlations_FLP( + SKP_float *XX, /* I/O Correlation matrices */ + SKP_float *xx, /* I/O Correlation values */ + const SKP_float noise, /* I Noise energy to add */ + const SKP_int D /* I Dimension of XX */ +) +{ + SKP_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler.c new file mode 100755 index 0000000..b7b7860 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler.c @@ -0,0 +1,323 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler.c * + * * + * Description: Interface to collection of resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +/* Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 32 44.1 48 + * + * 8 C UF U UF UF UF UF + * 12 AF C UF U UF UF UF + * 16 D AF C UF U UF UF + * Fs_in (kHz) 24 AIF D AF C UF UF U + * 32 UF AF D AF C UF UF + * 44.1 AMI AMI AMI AMI AMI C UF + * 48 DAF DAF AF D AF UF C + * + * default method: UF + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * DAF -> Allpass-based 2x downsampling followed by AR2 filter followed by FIR interpolation + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AMI -> ARMA4 filter followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + * + * Input signals sampled above 48 kHz are first downsampled to at most 48 kHz. + * Output signals sampled above 48 kHz are upsampled from at most 48 kHz. + */ + +#include "SKP_Silk_resampler_private.h" + +/* Greatest common divisor */ +static SKP_int32 gcd( + SKP_int32 a, + SKP_int32 b +) +{ + SKP_int32 tmp; + while( b > 0 ) { + tmp = a - b * SKP_DIV32( a, b ); + a = b; + b = tmp; + } + return a; +} + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +SKP_int SKP_Silk_resampler_init( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int32 Fs_Hz_in, /* I: Input sampling rate (Hz) */ + SKP_int32 Fs_Hz_out /* I: Output sampling rate (Hz) */ +) +{ + SKP_int32 cycleLen, cyclesPerBatch, up2 = 0, down2 = 0; + + /* Clear state */ + SKP_memset( S, 0, sizeof( SKP_Silk_resampler_state_struct ) ); + + /* Input checking */ +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + if( Fs_Hz_in < 8000 || Fs_Hz_in > 192000 || Fs_Hz_out < 8000 || Fs_Hz_out > 192000 ) { +#else + if( Fs_Hz_in < 8000 || Fs_Hz_in > 48000 || Fs_Hz_out < 8000 || Fs_Hz_out > 48000 ) { +#endif + SKP_assert( 0 ); + return -1; + } + +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + /* Determine pre downsampling and post upsampling */ + if( Fs_Hz_in > 96000 ) { + S->nPreDownsamplers = 2; + S->down_pre_function = SKP_Silk_resampler_private_down4; + } else if( Fs_Hz_in > 48000 ) { + S->nPreDownsamplers = 1; + S->down_pre_function = SKP_Silk_resampler_down2; + } else { + S->nPreDownsamplers = 0; + S->down_pre_function = NULL; + } + + if( Fs_Hz_out > 96000 ) { + S->nPostUpsamplers = 2; + S->up_post_function = SKP_Silk_resampler_private_up4; + } else if( Fs_Hz_out > 48000 ) { + S->nPostUpsamplers = 1; + S->up_post_function = SKP_Silk_resampler_up2; + } else { + S->nPostUpsamplers = 0; + S->up_post_function = NULL; + } + + if( S->nPreDownsamplers + S->nPostUpsamplers > 0 ) { + /* Ratio of output/input samples */ + S->ratio_Q16 = SKP_LSHIFT32( SKP_DIV32( SKP_LSHIFT32( Fs_Hz_out, 13 ), Fs_Hz_in ), 3 ); + /* Make sure the ratio is rounded up */ + while( SKP_SMULWW( S->ratio_Q16, Fs_Hz_in ) < Fs_Hz_out ) S->ratio_Q16++; + + /* Batch size is 10 ms */ + S->batchSizePrePost = SKP_DIV32_16( Fs_Hz_in, 100 ); + + /* Convert sampling rate to those after pre-downsampling and before post-upsampling */ + Fs_Hz_in = SKP_RSHIFT( Fs_Hz_in, S->nPreDownsamplers ); + Fs_Hz_out = SKP_RSHIFT( Fs_Hz_out, S->nPostUpsamplers ); + } +#endif + + /* Number of samples processed per batch */ + /* First, try 10 ms frames */ + S->batchSize = SKP_DIV32_16( Fs_Hz_in, 100 ); + if( ( SKP_MUL( S->batchSize, 100 ) != Fs_Hz_in ) || ( Fs_Hz_in % 100 != 0 ) ) { + /* No integer number of input or output samples with 10 ms frames, use greatest common divisor */ + cycleLen = SKP_DIV32( Fs_Hz_in, gcd( Fs_Hz_in, Fs_Hz_out ) ); + cyclesPerBatch = SKP_DIV32( RESAMPLER_MAX_BATCH_SIZE_IN, cycleLen ); + if( cyclesPerBatch == 0 ) { + /* cycleLen too big, let's just use the maximum batch size. Some distortion will result. */ + S->batchSize = RESAMPLER_MAX_BATCH_SIZE_IN; + SKP_assert( 0 ); + } else { + S->batchSize = SKP_MUL( cyclesPerBatch, cycleLen ); + } + } + + + /* Find resampler with the right sampling ratio */ + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == SKP_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = SKP_Silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + up2 = 1; + if( Fs_Hz_in > 24000 ) { + /* Low-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_up2; + } else { + /* High-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_private_up2_HQ; + } + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + if( SKP_MUL( Fs_Hz_out, 4 ) == SKP_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->Coefs = SKP_Silk_Resampler_3_4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 3 ) == SKP_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->Coefs = SKP_Silk_Resampler_2_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->Coefs = SKP_Silk_Resampler_1_2_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 8 ) == SKP_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 8 */ + S->FIR_Fracs = 3; + S->Coefs = SKP_Silk_Resampler_3_8_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->Coefs = SKP_Silk_Resampler_1_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + down2 = 1; + S->Coefs = SKP_Silk_Resampler_1_2_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + down2 = 1; + S->Coefs = SKP_Silk_Resampler_1_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 80 ) ) { /* Fs_out : Fs_in = 80 : 441 */ + S->Coefs = SKP_Silk_Resampler_80_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 120 ) ) { /* Fs_out : Fs_in = 120 : 441 */ + S->Coefs = SKP_Silk_Resampler_120_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 160 ) ) { /* Fs_out : Fs_in = 160 : 441 */ + S->Coefs = SKP_Silk_Resampler_160_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 240 ) ) { /* Fs_out : Fs_in = 240 : 441 */ + S->Coefs = SKP_Silk_Resampler_240_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 320 ) ) { /* Fs_out : Fs_in = 320 : 441 */ + S->Coefs = SKP_Silk_Resampler_320_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else { + /* Default resampler */ + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + up2 = 1; + if( Fs_Hz_in > 24000 ) { + /* Low-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_up2; + } else { + /* High-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_private_up2_HQ; + } + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = SKP_Silk_resampler_private_copy; + } + + S->input2x = up2 | down2; + + /* Ratio of input/output samples */ + S->invRatio_Q16 = SKP_LSHIFT32( SKP_DIV32( SKP_LSHIFT32( Fs_Hz_in, 14 + up2 - down2 ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( SKP_SMULWW( S->invRatio_Q16, SKP_LSHIFT32( Fs_Hz_out, down2 ) ) < SKP_LSHIFT32( Fs_Hz_in, up2 ) ) { + S->invRatio_Q16++; + } + + S->magic_number = 123456789; + + return 0; +} + +/* Clear the states of all resampling filters, without resetting sampling rate ratio */ +SKP_int SKP_Silk_resampler_clear( + SKP_Silk_resampler_state_struct *S /* I/O: Resampler state */ +) +{ + /* Clear state */ + SKP_memset( S->sDown2, 0, sizeof( S->sDown2 ) ); + SKP_memset( S->sIIR, 0, sizeof( S->sIIR ) ); + SKP_memset( S->sFIR, 0, sizeof( S->sFIR ) ); +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + SKP_memset( S->sDownPre, 0, sizeof( S->sDownPre ) ); + SKP_memset( S->sUpPost, 0, sizeof( S->sUpPost ) ); +#endif + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +SKP_int SKP_Silk_resampler( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + /* Verify that state was initialized and has not been corrupted */ + if( S->magic_number != 123456789 ) { + SKP_assert( 0 ); + return -1; + } + +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + if( S->nPreDownsamplers + S->nPostUpsamplers > 0 ) { + /* The input and/or output sampling rate is above 48000 Hz */ + SKP_int32 nSamplesIn, nSamplesOut; + SKP_int16 in_buf[ 480 ], out_buf[ 480 ]; + + while( inLen > 0 ) { + /* Number of input and output samples to process */ + nSamplesIn = SKP_min( inLen, S->batchSizePrePost ); + nSamplesOut = SKP_SMULWB( S->ratio_Q16, nSamplesIn ); + + SKP_assert( SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) <= 480 ); + SKP_assert( SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) <= 480 ); + + if( S->nPreDownsamplers > 0 ) { + S->down_pre_function( S->sDownPre, in_buf, in, nSamplesIn ); + if( S->nPostUpsamplers > 0 ) { + S->resampler_function( S, out_buf, in_buf, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + S->up_post_function( S->sUpPost, out, out_buf, SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) ); + } else { + S->resampler_function( S, out, in_buf, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + } + } else { + S->resampler_function( S, out_buf, in, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + S->up_post_function( S->sUpPost, out, out_buf, SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) ); + } + + in += nSamplesIn; + out += nSamplesOut; + inLen -= nSamplesIn; + } + } else +#endif + { + /* Input and output sampling rate are at most 48000 Hz */ + S->resampler_function( S, out, in, inLen ); + } + + return 0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2.c new file mode 100755 index 0000000..5d863c7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down2.c * + * * + * Downsample by a factor 2, mediocre quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_rom.h" + +/* Downsample by a factor 2, mediocre quality */ +void SKP_Silk_resampler_down2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ len ] */ + const SKP_int16 *in, /* I: Input signal [ floor(len/2) ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 k, len2 = SKP_RSHIFT32( inLen, 1 ); + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_down2_0 > 0 ); + SKP_assert( SKP_Silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_down2_1 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_down2_0 ); + out32 = SKP_ADD32( out32, S[ 1 ] ); + out32 = SKP_ADD32( out32, X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 11 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2_3.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2_3.c new file mode 100755 index 0000000..fb91eb9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down2_3.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down2_3.c * + * * + * Downsample by a factor 2/3, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void SKP_Silk_resampler_down2_3( + SKP_int32 *S, /* I/O: State vector [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ floor(2*inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 nSamplesIn, counter, res_Q6; + SKP_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + SKP_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S, ORDER_FIR * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = SKP_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + SKP_Silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = SKP_SMULWB( buf_ptr[ 0 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 1 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = SKP_SMULWB( buf_ptr[ 1 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 4 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down3.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down3.c new file mode 100755 index 0000000..a716d5c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_down3.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down3.c * + * * + * Downsample by a factor 3, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +#define ORDER_FIR 6 + +/* Downsample by a factor 3, low quality */ +void SKP_Silk_resampler_down3( + SKP_int32 *S, /* I/O: State vector [ 8 ] */ + SKP_int16 *out, /* O: Output signal [ floor(inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 nSamplesIn, counter, res_Q6; + SKP_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + SKP_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S, ORDER_FIR * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = SKP_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + SKP_Silk_Resampler_1_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = SKP_SMULWB( SKP_ADD32( buf_ptr[ 0 ], buf_ptr[ 5 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 1 ], buf_ptr[ 4 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 2 ], buf_ptr[ 3 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private.h new file mode 100755 index 0000000..e7159e1 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private.h @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_structs.h * + * * + * Description: Structs for IIR/FIR resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * * + * */ + +#ifndef SKP_Silk_RESAMPLER_H +#define SKP_Silk_RESAMPLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_structs.h" +#include "SKP_Silk_resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_IN 480 + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void SKP_Silk_resampler_private_IIR_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void SKP_Silk_resampler_private_down_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Copy */ +void SKP_Silk_resampler_private_copy( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void SKP_Silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void SKP_Silk_resampler_private_up2_HQ( + SKP_int32 *S, /* I/O: Resampler state [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Upsample 4x, low quality */ +void SKP_Silk_resampler_private_up4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 4 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Downsample 4x, low quality */ +void SKP_Silk_resampler_private_down4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ floor(len/2) ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Second order AR filter */ +void SKP_Silk_resampler_private_AR2( + SKP_int32 S[], /* I/O: State vector [ 2 ] */ + SKP_int32 out_Q8[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 A_Q14[], /* I: AR coefficients, Q14 */ + SKP_int32 len /* I: Signal length */ +); + +/* Fourth order ARMA filter */ +void SKP_Silk_resampler_private_ARMA4( + SKP_int32 S[], /* I/O: State vector [ 4 ] */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 Coef[], /* I: ARMA coefficients [ 7 ] */ + SKP_int32 len /* I: Signal length */ +); + + +#ifdef __cplusplus +} +#endif +#endif // SKP_Silk_RESAMPLER_H + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_AR2.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_AR2.c new file mode 100755 index 0000000..02b0f5d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_AR2.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_AR2. c * + * * + * Second order AR filter with single delay elements * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Second order AR filter with single delay elements */ +void SKP_Silk_resampler_private_AR2( + SKP_int32 S[], /* I/O: State vector [ 2 ] */ + SKP_int32 out_Q8[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 A_Q14[], /* I: AR coefficients, Q14 */ + SKP_int32 len /* I: Signal length */ +) +{ + SKP_int32 k; + SKP_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = SKP_ADD_LSHIFT32( S[ 0 ], (SKP_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = SKP_LSHIFT( out32, 2 ); + S[ 0 ] = SKP_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = SKP_SMULWB( out32, A_Q14[ 1 ] ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_ARMA4.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_ARMA4.c new file mode 100755 index 0000000..22259cf --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_ARMA4.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_ARMA4.c * + * * + * Fourth order ARMA filter, applies 64x gain * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Fourth order ARMA filter */ +/* Internally operates as two biquad filters in sequence. */ + +/* Coeffients are stored in a packed format: */ +/* { B1_Q14[1], B2_Q14[1], -A1_Q14[1], -A1_Q14[2], -A2_Q14[1], -A2_Q14[2], gain_Q16 } */ +/* where it is assumed that B*_Q14[0], B*_Q14[2], A*_Q14[0] are all 16384 */ +void SKP_Silk_resampler_private_ARMA4( + SKP_int32 S[], /* I/O: State vector [ 4 ] */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 Coef[], /* I: ARMA coefficients [ 7 ] */ + SKP_int32 len /* I: Signal length */ +) +{ + SKP_int32 k; + SKP_int32 in_Q8, out1_Q8, out2_Q8, X; + + for( k = 0; k < len; k++ ) { + in_Q8 = SKP_LSHIFT32( (SKP_int32)in[ k ], 8 ); + + /* Outputs of first and second biquad */ + out1_Q8 = SKP_ADD_LSHIFT32( in_Q8, S[ 0 ], 2 ); + out2_Q8 = SKP_ADD_LSHIFT32( out1_Q8, S[ 2 ], 2 ); + + /* Update states, which are stored in Q6. Coefficients are in Q14 here */ + X = SKP_SMLAWB( S[ 1 ], in_Q8, Coef[ 0 ] ); + S[ 0 ] = SKP_SMLAWB( X, out1_Q8, Coef[ 2 ] ); + + X = SKP_SMLAWB( S[ 3 ], out1_Q8, Coef[ 1 ] ); + S[ 2 ] = SKP_SMLAWB( X, out2_Q8, Coef[ 4 ] ); + + S[ 1 ] = SKP_SMLAWB( SKP_RSHIFT32( in_Q8, 2 ), out1_Q8, Coef[ 3 ] ); + S[ 3 ] = SKP_SMLAWB( SKP_RSHIFT32( out1_Q8, 2 ), out2_Q8, Coef[ 5 ] ); + + /* Apply gain and store to output. The coefficient is in Q16 */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( SKP_SMLAWB( 128, out2_Q8, Coef[ 6 ] ), 8 ) ); + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_IIR_FIR.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_IIR_FIR.c new file mode 100755 index 0000000..1b46b11 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_IIR_FIR.c @@ -0,0 +1,105 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_IIR_FIR.c * + * * + * Description: Hybrid IIR/FIR polyphase implementation of resampling * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_IIR_FIR_INTERPOL( + SKP_int16 * out, SKP_int16 * buf, SKP_int32 max_index_Q16 , SKP_int32 index_increment_Q16 ){ + SKP_int32 index_Q16, res_Q15; + SKP_int16 *buf_ptr; + SKP_int32 table_index; + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = SKP_SMULWB( index_Q16 & 0xFFFF, 144 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = SKP_SMULBB( buf_ptr[ 0 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 0 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 1 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 1 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 2 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 2 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 3 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 2 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 4 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 1 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 5 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 0 ] ); + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void SKP_Silk_resampler_private_IIR_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_int32 nSamplesIn; + SKP_int32 max_index_Q16, index_increment_Q16; + SKP_int16 buf[ 2 * RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_144 ]; + + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = SKP_min( inLen, S->batchSize ); + + if( S->input2x == 1 ) { + /* Upsample 2x */ + S->up2_function( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, nSamplesIn ); + } else { + /* Fourth-order ARMA filter */ + SKP_Silk_resampler_private_ARMA4( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, S->Coefs, nSamplesIn ); + } + + max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 + S->input2x ); /* +1 if 2x upsampling */ + out = SKP_Silk_resampler_private_IIR_FIR_INTERPOL(out, buf, max_index_Q16, index_increment_Q16); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S->sFIR, &buf[nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_copy.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_copy.c new file mode 100755 index 0000000..093fb0b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_copy.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_copy.c * + * * + * Description: Copy. * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Copy */ +void SKP_Silk_resampler_private_copy( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_memcpy( out, in, inLen * sizeof( SKP_int16 ) ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down4.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down4.c new file mode 100755 index 0000000..5cce504 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down4.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_down4.c * + * * + * Downsample by a factor 4 * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Downsample by a factor 4. Note: very low quality, only use with input sampling rates above 96 kHz. */ +void SKP_Silk_resampler_private_down4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ floor(len/2) ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 k, len4 = SKP_RSHIFT32( inLen, 2 ); + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_down2_0 > 0 ); + SKP_assert( SKP_Silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len4; k++ ) { + /* Add two input samples and convert to Q10 */ + in32 = SKP_LSHIFT( SKP_ADD32( (SKP_int32)in[ 4 * k ], (SKP_int32)in[ 4 * k + 1 ] ), 9 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_down2_1 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Add two input samples and convert to Q10 */ + in32 = SKP_LSHIFT( SKP_ADD32( (SKP_int32)in[ 4 * k + 2 ], (SKP_int32)in[ 4 * k + 3 ] ), 9 ); + + /* All-pass section for odd input sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_down2_0 ); + out32 = SKP_ADD32( out32, S[ 1 ] ); + out32 = SKP_ADD32( out32, X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 11 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down_FIR.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down_FIR.c new file mode 100755 index 0000000..5bb5475 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_down_FIR.c @@ -0,0 +1,160 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_down_FIR.c * + * * + * Description: Hybrid IIR/FIR polyphase implementation of resampling * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL0( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16){ + + SKP_int32 index_Q16, res_Q6; + SKP_int32 *buf_ptr; + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = SKP_SMULWB( SKP_ADD32( buf_ptr[ 0 ], buf_ptr[ 11 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 1 ], buf_ptr[ 10 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 2 ], buf_ptr[ 9 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 3 ], buf_ptr[ 8 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 4 ], buf_ptr[ 7 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 5 ], buf_ptr[ 6 ] ), FIR_Coefs[ 5 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + } + return out; +} + +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL1( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16, SKP_int32 FIR_Fracs){ + + SKP_int32 index_Q16, res_Q6; + SKP_int32 *buf_ptr; + SKP_int32 interpol_ind; + const SKP_int16 *interpol_ptr; + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = SKP_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * interpol_ind ]; + res_Q6 = SKP_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 5 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + } + return out; +} + + +/* Resample with a 2x downsampler (optional), a 2nd order AR filter followed by FIR interpolation */ +void SKP_Silk_resampler_private_down_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_int32 nSamplesIn; + SKP_int32 max_index_Q16, index_increment_Q16; + SKP_int16 buf1[ RESAMPLER_MAX_BATCH_SIZE_IN / 2 ]; + SKP_int32 buf2[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_DOWN_ORDER_FIR ]; + const SKP_int16 *FIR_Coefs; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf2, S->sFIR, RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = SKP_min( inLen, S->batchSize ); + + if( S->input2x == 1 ) { + /* Downsample 2x */ + SKP_Silk_resampler_down2( S->sDown2, buf1, in, nSamplesIn ); + + nSamplesIn = SKP_RSHIFT32( nSamplesIn, 1 ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], buf1, S->Coefs, nSamplesIn ); + } else { + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], in, S->Coefs, nSamplesIn ); + } + + max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + if( S->FIR_Fracs == 1 ) { + out = SKP_Silk_resampler_private_down_FIR_INTERPOL0(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16); + } else { + out = SKP_Silk_resampler_private_down_FIR_INTERPOL1(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16, S->FIR_Fracs); + } + + in += nSamplesIn << S->input2x; + inLen -= nSamplesIn << S->input2x; + + if( inLen > S->input2x ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf2, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S->sFIR, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up2_HQ.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up2_HQ.c new file mode 100755 index 0000000..8015c91 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up2_HQ.c @@ -0,0 +1,118 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_up2_HQ.c * + * * + * Upsample by a factor 2, high quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void SKP_Silk_resampler_private_up2_HQ( + SKP_int32 *S, /* I/O: Resampler state [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of INPUT samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32_1, out32_2, Y, X; + + SKP_assert( SKP_Silk_resampler_up2_hq_0[ 0 ] > 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_0[ 1 ] < 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_1[ 0 ] > 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_1[ 1 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = SKP_SUB32( out32_1, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( out32_1, X ); + + /* Biquad notch filter */ + out32_2 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 2 ] ); + out32_2 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 1 ] ); + out32_1 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 0 ] ); + S[ 5 ] = SKP_SUB32( out32_2, S[ 5 ] ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( + SKP_SMLAWB( 256, out32_1, SKP_Silk_resampler_up2_hq_notch[ 3 ] ), 9 ) ); + + /* First all-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 2 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = SKP_ADD32( S[ 2 ], X ); + S[ 2 ] = SKP_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = SKP_SUB32( out32_1, S[ 3 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = SKP_ADD32( S[ 3 ], X ); + S[ 3 ] = SKP_ADD32( out32_1, X ); + + /* Biquad notch filter */ + out32_2 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 2 ] ); + out32_2 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 1 ] ); + out32_1 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 0 ] ); + S[ 4 ] = SKP_SUB32( out32_2, S[ 4 ] ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( + SKP_SMLAWB( 256, out32_1, SKP_Silk_resampler_up2_hq_notch[ 3 ] ), 9 ) ); + } +} + + +void SKP_Silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_Silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up4.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up4.c new file mode 100755 index 0000000..f13347f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_private_up4.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_up4.c * + * * + * Upsample by a factor 4, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Upsample by a factor 4, Note: very low quality, only use with output sampling rates above 96 kHz. */ +void SKP_Silk_resampler_private_up4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 4 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of INPUT samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32, Y, X; + SKP_int16 out16; + + SKP_assert( SKP_Silk_resampler_up2_lq_0 > 0 ); + SKP_assert( SKP_Silk_resampler_up2_lq_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* All-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_lq_0 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out16 = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + out[ 4 * k ] = out16; + out[ 4 * k + 1 ] = out16; + + /* All-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_lq_1 ); + out32 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out16 = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + out[ 4 * k + 2 ] = out16; + out[ 4 * k + 3 ] = out16; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.c new file mode 100755 index 0000000..5315ce5 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.c @@ -0,0 +1,269 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_rom.c * + * * + * Description: Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 550 Words (1.1 kB) * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_resampler_private.h" + +/* Tables for 2x downsampler */ +const SKP_int16 SKP_Silk_resampler_down2_0 = 9872; +const SKP_int16 SKP_Silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, low quality */ +const SKP_int16 SKP_Silk_resampler_up2_lq_0 = 8102; +const SKP_int16 SKP_Silk_resampler_up2_lq_1 = 36783 - 65536; + +/* Tables for 2x upsampler, high quality */ +const SKP_int16 SKP_Silk_resampler_up2_hq_0[ 2 ] = { 4280, 33727 - 65536 }; +const SKP_int16 SKP_Silk_resampler_up2_hq_1[ 2 ] = { 16295, 54015 - 65536 }; +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.12, 1]; A = [1, 0.055, 0.8]; G = 0.87; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]); */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +const SKP_int16 SKP_Silk_resampler_up2_hq_notch[ 4 ] = { 7864, -3604, 13107, 28508 }; + + +/* Tables with IIR and FIR coefficients for fractional downsamplers (70 Words) */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + -18249, -12532, + -97, 284, -495, 309, 10268, 20317, + -94, 156, -48, -720, 5984, 18278, + -45, -4, 237, -847, 2540, 14662, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + -11891, -12486, + 20, 211, -657, 688, 8423, 15911, + -44, 197, -152, -653, 3855, 13015, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 2415, -13101, + 158, -295, -400, 1265, 4832, 7968, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_3_8_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 13270, -13738, + -294, -123, 747, 2043, 3339, 3995, + -151, -311, 414, 1583, 2947, 3877, + -33, -389, 143, 1141, 2503, 3653, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 16643, -14000, + -331, 19, 581, 1421, 2290, 2845, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 + 3 ] = { + 16777, -9792, + 890, 1614, 2148, +}; + + +/* Tables with coefficients for 4th order ARMA filter (35 Words), in a packed format: */ +/* { B1_Q14[1], B2_Q14[1], -A1_Q14[1], -A1_Q14[2], -A2_Q14[1], -A2_Q14[2], gain_Q16 } */ +/* where it is assumed that B*_Q14[0], B*_Q14[2], A*_Q14[0] are all 16384 */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_320_441_ARMA4_COEFS[ 7 ] = { + 31454, 24746, -9706, -3386, -17911, -13243, 24797 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_240_441_ARMA4_COEFS[ 7 ] = { + 28721, 11254, 3189, -2546, -1495, -12618, 11562 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_160_441_ARMA4_COEFS[ 7 ] = { + 23492, -6457, 14358, -4856, 14654, -13008, 4456 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_120_441_ARMA4_COEFS[ 7 ] = { + 19311, -15569, 19489, -6950, 21441, -13559, 2370 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_80_441_ARMA4_COEFS[ 7 ] = { + 13248, -23849, 24126, -9486, 26806, -14286, 1065 +}; + +/* Table with interplation fractions of 1/288 : 2/288 : 287/288 (432 Words) */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_resampler_frac_FIR_144[ 144 ][ RESAMPLER_ORDER_FIR_144 / 2 ] = { + { -647, 1884, 30078}, + { -625, 1736, 30044}, + { -603, 1591, 30005}, + { -581, 1448, 29963}, + { -559, 1308, 29917}, + { -537, 1169, 29867}, + { -515, 1032, 29813}, + { -494, 898, 29755}, + { -473, 766, 29693}, + { -452, 636, 29627}, + { -431, 508, 29558}, + { -410, 383, 29484}, + { -390, 260, 29407}, + { -369, 139, 29327}, + { -349, 20, 29242}, + { -330, -97, 29154}, + { -310, -211, 29062}, + { -291, -324, 28967}, + { -271, -434, 28868}, + { -253, -542, 28765}, + { -234, -647, 28659}, + { -215, -751, 28550}, + { -197, -852, 28436}, + { -179, -951, 28320}, + { -162, -1048, 28200}, + { -144, -1143, 28077}, + { -127, -1235, 27950}, + { -110, -1326, 27820}, + { -94, -1414, 27687}, + { -77, -1500, 27550}, + { -61, -1584, 27410}, + { -45, -1665, 27268}, + { -30, -1745, 27122}, + { -15, -1822, 26972}, + { 0, -1897, 26820}, + { 15, -1970, 26665}, + { 29, -2041, 26507}, + { 44, -2110, 26346}, + { 57, -2177, 26182}, + { 71, -2242, 26015}, + { 84, -2305, 25845}, + { 97, -2365, 25673}, + { 110, -2424, 25498}, + { 122, -2480, 25320}, + { 134, -2534, 25140}, + { 146, -2587, 24956}, + { 157, -2637, 24771}, + { 168, -2685, 24583}, + { 179, -2732, 24392}, + { 190, -2776, 24199}, + { 200, -2819, 24003}, + { 210, -2859, 23805}, + { 220, -2898, 23605}, + { 229, -2934, 23403}, + { 238, -2969, 23198}, + { 247, -3002, 22992}, + { 255, -3033, 22783}, + { 263, -3062, 22572}, + { 271, -3089, 22359}, + { 279, -3114, 22144}, + { 286, -3138, 21927}, + { 293, -3160, 21709}, + { 300, -3180, 21488}, + { 306, -3198, 21266}, + { 312, -3215, 21042}, + { 318, -3229, 20816}, + { 323, -3242, 20589}, + { 328, -3254, 20360}, + { 333, -3263, 20130}, + { 338, -3272, 19898}, + { 342, -3278, 19665}, + { 346, -3283, 19430}, + { 350, -3286, 19194}, + { 353, -3288, 18957}, + { 356, -3288, 18718}, + { 359, -3286, 18478}, + { 362, -3283, 18238}, + { 364, -3279, 17996}, + { 366, -3273, 17753}, + { 368, -3266, 17509}, + { 369, -3257, 17264}, + { 371, -3247, 17018}, + { 372, -3235, 16772}, + { 372, -3222, 16525}, + { 373, -3208, 16277}, + { 373, -3192, 16028}, + { 373, -3175, 15779}, + { 373, -3157, 15529}, + { 372, -3138, 15279}, + { 371, -3117, 15028}, + { 370, -3095, 14777}, + { 369, -3072, 14526}, + { 368, -3048, 14274}, + { 366, -3022, 14022}, + { 364, -2996, 13770}, + { 362, -2968, 13517}, + { 359, -2940, 13265}, + { 357, -2910, 13012}, + { 354, -2880, 12760}, + { 351, -2848, 12508}, + { 348, -2815, 12255}, + { 344, -2782, 12003}, + { 341, -2747, 11751}, + { 337, -2712, 11500}, + { 333, -2676, 11248}, + { 328, -2639, 10997}, + { 324, -2601, 10747}, + { 320, -2562, 10497}, + { 315, -2523, 10247}, + { 310, -2482, 9998}, + { 305, -2442, 9750}, + { 300, -2400, 9502}, + { 294, -2358, 9255}, + { 289, -2315, 9009}, + { 283, -2271, 8763}, + { 277, -2227, 8519}, + { 271, -2182, 8275}, + { 265, -2137, 8032}, + { 259, -2091, 7791}, + { 252, -2045, 7550}, + { 246, -1998, 7311}, + { 239, -1951, 7072}, + { 232, -1904, 6835}, + { 226, -1856, 6599}, + { 219, -1807, 6364}, + { 212, -1758, 6131}, + { 204, -1709, 5899}, + { 197, -1660, 5668}, + { 190, -1611, 5439}, + { 183, -1561, 5212}, + { 175, -1511, 4986}, + { 168, -1460, 4761}, + { 160, -1410, 4538}, + { 152, -1359, 4317}, + { 145, -1309, 4098}, + { 137, -1258, 3880}, + { 129, -1207, 3664}, + { 121, -1156, 3450}, + { 113, -1105, 3238}, + { 105, -1054, 3028}, + { 97, -1003, 2820}, + { 89, -952, 2614}, + { 81, -901, 2409}, + { 73, -851, 2207}, +}; diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.h new file mode 100755 index 0000000..4792721 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_rom.h @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resample_rom.h * + * * + * Description: Header file for FIR resampling of * + * 32 and 44 kHz input * + * * + * Copyright 2007 (c), Skype Limited * + * All rights reserved. * + * * + * Date: 070807 * + * */ + +#ifndef _SKP_SILK_FIX_RESAMPLER_ROM_H_ +#define _SKP_SILK_FIX_RESAMPLER_ROM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR 12 +#define RESAMPLER_ORDER_FIR_144 6 + + +/* Tables for 2x downsampler. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_down2_0; +extern const SKP_int16 SKP_Silk_resampler_down2_1; + +/* Tables for 2x upsampler, low quality. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_up2_lq_0; +extern const SKP_int16 SKP_Silk_resampler_up2_lq_1; + +/* Tables for 2x upsampler, high quality. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_up2_hq_0[ 2 ]; +extern const SKP_int16 SKP_Silk_resampler_up2_hq_1[ 2 ]; +extern const SKP_int16 SKP_Silk_resampler_up2_hq_notch[ 4 ]; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const SKP_int16 SKP_Silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_3_8_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 + 3 ]; + +/* Tables with coefficients for 4th order ARMA filter */ +extern const SKP_int16 SKP_Silk_Resampler_320_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_240_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_160_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_120_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_80_441_ARMA4_COEFS[ 7 ]; + +/* Table with interplation fractions of 1/288 : 2/288 : 287/288 (432 Words) */ +extern const SKP_int16 SKP_Silk_resampler_frac_FIR_144[ 144 ][ RESAMPLER_ORDER_FIR_144 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif // _SKP_SILK_FIX_RESAMPLER_ROM_H_ diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_structs.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_structs.h new file mode 100755 index 0000000..c44bbc9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_structs.h @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_structs.h * + * * + * Description: Structs for IIR/FIR resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * * + * */ + +#ifndef SKP_Silk_RESAMPLER_STRUCTS_H +#define SKP_Silk_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flag to enable support for input/output sampling rates above 48 kHz. Turn off for embedded devices */ +#define RESAMPLER_SUPPORT_ABOVE_48KHZ 1 + +#define SKP_Silk_RESAMPLER_MAX_FIR_ORDER 16 +#define SKP_Silk_RESAMPLER_MAX_IIR_ORDER 6 + + +typedef struct _SKP_Silk_resampler_state_struct{ + SKP_int32 sIIR[ SKP_Silk_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + SKP_int32 sFIR[ SKP_Silk_RESAMPLER_MAX_FIR_ORDER ]; + SKP_int32 sDown2[ 2 ]; + void (*resampler_function)( void *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + void (*up2_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + SKP_int32 batchSize; + SKP_int32 invRatio_Q16; + SKP_int32 FIR_Fracs; + SKP_int32 input2x; + const SKP_int16 *Coefs; +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + SKP_int32 sDownPre[ 2 ]; + SKP_int32 sUpPost[ 2 ]; + void (*down_pre_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + void (*up_post_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + SKP_int32 batchSizePrePost; + SKP_int32 ratio_Q16; + SKP_int32 nPreDownsamplers; + SKP_int32 nPostUpsamplers; +#endif + SKP_int32 magic_number; +} SKP_Silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SKP_Silk_RESAMPLER_STRUCTS_H */ + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_up2.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_up2.c new file mode 100755 index 0000000..c452cc6 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_resampler_up2.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_up2.c * + * * + * Upsample by a factor 2, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_rom.h" + +/* Upsample by a factor 2, low quality */ +void SKP_Silk_resampler_up2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_up2_lq_0 > 0 ); + SKP_assert( SKP_Silk_resampler_up2_lq_1 < 0 ); + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* All-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_lq_0 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out[ 2 * k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + + /* All-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_lq_1 ); + out32 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_residual_energy_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_residual_energy_FLP.c new file mode 100755 index 0000000..2fd63f0 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_residual_energy_FLP.c @@ -0,0 +1,110 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_float SKP_Silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const SKP_float *c, /* I Filter coefficients */ + SKP_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const SKP_float *wXx, /* I Weighted correlation vector */ + const SKP_float wxx, /* I Weighted correlation value */ + const SKP_int D /* I Dimension */ +) +{ + SKP_int i, j, k; + SKP_float tmp, nrg, regularization; + + /* Safety checks */ + SKP_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + SKP_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void SKP_Silk_residual_energy_FLP( + SKP_float nrgs[], /* O Residual energy per subframe */ + const SKP_float x[], /* I Input signal */ + SKP_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const SKP_float gains[], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int shift; + SKP_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + SKP_Silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( SKP_float )( gains[ 0 ] * gains[ 0 ] * SKP_Silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( SKP_float )( gains[ 1 ] * gains[ 1 ] * SKP_Silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + SKP_Silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( SKP_float )( gains[ 2 ] * gains[ 2 ] * SKP_Silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( SKP_float )( gains[ 3 ] * gains[ 3 ] * SKP_Silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_copy_vector_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_copy_vector_FLP.c new file mode 100755 index 0000000..c02492e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_copy_vector_FLP.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void SKP_Silk_scale_copy_vector_FLP( + SKP_float *data_out, + const SKP_float *data_in, + SKP_float gain, + SKP_int dataSize +) +{ + SKP_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_vector_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_vector_FLP.c new file mode 100755 index 0000000..84551a0 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_scale_vector_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FLP.h" + +/* multiply a vector by a constant */ +void SKP_Silk_scale_vector_FLP( + SKP_float *data1, + SKP_float gain, + SKP_int dataSize +) +{ + SKP_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_schur_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_schur_FLP.c new file mode 100755 index 0000000..7ca2afc --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_schur_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_schur.c * + * * + * Calculates the reflection coefficients from the correlation sequence * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + */ + +#include "SKP_Silk_SigProc_FLP.h" + +SKP_float SKP_Silk_schur_FLP( /* O returns residual energy */ + SKP_float refl_coef[], /* O reflection coefficients (length order) */ + const SKP_float auto_corr[], /* I autotcorrelation sequence (length order+1) */ + SKP_int order /* I order */ +) +{ + SKP_int k, n; + SKP_float C[SKP_Silk_MAX_ORDER_LPC + 1][2]; + SKP_float Ctmp1, Ctmp2, rc_tmp; + + /* copy correlations */ + for( k = 0; k < order+1; k++ ){ + C[k][0] = C[k][1] = auto_corr[k]; + } + + for( k = 0; k < order; k++ ) { + /* get reflection coefficient */ + rc_tmp = -C[k + 1][0] / SKP_max_float( C[0][1], 1e-9f ); + + /* save the output */ + refl_coef[k] = rc_tmp; + + /* update correlations */ + for( n = 0; n < order - k; n++ ){ + Ctmp1 = C[n + k + 1][0]; + Ctmp2 = C[n][1]; + C[n + k + 1][0] = Ctmp1 + Ctmp2 * rc_tmp; + C[n][1] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* return residual energy */ + return C[0][1]; +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_setup_complexity.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_setup_complexity.h new file mode 100755 index 0000000..25bcefd --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_setup_complexity.h @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" +#include "SKP_Silk_tuning_parameters.h" + +SKP_INLINE SKP_int SKP_Silk_setup_complexity( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Check that settings are valid */ + if( LOW_COMPLEXITY_ONLY && Complexity != 0 ) { + ret = SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + /* Set encoding complexity */ + if( Complexity == 0 || LOW_COMPLEXITY_ONLY ) { + /* Low complexity */ + psEncC->Complexity = 0; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_LC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_LC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 8; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 1; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS_LC_MODE; + psEncC->warping_Q16 = 0; + } else if( Complexity == 1 ) { + /* Medium complexity */ + psEncC->Complexity = 1; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_MC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_MC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS_MC_MODE; + psEncC->warping_Q16 = psEncC->fs_kHz * SKP_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity == 2 ) { + /* High complexity */ + psEncC->Complexity = 2; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_HC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_HC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS; + psEncC->warping_Q16 = psEncC->fs_kHz * SKP_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + ret = SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = SKP_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = 5 * psEncC->fs_kHz + 2 * psEncC->la_shape; + + SKP_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + SKP_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + SKP_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + SKP_assert( psEncC->warping_Q16 <= 32767 ); + SKP_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + SKP_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return( ret ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_shell_coder.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_shell_coder.c new file mode 100755 index 0000000..9d0f546 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_shell_coder.c @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +SKP_INLINE void combine_pulses( + SKP_int *out, /* O: combined pulses vector [len] */ + const SKP_int *in, /* I: input vector [2 * len] */ + const SKP_int len /* I: number of OUTPUT samples */ +) +{ + SKP_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +SKP_INLINE void encode_split( + SKP_Silk_range_coder_state *sRC, /* I/O: compressor data structure */ + const SKP_int p_child1, /* I: pulse amplitude of first child subframe */ + const SKP_int p, /* I: pulse amplitude of current subframe */ + const SKP_uint16 *shell_table /* I: table of shell cdfs */ +) +{ + const SKP_uint16 *cdf; + + if( p > 0 ) { + cdf = &shell_table[ SKP_Silk_shell_code_table_offsets[ p ] ]; + SKP_Silk_range_encoder( sRC, p_child1, cdf ); + } +} + +SKP_INLINE void decode_split( + SKP_int *p_child1, /* O: pulse amplitude of first child subframe */ + SKP_int *p_child2, /* O: pulse amplitude of second child subframe */ + SKP_Silk_range_coder_state *sRC, /* I/O: compressor data structure */ + const SKP_int p, /* I: pulse amplitude of current subframe */ + const SKP_uint16 *shell_table /* I: table of shell cdfs */ +) +{ + SKP_int cdf_middle; + const SKP_uint16 *cdf; + + if( p > 0 ) { + cdf_middle = SKP_RSHIFT( p, 1 ); + cdf = &shell_table[ SKP_Silk_shell_code_table_offsets[ p ] ]; + SKP_Silk_range_decoder( p_child1, sRC, cdf, cdf_middle ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_encoder( + SKP_Silk_range_coder_state *sRC, /* I/O compressor data structure */ + const SKP_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + SKP_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + SKP_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( sRC, pulses3[ 0 ], pulses4[ 0 ], SKP_Silk_shell_code_table3 ); + + encode_split( sRC, pulses2[ 0 ], pulses3[ 0 ], SKP_Silk_shell_code_table2 ); + + encode_split( sRC, pulses1[ 0 ], pulses2[ 0 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 0 ], pulses1[ 0 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 2 ], pulses1[ 1 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses1[ 2 ], pulses2[ 1 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 4 ], pulses1[ 2 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 6 ], pulses1[ 3 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses2[ 2 ], pulses3[ 1 ], SKP_Silk_shell_code_table2 ); + + encode_split( sRC, pulses1[ 4 ], pulses2[ 2 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 8 ], pulses1[ 4 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 10 ], pulses1[ 5 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses1[ 6 ], pulses2[ 3 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 12 ], pulses1[ 6 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 14 ], pulses1[ 7 ], SKP_Silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_decoder( + SKP_int *pulses0, /* O data: nonnegative pulse amplitudes */ + SKP_Silk_range_coder_state *sRC, /* I/O compressor data structure */ + const SKP_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + SKP_int pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + SKP_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], sRC, pulses4, SKP_Silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], sRC, pulses3[ 0 ], SKP_Silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], sRC, pulses2[ 0 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], sRC, pulses1[ 0 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], sRC, pulses1[ 1 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], sRC, pulses2[ 1 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], sRC, pulses1[ 2 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], sRC, pulses1[ 3 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], sRC, pulses3[ 1 ], SKP_Silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], sRC, pulses2[ 2 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], sRC, pulses1[ 4 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], sRC, pulses1[ 5 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], sRC, pulses2[ 3 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], sRC, pulses1[ 6 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], sRC, pulses1[ 7 ], SKP_Silk_shell_code_table0 ); +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sigm_Q15.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sigm_Q15.c new file mode 100755 index 0000000..586c157 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sigm_Q15.c @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_sigm_Q15.c * + * * + * Approximate sigmoid function * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" +/********************************/ +/* approximate sigmoid function */ +/********************************/ +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const SKP_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const SKP_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const SKP_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +SKP_int SKP_Silk_sigm_Q15( SKP_int in_Q5 ) +{ + SKP_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = SKP_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - SKP_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = SKP_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + SKP_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_solve_LS_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_solve_LS_FLP.c new file mode 100755 index 0000000..91fa609 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_solve_LS_FLP.c @@ -0,0 +1,203 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" +#include "SKP_Silk_tuning_parameters.h" + +/********************************************************************** + * LDL Factorisation. Finds the upper triangular matrix L and the diagonal + * Matrix D (only the diagonal elements returned in a vector)such that + * the symmetric matric A is given by A = L*D*L'. + **********************************************************************/ +void SKP_Silk_LDL_FLP( + SKP_float *A, /* (I/O) Pointer to Symetric Square Matrix */ + SKP_int M, /* (I) Size of Matrix */ + SKP_float *L, /* (I/O) Pointer to Square Upper triangular Matrix */ + SKP_float *Dinv /* (I/O) Pointer to vector holding the inverse diagonal elements of D */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM lower + * triangular matrix, with ones on the diagonal. + **********************************************************************/ +void SKP_Silk_SolveWithLowerTriangularWdiagOnes_FLP( + const SKP_float *L, /* (I) Pointer to Lower Triangular Matrix */ + SKP_int M, /* (I) Dim of Matrix equation */ + const SKP_float *b, /* (I) b Vector */ + SKP_float *x /* (O) x Vector */ +); + +/********************************************************************** + * Function to solve linear equation (A^T)x = b, when A is a MxM lower + * triangular, with ones on the diagonal. (ie then A^T is upper triangular) + **********************************************************************/ +void SKP_Silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const SKP_float *L, /* (I) Pointer to Lower Triangular Matrix */ + SKP_int M, /* (I) Dim of Matrix equation */ + const SKP_float *b, /* (I) b Vector */ + SKP_float *x /* (O) x Vector */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM + * symmetric square matrix - using LDL factorisation + **********************************************************************/ +void SKP_Silk_solve_LDL_FLP( + SKP_float *A, /* I/O Symmetric square matrix, out: reg. */ + const SKP_int M, /* I Size of matrix */ + const SKP_float *b, /* I Pointer to b vector */ + SKP_float *x /* O Pointer to x solution vector */ +) +{ + SKP_int i; + SKP_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ]; + SKP_float T[ MAX_MATRIX_SIZE ]; + SKP_float Dinv[ MAX_MATRIX_SIZE ]; // inverse diagonal elements of D + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*(L^T), + where L is lower triangular with ones on diagonal + ****************************************************/ + SKP_Silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv ); + + /**************************************************** + * substitute D*(L^T) = T. ie: + L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b + ******************************************************/ + SKP_Silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T ); + + /**************************************************** + D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + for( i = 0; i < M; i++ ) { + T[ i ] = T[ i ] * Dinv[ i ]; + } + /**************************************************** + x = inv(L') * inv(D) * T + *****************************************************/ + SKP_Silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x ); +} + +void SKP_Silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const SKP_float *L, /* (I) Pointer to Lower Triangular Matrix */ + SKP_int M, /* (I) Dim of Matrix equation */ + const SKP_float *b, /* (I) b Vector */ + SKP_float *x /* (O) x Vector */ +) +{ + SKP_int i, j; + SKP_float temp; + const SKP_float *ptr1; + + for( i = M - 1; i >= 0; i-- ) { + ptr1 = matrix_adr( L, 0, i, M ); + temp = 0; + for( j = M - 1; j > i ; j-- ) { + temp += ptr1[ j * M ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +void SKP_Silk_SolveWithLowerTriangularWdiagOnes_FLP( + const SKP_float *L, /* (I) Pointer to Lower Triangular Matrix */ + SKP_int M, /* (I) Dim of Matrix equation */ + const SKP_float *b, /* (I) b Vector */ + SKP_float *x /* (O) x Vector */ +) +{ + SKP_int i, j; + SKP_float temp; + const SKP_float *ptr1; + + for( i = 0; i < M; i++ ) { + ptr1 = matrix_adr( L, i, 0, M ); + temp = 0; + for( j = 0; j < i; j++ ) { + temp += ptr1[ j ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +void SKP_Silk_LDL_FLP( + SKP_float *A, /* (I/O) Pointer to Symetric Square Matrix */ + SKP_int M, /* (I) Size of Matrix */ + SKP_float *L, /* (I/O) Pointer to Square Upper triangular Matrix */ + SKP_float *Dinv /* (I/O) Pointer to vector holding the inverse diagonal elements of D */ +) +{ + SKP_int i, j, k, loop_count, err = 1; + SKP_float *ptr1, *ptr2; + double temp, diag_min_value; + SKP_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; // temp arrays + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] ); + for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) { + err = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L, j, 0, M ); + temp = matrix_ptr( A, j, j, M ); // element in row j column j + for( i = 0; i < j; i++ ) { + v[ i ] = ptr1[ i ] * D[ i ]; + temp -= ptr1[ i ] * v[ i ]; + } + if( temp < diag_min_value ) { + /* Badly conditioned matrix: add white noise and run again */ + temp = ( loop_count + 1 ) * diag_min_value - temp; + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) += ( SKP_float )temp; + } + err = 1; + break; + } + D[ j ] = ( SKP_float )temp; + Dinv[ j ] = ( SKP_float )( 1.0f / temp ); + matrix_ptr( L, j, j, M ) = 1.0f; + + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L, j + 1, 0, M); + for( i = j + 1; i < M; i++ ) { + temp = 0.0; + for( k = 0; k < j; k++ ) { + temp += ptr2[ k ] * v[ k ]; + } + matrix_ptr( L, i, j, M ) = ( SKP_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] ); + ptr2 += M; // go to next column + } + } + } + SKP_assert( err == 0 ); +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort.c new file mode 100755 index 0000000..934373f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort.c @@ -0,0 +1,147 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "SKP_Silk_SigProc_FIX.h" + +void SKP_Silk_insertion_sort_increasing( + SKP_int32 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted output positions */ +) +{ + SKP_int32 value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + +void SKP_Silk_insertion_sort_decreasing_int16( + SKP_int16 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted output positions */ +) +{ + SKP_int i, j; + SKP_int value; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + +void SKP_Silk_insertion_sort_increasing_all_values( + SKP_int *a, /* I/O: Unsorted / Sorted vector */ + const SKP_int L /* I: Vector length */ +) +{ + SKP_int value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort_FLP.c new file mode 100755 index 0000000..9bcc877 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sort_FLP.c @@ -0,0 +1,128 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* To be implemented: */ + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_SigProc_FLP.h" + +void SKP_Silk_insertion_sort_increasing_FLP( + SKP_float *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +) +{ + SKP_float value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + +void SKP_Silk_insertion_sort_decreasing_FLP( + SKP_float *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +) +{ + SKP_float value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs.h new file mode 100755 index 0000000..10c4117 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs.h @@ -0,0 +1,353 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_STRUCTS_H +#define SKP_SILK_STRUCTS_H + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + SKP_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + SKP_int32 sLTP_shp_Q10[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + NSQ_LPC_BUF_LENGTH ]; + SKP_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 sLF_AR_shp_Q12; + SKP_int lagPrev; + SKP_int sLTP_buf_idx; + SKP_int sLTP_shp_buf_idx; + SKP_int32 rand_seed; + SKP_int32 prev_inv_gain_Q16; + SKP_int rewhite_flag; +} SKP_Silk_nsq_state; /* FIX*/ + +/* Struct for Low BitRate Redundant (LBRR) information */ +typedef struct { + SKP_uint8 payload[ MAX_ARITHM_BYTES ]; + SKP_int nBytes; /* Number of bytes in payload */ + SKP_int usage; /* Tells how the payload should be used as FEC */ +} SKP_SILK_LBRR_struct; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + SKP_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + SKP_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + SKP_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + SKP_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + SKP_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + SKP_int16 HPstate; /* State of differentiator in the lowest band */ + SKP_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + SKP_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + SKP_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + SKP_int32 counter; /* Frame counter used in the initial phase */ +} SKP_Silk_VAD_state; + +/*******************************/ +/* Range encoder/decoder state */ +/*******************************/ +typedef struct { + SKP_int32 bufferLength; + SKP_int32 bufferIx; + SKP_uint32 base_Q32; + SKP_uint32 range_Q16; + SKP_int32 error; + SKP_uint8 buffer[ MAX_ARITHM_BYTES ]; /* Buffer containing payload */ +} SKP_Silk_range_coder_state; + +/* Input frequency range detection struct */ +typedef struct { + SKP_int32 S_HP_8_kHz[ NB_SOS ][ 2 ]; /* HP filter State */ + SKP_int32 ConsecSmplsAboveThres; + SKP_int32 ActiveSpeech_ms; /* Accumulated time with active speech */ + SKP_int SWB_detected; /* Flag to indicate SWB input */ + SKP_int WB_detected; /* Flag to indicate WB input */ +} SKP_Silk_detect_SWB_state; + +#if SWITCH_TRANSITION_FILTERING +/* Variable cut-off low-pass filter state */ +typedef struct { + SKP_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + SKP_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + SKP_int mode; /* Operating mode, 0: switch down, 1: switch up */ +} SKP_Silk_LP_state; +#endif + +/* Structure for one stage of MSVQ */ +typedef struct { + const SKP_int32 nVectors; + const SKP_int16 *CB_NLSF_Q15; + const SKP_int16 *Rates_Q5; +} SKP_Silk_NLSF_CBS; + +/* Structure containing NLSF MSVQ codebook */ +typedef struct { + const SKP_int32 nStages; + + /* Fields for (de)quantizing */ + const SKP_Silk_NLSF_CBS *CBStages; + const SKP_int *NDeltaMin_Q15; + + /* Fields for arithmetic (de)coding */ + const SKP_uint16 *CDF; + const SKP_uint16 * const *StartPtr; + const SKP_int *MiddleIx; +} SKP_Silk_NLSF_CB_struct; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + SKP_Silk_range_coder_state sRC; /* Range coder state */ + SKP_Silk_range_coder_state sRC_LBRR; /* Range coder state (for low bitrate redundancy) */ + SKP_Silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + SKP_Silk_nsq_state sNSQ_LBRR; /* Noise Shape Quantizer State ( for low bitrate redundancy ) */ + +#if HIGH_PASS_INPUT + SKP_int32 In_HP_State[ 2 ]; /* High pass filter state */ +#endif +#if SWITCH_TRANSITION_FILTERING + SKP_Silk_LP_state sLP; /* Low pass filter state */ +#endif + SKP_Silk_VAD_state sVAD; /* Voice activity detector state */ + + SKP_int LBRRprevLastGainIndex; + SKP_int prev_sigtype; + SKP_int typeOffsetPrev; /* Previous signal type and quantization offset */ + SKP_int prevLag; + SKP_int prev_lagIndex; + SKP_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + SKP_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + SKP_int maxInternal_fs_kHz; /* Maximum internal sampling frequency (kHz) */ + SKP_int fs_kHz; /* Internal sampling frequency (kHz) */ + SKP_int fs_kHz_changed; /* Did we switch yet? */ + SKP_int frame_length; /* Frame length (samples) */ + SKP_int subfr_length; /* Subframe length (samples) */ + SKP_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + SKP_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + SKP_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + SKP_int32 TargetRate_bps; /* Target bitrate (bps) */ + SKP_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + SKP_int PacketLoss_perc; /* Packet loss rate measured by farend */ + SKP_int32 frameCounter; + SKP_int Complexity; /* Complexity setting: 0-> low; 1-> medium; 2->high */ + SKP_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + SKP_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + SKP_int shapingLPCOrder; /* Filter order for noise shaping filters */ + SKP_int predictLPCOrder; /* Filter order for prediction filters */ + SKP_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + SKP_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + SKP_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + SKP_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */ + SKP_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + SKP_int first_frame_after_reset; /* Flag for deactivating NLSF interp. and fluc. reduction after resets */ + SKP_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + SKP_int warping_Q16; /* Warping parameter for warped noise shaping */ + + /* Input/output buffering */ + SKP_int16 inputBuf[ MAX_FRAME_LENGTH ]; /* buffer containin input signal */ + SKP_int inputBufIx; + SKP_int nFramesInPayloadBuf; /* number of frames sitting in outputBuf */ + SKP_int nBytesInPayloadBuf; /* number of bytes sitting in outputBuf */ + + /* Parameters For LTP scaling Control */ + SKP_int frames_since_onset; + + const SKP_Silk_NLSF_CB_struct *psNLSF_CB[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */ + + /* Struct for Inband LBRR */ + SKP_SILK_LBRR_struct LBRR_buffer[ MAX_LBRR_DELAY ]; + SKP_int oldest_LBRR_idx; + SKP_int useInBandFEC; /* Saves the API setting for query */ + SKP_int LBRR_enabled; + SKP_int LBRR_GainIncreases; /* Number of shifts to Gains to get LBRR rate Voiced frames */ + + /* Bitrate control */ + SKP_int32 bitrateDiff; /* Accumulated diff. between the target bitrate and the switch bitrates */ + SKP_int32 bitrate_threshold_up; /* Threshold for switching to a higher internal sample frequency */ + SKP_int32 bitrate_threshold_down; /* Threshold for switching to a lower internal sample frequency */ + + SKP_Silk_resampler_state_struct resampler_state; + + /* DTX */ + SKP_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + SKP_int useDTX; /* Flag to enable DTX */ + SKP_int inDTX; /* Flag to signal DTX period */ + SKP_int vadFlag; /* Flag to indicate Voice Activity */ + + /* Struct for detecting SWB input */ + SKP_Silk_detect_SWB_state sSWBdetect; + + + /* Buffers */ + SKP_int8 q[ MAX_FRAME_LENGTH ]; /* pulse signal buffer */ + SKP_int8 q_LBRR[ MAX_FRAME_LENGTH ]; /* pulse signal buffer */ + +} SKP_Silk_encoder_state; + + +/************************/ +/* Encoder control */ +/************************/ +typedef struct { + /* Quantization indices */ + SKP_int lagIndex; + SKP_int contourIndex; + SKP_int PERIndex; + SKP_int LTPIndex[ NB_SUBFR ]; + SKP_int NLSFIndices[ NLSF_MSVQ_MAX_CB_STAGES ]; /* NLSF path of quantized LSF vector */ + SKP_int NLSFInterpCoef_Q2; + SKP_int GainsIndices[ NB_SUBFR ]; + SKP_int32 Seed; + SKP_int LTP_scaleIndex; + SKP_int RateLevelIndex; + SKP_int QuantOffsetType; + SKP_int sigtype; + + /* Prediction and coding parameters */ + SKP_int pitchL[ NB_SUBFR ]; + + SKP_int LBRR_usage; /* Low bitrate redundancy usage */ +} SKP_Silk_encoder_control; + +/* Struct for Packet Loss Concealment */ +typedef struct { + SKP_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + SKP_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + SKP_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + SKP_int last_frame_lost; /* Was previous frame lost */ + SKP_int32 rand_seed; /* Seed for unvoiced signal generation */ + SKP_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + SKP_int32 conc_energy; + SKP_int conc_energy_shift; + SKP_int16 prevLTP_scale_Q14; + SKP_int32 prevGain_Q16[ NB_SUBFR ]; + SKP_int fs_kHz; +} SKP_Silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + SKP_int32 CNG_exc_buf_Q10[ MAX_FRAME_LENGTH ]; + SKP_int CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + SKP_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + SKP_int32 CNG_smth_Gain_Q16; + SKP_int32 rand_seed; + SKP_int fs_kHz; +} SKP_Silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + SKP_Silk_range_coder_state sRC; /* Range coder state */ + SKP_int32 prev_inv_gain_Q16; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + MAX_LPC_ORDER ]; + SKP_int32 exc_Q10[ MAX_FRAME_LENGTH ]; + SKP_int32 res_Q10[ MAX_FRAME_LENGTH ]; + SKP_int16 outBuf[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for output signal */ + SKP_int lagPrev; /* Previous Lag */ + SKP_int LastGainIndex; /* Previous gain index */ + SKP_int LastGainIndex_EnhLayer; /* Previous gain index */ + SKP_int typeOffsetPrev; /* Previous signal type and quantization offset */ + SKP_int32 HPState[ DEC_HP_ORDER ]; /* HP filter state */ + const SKP_int16 *HP_A; /* HP filter AR coefficients */ + const SKP_int16 *HP_B; /* HP filter MA coefficients */ + SKP_int fs_kHz; /* Sampling frequency in kHz */ + SKP_int32 prev_API_sampleRate; /* Previous API sample frequency (Hz) */ + SKP_int frame_length; /* Frame length (samples) */ + SKP_int subfr_length; /* Subframe length (samples) */ + SKP_int LPC_order; /* LPC order */ + SKP_int prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + SKP_int first_frame_after_reset; /* Flag for deactivating NLSF interp. and fluc. reduction after resets */ + + /* For buffering payload in case of more frames per packet */ + SKP_int nBytesLeft; + SKP_int nFramesDecoded; + SKP_int nFramesInPacket; + SKP_int moreInternalDecoderFrames; + SKP_int FrameTermination; + + SKP_Silk_resampler_state_struct resampler_state; + + const SKP_Silk_NLSF_CB_struct *psNLSF_CB[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */ + + /* Parameters used to investigate if inband FEC is used */ + SKP_int vadFlag; + SKP_int no_FEC_counter; /* Counts number of frames wo inband FEC */ + SKP_int inband_FEC_offset; /* 0: no FEC, 1: FEC with 1 packet offset, 2: FEC w 2 packets offset */ + + /* CNG state */ + SKP_Silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + SKP_int lossCnt; + SKP_int prev_sigtype; /* Previous sigtype */ + + SKP_Silk_PLC_struct sPLC; + + + +} SKP_Silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* prediction and coding parameters */ + SKP_int pitchL[ NB_SUBFR ]; + SKP_int32 Gains_Q16[ NB_SUBFR ]; + SKP_int32 Seed; + /* holds interpolated and final coefficients, 4-byte aligned */ + SKP_DWORD_ALIGN SKP_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ]; + SKP_int LTP_scale_Q14; + + /* quantization indices */ + SKP_int PERIndex; + SKP_int RateLevelIndex; + SKP_int QuantOffsetType; + SKP_int sigtype; + SKP_int NLSFInterpCoef_Q2; +} SKP_Silk_decoder_control; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs_FLP.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs_FLP.h new file mode 100755 index 0000000..7189c8d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_structs_FLP.h @@ -0,0 +1,168 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_STRUCTS_FLP_H +#define SKP_SILK_STRUCTS_FLP_H + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_main.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + SKP_int LastGainIndex; + SKP_float HarmBoost_smth; + SKP_float HarmShapeGain_smth; + SKP_float Tilt_smth; +} SKP_Silk_shape_state_FLP; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + SKP_float sLTP_shp[ LTP_BUF_LENGTH ]; + SKP_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + SKP_int sLTP_shp_buf_idx; + SKP_float sLF_AR_shp; + SKP_float sLF_MA_shp; + SKP_float sHarmHP; + SKP_int32 rand_seed; + SKP_int lagPrev; +} SKP_Silk_prefilter_state_FLP; + +/*****************************/ +/* Prediction analysis state */ +/*****************************/ +typedef struct { + SKP_int pitch_LPC_win_length; + SKP_int min_pitch_lag; /* Lowest possible pitch lag (samples) */ + SKP_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + SKP_float prev_NLSFq[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ +} SKP_Silk_predict_state_FLP; + +/*******************************************/ +/* Structure containing NLSF MSVQ codebook */ +/*******************************************/ +/* structure for one stage of MSVQ */ +typedef struct { + const SKP_int32 nVectors; + const SKP_float *CB; + const SKP_float *Rates; +} SKP_Silk_NLSF_CBS_FLP; + +typedef struct { + const SKP_int32 nStages; + + /* fields for (de)quantizing */ + const SKP_Silk_NLSF_CBS_FLP *CBStages; + const SKP_float *NDeltaMin; + + /* fields for arithmetic (de)coding */ + const SKP_uint16 *CDF; + const SKP_uint16 * const *StartPtr; + const SKP_int *MiddleIx; +} SKP_Silk_NLSF_CB_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + SKP_Silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + + SKP_float variable_HP_smth1; /* State of first smoother */ + SKP_float variable_HP_smth2; /* State of second smoother */ + + SKP_Silk_shape_state_FLP sShape; /* Noise shaping state */ + SKP_Silk_prefilter_state_FLP sPrefilt; /* Prefilter State */ + SKP_Silk_predict_state_FLP sPred; /* Prediction State */ + + /* Buffer for find pitch and noise shape analysis */ + SKP_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + SKP_float LTPCorr; /* Normalized correlation from pitch lag estimator */ + SKP_float mu_LTP; /* Rate-distortion tradeoff in LTP quantization */ + SKP_float SNR_dB; /* Quality setting */ + SKP_float avgGain; /* average gain during active speech */ + SKP_float BufferedInChannel_ms; /* Simulated number of ms buffer in channel because of exceeded TargetRate_bps */ + SKP_float speech_activity; /* Speech activity */ + + /* Parameters for LTP scaling control */ + SKP_float prevLTPredCodGain; + SKP_float HPLTPredCodGain; + + SKP_float inBandFEC_SNR_comp; /* Compensation to SNR_DB when using inband FEC Voiced */ + + const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */ +} SKP_Silk_encoder_state_FLP; + + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + SKP_Silk_encoder_control sCmn; /* Common struct, shared with fixed-point code */ + + /* Prediction and coding parameters */ + SKP_float Gains[NB_SUBFR]; + SKP_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + SKP_float LTPCoef[LTP_ORDER * NB_SUBFR]; + SKP_float LTP_scale; + + /* Noise shaping parameters */ + SKP_float AR1[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_float AR2[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_float LF_MA_shp[ NB_SUBFR ]; + SKP_float LF_AR_shp[ NB_SUBFR ]; + SKP_float GainsPre[ NB_SUBFR ]; + SKP_float HarmBoost[ NB_SUBFR ]; + SKP_float Tilt[ NB_SUBFR ]; + SKP_float HarmShapeGain[ NB_SUBFR ]; + SKP_float Lambda; + SKP_float input_quality; + SKP_float coding_quality; + SKP_float pitch_freq_low_Hz; + SKP_float current_SNR_dB; + + /* Measures */ + SKP_float sparseness; + SKP_float predGain; + SKP_float LTPredCodGain; + SKP_float input_quality_bands[ VAD_N_BANDS ]; + SKP_float input_tilt; + SKP_float ResNrg[ NB_SUBFR ]; /* Residual energy per subframe */ +} SKP_Silk_encoder_control_FLP; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sum_sqr_shift.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sum_sqr_shift.c new file mode 100755 index 0000000..271c300 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_sum_sqr_shift.c @@ -0,0 +1,100 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_sum_sqr_shift.c * + * * + * compute number of bits to right shift the sum of squares of a vector * + * of int16s to make it fit in an int32 * + * * + * Copyright 2006-2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void SKP_Silk_sum_sqr_shift( + SKP_int32 *energy, /* O Energy of x, after shifting to the right */ + SKP_int *shift, /* O Number of bits right shift applied to energy */ + const SKP_int16 *x, /* I Input vector */ + SKP_int len /* I Length of input vector */ +) +{ + SKP_int i, shft; + SKP_int32 in32, nrg_tmp, nrg; + + if( (SKP_int32)( (SKP_int_ptr_size)x & 2 ) != 0 ) { + /* Input is not 4-byte aligned */ + nrg = SKP_SMULBB( x[ 0 ], x[ 0 ] ); + i = 1; + } else { + nrg = 0; + i = 0; + } + shft = 0; + len--; + while( i < len ) { + /* Load two values at once */ + in32 = *( (SKP_int32 *)&x[ i ] ); + nrg = SKP_SMLABB_ovflw( nrg, in32, in32 ); + nrg = SKP_SMLATT_ovflw( nrg, in32, in32 ); + i += 2; + if( nrg < 0 ) { + /* Scale down */ + nrg = (SKP_int32)SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft = 2; + break; + } + } + for( ; i < len; i += 2 ) { + /* Load two values at once */ + in32 = *( (SKP_int32 *)&x[ i ] ); + nrg_tmp = SKP_SMULBB( in32, in32 ); + nrg_tmp = SKP_SMLATT_ovflw( nrg_tmp, in32, in32 ); + nrg = (SKP_int32)SKP_ADD_RSHIFT_uint( nrg, (SKP_uint32)nrg_tmp, shft ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (SKP_int32)SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft += 2; + } + } + if( i == len ) { + /* One sample left to process */ + nrg_tmp = SKP_SMULBB( x[ i ], x[ i ] ); + nrg = (SKP_int32)SKP_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + /* Make sure to have at least one extra leading zero (two leading zeros in total) */ + if( nrg & 0xC0000000 ) { + nrg = SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft += 2; + } + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables.h new file mode 100755 index 0000000..fb6d27c --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables.h @@ -0,0 +1,168 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_H +#define SKP_SILK_TABLES_H + +#include "SKP_Silk_define.h" +#include "SKP_Silk_structs.h" + +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* entropy coding tables */ +extern const SKP_uint16 SKP_Silk_type_offset_CDF[ 5 ]; /* 5 */ +extern const SKP_uint16 SKP_Silk_type_offset_joint_CDF[ 4 ][ 5 ]; /* 20 */ +extern const SKP_int SKP_Silk_type_offset_CDF_offset; + +extern const SKP_uint16 SKP_Silk_gain_CDF[ 2 ][ N_LEVELS_QGAIN + 1 ]; /* 130 */ +extern const SKP_int SKP_Silk_gain_CDF_offset; +extern const SKP_uint16 SKP_Silk_delta_gain_CDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 2 ]; /* 46 */ +extern const SKP_int SKP_Silk_delta_gain_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pitch_lag_NB_CDF[ 8 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 130 */ +extern const SKP_int SKP_Silk_pitch_lag_NB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_MB_CDF[ 12 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 194 */ +extern const SKP_int SKP_Silk_pitch_lag_MB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_WB_CDF[ 16 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 258 */ +extern const SKP_int SKP_Silk_pitch_lag_WB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_SWB_CDF[ 24 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 386 */ +extern const SKP_int SKP_Silk_pitch_lag_SWB_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pitch_contour_CDF[ 35 ]; /* 35 */ +extern const SKP_int SKP_Silk_pitch_contour_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_contour_NB_CDF[ 12 ]; /* 12 */ +extern const SKP_int SKP_Silk_pitch_contour_NB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_delta_CDF[23]; /* 23 */ +extern const SKP_int SKP_Silk_pitch_delta_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS ][ MAX_PULSES + 3 ]; /* 210 */ +extern const SKP_int SKP_Silk_pulses_per_block_CDF_offset; +extern const SKP_int16 SKP_Silk_pulses_per_block_BITS_Q6[ N_RATE_LEVELS - 1 ][ MAX_PULSES + 2 ]; /* 180 */ + +extern const SKP_uint16 SKP_Silk_rate_levels_CDF[ 2 ][ N_RATE_LEVELS ]; /* 20 */ +extern const SKP_int SKP_Silk_rate_levels_CDF_offset; +extern const SKP_int16 SKP_Silk_rate_levels_BITS_Q6[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const SKP_int SKP_Silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const SKP_uint16 SKP_Silk_shell_code_table0[ 33 ]; /* 33 */ +extern const SKP_uint16 SKP_Silk_shell_code_table1[ 52 ]; /* 52 */ +extern const SKP_uint16 SKP_Silk_shell_code_table2[ 102 ]; /* 102 */ +extern const SKP_uint16 SKP_Silk_shell_code_table3[ 207 ]; /* 207 */ +extern const SKP_uint16 SKP_Silk_shell_code_table_offsets[ 19 ]; /* 19 */ + +extern const SKP_uint16 SKP_Silk_lsb_CDF[ 3 ]; /* 3 */ + +extern const SKP_uint16 SKP_Silk_sign_CDF[ 36 ]; /* 36 */ + +extern const SKP_uint16 SKP_Silk_LTP_per_index_CDF[ 4 ]; /* 4 */ +extern const SKP_int SKP_Silk_LTP_per_index_CDF_offset; +extern const SKP_int16 * const SKP_Silk_LTP_gain_BITS_Q6_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_uint16 * const SKP_Silk_LTP_gain_CDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_int SKP_Silk_LTP_gain_CDF_offsets[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_int32 SKP_Silk_LTP_gain_middle_avg_RD_Q14; +extern const SKP_uint16 SKP_Silk_LTPscale_CDF[ 4 ]; /* 4 */ +extern const SKP_int SKP_Silk_LTPscale_offset; + +/* Tables for LTPScale */ +extern const SKP_int16 SKP_Silk_LTPScales_table_Q14[ 3 ]; + +extern const SKP_uint16 SKP_Silk_vadflag_CDF[ 3 ]; /* 3 */ +extern const SKP_int SKP_Silk_vadflag_offset; + +extern const SKP_int SKP_Silk_SamplingRates_table[ 4 ]; /* 4 */ +extern const SKP_uint16 SKP_Silk_SamplingRates_CDF[ 5 ]; /* 5 */ +extern const SKP_int SKP_Silk_SamplingRates_offset; + +extern const SKP_uint16 SKP_Silk_NLSF_interpolation_factor_CDF[ 6 ]; +extern const SKP_int SKP_Silk_NLSF_interpolation_factor_offset; + +/* NLSF codebooks */ +extern const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_16, SKP_Silk_NLSF_CB1_16; +extern const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_10, SKP_Silk_NLSF_CB1_10; + +/* quantization tables */ +extern const SKP_int16 * const SKP_Silk_LTP_vq_ptrs_Q14[ NB_LTP_CBKS ]; /* 168 */ +extern const SKP_int SKP_Silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +extern const SKP_int32 TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_SWB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; + +extern const SKP_int32 SNR_table_one_bit_per_sample_Q7[ 4 ]; + +/* Filter coeficicnts for HP filter: 4. Order filter implementad as two biquad filters */ +extern const SKP_int16 SKP_Silk_SWB_detect_B_HP_Q13[ NB_SOS ][ 3 ]; +extern const SKP_int16 SKP_Silk_SWB_detect_A_HP_Q13[ NB_SOS ][ 2 ]; + +/* Decoder high-pass filter coefficients for 24 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_24[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_24[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 16 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_16[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_16[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 12 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_12[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_12[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 8 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_8[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_8[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Table for frame termination indication */ +extern const SKP_uint16 SKP_Silk_FrameTermination_CDF[ 5 ]; +extern const SKP_int SKP_Silk_FrameTermination_offset; + +/* Table for random seed */ +extern const SKP_uint16 SKP_Silk_Seed_CDF[ 5 ]; +extern const SKP_int SKP_Silk_Seed_offset; + +/* Quantization offsets */ +extern const SKP_int16 SKP_Silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; + +#if SWITCH_TRANSITION_FILTERING +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const SKP_int32 SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; +extern const SKP_int32 SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_FLP.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_FLP.h new file mode 100755 index 0000000..554122b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_FLP.h @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_FLP_H +#define SKP_SILK_TABLES_FLP_H + +#include "SKP_Silk_structs_FLP.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* filters */ +extern const SKP_float SKP_Silk_HarmShapeFIR_FLP[ HARM_SHAPE_FIR_TAPS ]; + +/* Table of quantization offset values */ +extern const SKP_float SKP_Silk_Quantization_Offsets[ 2 ][ 2 ]; + +/* NLSF codebooks */ +extern const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB0_16_FLP, SKP_Silk_NLSF_CB1_16_FLP; +extern const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB0_10_FLP, SKP_Silk_NLSF_CB1_10_FLP; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_LTP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_LTP.c new file mode 100755 index 0000000..075e7d4 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_LTP.c @@ -0,0 +1,324 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_LTP_per_index_CDF[ 4 ] = { + 0, 20992, 40788, 65535 +}; + +const SKP_int SKP_Silk_LTP_per_index_CDF_offset = 1; + + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_0[ 11 ] = { + 0, 49380, 54463, 56494, 58437, 60101, 61683, 62985, + 64066, 64823, 65535 +}; + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_1[ 21 ] = { + 0, 25290, 30654, 35710, 40386, 42937, 45250, 47459, + 49411, 51348, 52974, 54517, 55976, 57423, 58865, 60285, + 61667, 62895, 63827, 64724, 65535 +}; + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_2[ 41 ] = { + 0, 4958, 9439, 13581, 17638, 21651, 25015, 28025, + 30287, 32406, 34330, 36240, 38130, 39790, 41281, 42764, + 44229, 45676, 47081, 48431, 49675, 50849, 51932, 52966, + 53957, 54936, 55869, 56789, 57708, 58504, 59285, 60043, + 60796, 61542, 62218, 62871, 63483, 64076, 64583, 65062, + 65535 +}; + +const SKP_int SKP_Silk_LTP_gain_CDF_offsets[ 3 ] = { + 1, 3, 10 +}; + +const SKP_int32 SKP_Silk_LTP_gain_middle_avg_RD_Q14 = 11010; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_0[ 10 ] = { + 26, 236, 321, 325, 339, 344, 362, 379, + 412, 418 +}; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_1[ 20 ] = { + 88, 231, 237, 244, 300, 309, 313, 324, + 325, 341, 346, 351, 352, 352, 354, 356, + 367, 393, 396, 406 +}; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_2[ 40 ] = { + 238, 248, 255, 257, 258, 274, 284, 311, + 317, 326, 326, 327, 339, 349, 350, 351, + 352, 355, 358, 366, 371, 379, 383, 387, + 388, 393, 394, 394, 407, 409, 412, 412, + 413, 422, 426, 432, 434, 449, 454, 455 +}; + +const SKP_uint16 * const SKP_Silk_LTP_gain_CDF_ptrs[ NB_LTP_CBKS ] = { + SKP_Silk_LTP_gain_CDF_0, + SKP_Silk_LTP_gain_CDF_1, + SKP_Silk_LTP_gain_CDF_2 +}; + +const SKP_int16 * const SKP_Silk_LTP_gain_BITS_Q6_ptrs[ NB_LTP_CBKS ] = { + SKP_Silk_LTP_gain_BITS_Q6_0, + SKP_Silk_LTP_gain_BITS_Q6_1, + SKP_Silk_LTP_gain_BITS_Q6_2 +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_0_Q14[ 10 ][ 5 ] = +{ +{ + 594, 984, 2840, 1021, 669 +}, +{ + 10, 35, 304, -1, 23 +}, +{ + -694, 1923, 4603, 2975, 2335 +}, +{ + 2437, 3176, 3778, 1940, 481 +}, +{ + 214, -46, 7870, 4406, -521 +}, +{ + -896, 4818, 8501, 1623, -887 +}, +{ + -696, 3178, 6480, -302, 1081 +}, +{ + 517, 599, 1002, 567, 560 +}, +{ + -2075, -834, 4712, -340, 896 +}, +{ + 1435, -644, 3993, -612, -2063 +} +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_1_Q14[ 20 ][ 5 ] = +{ +{ + 1655, 2918, 5001, 3010, 1775 +}, +{ + 113, 198, 856, 176, 178 +}, +{ + -843, 2479, 7858, 5371, 574 +}, +{ + 59, 5356, 7648, 2850, -315 +}, +{ + 3840, 4851, 6527, 1583, -1233 +}, +{ + 1620, 1760, 2330, 1876, 2045 +}, +{ + -545, 1854, 11792, 1547, -307 +}, +{ + -604, 689, 5369, 5074, 4265 +}, +{ + 521, -1331, 9829, 6209, -1211 +}, +{ + -1315, 6747, 9929, -1410, 546 +}, +{ + 117, -144, 2810, 1649, 5240 +}, +{ + 5392, 3476, 2425, -38, 633 +}, +{ + 14, -449, 5274, 3547, -171 +}, +{ + -98, 395, 9114, 1676, 844 +}, +{ + -908, 3843, 8861, -957, 1474 +}, +{ + 396, 6747, 5379, -329, 1269 +}, +{ + -335, 2830, 4281, 270, -54 +}, +{ + 1502, 5609, 8958, 6045, 2059 +}, +{ + -370, 479, 5267, 5726, 1174 +}, +{ + 5237, -1144, 6510, 455, 512 +} +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_2_Q14[ 40 ][ 5 ] = +{ +{ + -278, 415, 9345, 7106, -431 +}, +{ + -1006, 3863, 9524, 4724, -871 +}, +{ + -954, 4624, 11722, 973, -300 +}, +{ + -117, 7066, 8331, 1959, -901 +}, +{ + 593, 3412, 6070, 4914, 1567 +}, +{ + 54, -51, 12618, 4228, -844 +}, +{ + 3157, 4822, 5229, 2313, 717 +}, +{ + -244, 1161, 14198, 779, 69 +}, +{ + -1218, 5603, 12894, -2301, 1001 +}, +{ + -132, 3960, 9526, 577, 1806 +}, +{ + -1633, 8815, 10484, -2452, 895 +}, +{ + 235, 450, 1243, 667, 437 +}, +{ + 959, -2630, 10897, 8772, -1852 +}, +{ + 2420, 2046, 8893, 4427, -1569 +}, +{ + 23, 7091, 8356, -1285, 1508 +}, +{ + -1133, 835, 7662, 6043, 2800 +}, +{ + 439, 391, 11016, 2253, 1362 +}, +{ + -1020, 2876, 13436, 4015, -3020 +}, +{ + 1060, -2690, 13512, 5565, -1394 +}, +{ + -1420, 8007, 11421, -152, -1672 +}, +{ + -893, 2895, 15434, -1490, 159 +}, +{ + -1054, 428, 12208, 8538, -3344 +}, +{ + 1772, -1304, 7593, 6185, 561 +}, +{ + 525, -1207, 6659, 11151, -1170 +}, +{ + 439, 2667, 4743, 2359, 5515 +}, +{ + 2951, 7432, 7909, -230, -1564 +}, +{ + -72, 2140, 5477, 1391, 1580 +}, +{ + 476, -1312, 15912, 2174, -1027 +}, +{ + 5737, 441, 2493, 2043, 2757 +}, +{ + 228, -43, 1803, 6663, 7064 +}, +{ + 4596, 9182, 1917, -200, 203 +}, +{ + -704, 12039, 5451, -1188, 542 +}, +{ + 1782, -1040, 10078, 7513, -2767 +}, +{ + -2626, 7747, 9019, 62, 1710 +}, +{ + 235, -233, 2954, 10921, 1947 +}, +{ + 10854, 2814, 1232, -111, 222 +}, +{ + 2267, 2778, 12325, 156, -1658 +}, +{ + -2950, 8095, 16330, 268, -3626 +}, +{ + 67, 2083, 7950, -80, -2432 +}, +{ + 518, -66, 1718, 415, 11435 +} +}; + +const SKP_int16 * const SKP_Silk_LTP_vq_ptrs_Q14[ NB_LTP_CBKS ] = { + &SKP_Silk_LTP_gain_vq_0_Q14[ 0 ][ 0 ], + &SKP_Silk_LTP_gain_vq_1_Q14[ 0 ][ 0 ], + &SKP_Silk_LTP_gain_vq_2_Q14[ 0 ][ 0 ] +}; + +const SKP_int SKP_Silk_LTP_vq_sizes[ NB_LTP_CBKS ] = { + 10, 20, 40 +}; diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.c new file mode 100755 index 0000000..49b27d2 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.c @@ -0,0 +1,890 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.29 + 2.66 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB0_10.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ NLSF_MSVQ_CB0_10_VECTORS + NLSF_MSVQ_CB0_10_STAGES ] = +{ + 0, + 2658, + 4420, + 6107, + 7757, + 9408, + 10955, + 12502, + 13983, + 15432, + 16882, + 18331, + 19750, + 21108, + 22409, + 23709, + 25010, + 26256, + 27501, + 28747, + 29965, + 31158, + 32351, + 33544, + 34736, + 35904, + 36997, + 38091, + 39185, + 40232, + 41280, + 42327, + 43308, + 44290, + 45271, + 46232, + 47192, + 48132, + 49032, + 49913, + 50775, + 51618, + 52462, + 53287, + 54095, + 54885, + 55675, + 56449, + 57222, + 57979, + 58688, + 59382, + 60076, + 60726, + 61363, + 61946, + 62505, + 63052, + 63543, + 63983, + 64396, + 64766, + 65023, + 65279, + 65535, + 0, + 4977, + 9542, + 14106, + 18671, + 23041, + 27319, + 31596, + 35873, + 39969, + 43891, + 47813, + 51652, + 55490, + 59009, + 62307, + 65535, + 0, + 8571, + 17142, + 25529, + 33917, + 42124, + 49984, + 57844, + 65535, + 0, + 8732, + 17463, + 25825, + 34007, + 42189, + 50196, + 58032, + 65535, + 0, + 8948, + 17704, + 25733, + 33762, + 41791, + 49821, + 57678, + 65535, + 0, + 4374, + 8655, + 12936, + 17125, + 21313, + 25413, + 29512, + 33611, + 37710, + 41809, + 45820, + 49832, + 53843, + 57768, + 61694, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 65 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 82 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 91 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 100 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 109 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + 23, + 8, + 5, + 5, + 5, + 9 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 148, 167, + 169, 170, + 170, 173, + 173, 175, + 176, 176, + 176, 177, + 179, 181, + 181, 181, + 183, 183, + 183, 184, + 185, 185, + 185, 185, + 186, 189, + 189, 189, + 191, 191, + 191, 194, + 194, 194, + 195, 195, + 196, 198, + 199, 200, + 201, 201, + 202, 203, + 204, 204, + 205, 205, + 206, 209, + 210, 210, + 213, 214, + 218, 220, + 221, 226, + 231, 234, + 239, 256, + 256, 256, + 119, 123, + 123, 123, + 125, 126, + 126, 126, + 128, 130, + 130, 131, + 131, 135, + 138, 139, + 94, 94, + 95, 95, + 96, 98, + 98, 99, + 93, 93, + 95, 96, + 96, 97, + 98, 100, + 92, 93, + 97, 97, + 97, 97, + 98, 98, + 125, 126, + 126, 127, + 127, 128, + 128, 128, + 128, 128, + 129, 129, + 129, 130, + 130, 131 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min_Q15[ 10 + 1 ] = +{ + 563, + 3, + 22, + 20, + 3, + 3, + 132, + 119, + 358, + 86, + 964 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 2210, 4023, + 6981, 9260, + 12573, 15687, + 19207, 22383, + 25981, 29142, + 3285, 4172, + 6116, 10856, + 15289, 16826, + 19701, 22010, + 24721, 29313, + 1554, 2511, + 6577, 10337, + 13837, 16511, + 20086, 23214, + 26480, 29464, + 3062, 4017, + 5771, 10037, + 13365, 14952, + 20140, 22891, + 25229, 29603, + 2085, 3457, + 5934, 8718, + 11501, 13670, + 17997, 21817, + 24935, 28745, + 2776, 4093, + 6421, 10413, + 15111, 16806, + 20825, 23826, + 26308, 29411, + 2717, 4034, + 5697, 8463, + 14301, 16354, + 19007, 23413, + 25812, 28506, + 2872, 3702, + 5881, 11034, + 17141, 18879, + 21146, 23451, + 25817, 29600, + 2999, 4015, + 7357, 11219, + 12866, 17307, + 20081, 22644, + 26774, 29107, + 2942, 3866, + 5918, 11915, + 13909, 16072, + 20453, 22279, + 27310, 29826, + 2271, 3527, + 6606, 9729, + 12943, 17382, + 20224, 22345, + 24602, 28290, + 2207, 3310, + 5844, 9339, + 11141, 15651, + 18576, 21177, + 25551, 28228, + 3963, 4975, + 6901, 11588, + 13466, 15577, + 19231, 21368, + 25510, 27759, + 2749, 3549, + 6966, 13808, + 15653, 17645, + 20090, 22599, + 26467, 28537, + 2126, 3504, + 5109, 9954, + 12550, 14620, + 19703, 21687, + 26457, 29106, + 3966, 5745, + 7442, 9757, + 14468, 16404, + 19135, 23048, + 25375, 28391, + 3197, 4751, + 6451, 9298, + 13038, 14874, + 17962, 20627, + 23835, 28464, + 3195, 4081, + 6499, 12252, + 14289, 16040, + 18357, 20730, + 26980, 29309, + 1533, 2471, + 4486, 7796, + 12332, 15758, + 19567, 22298, + 25673, 29051, + 2002, 2971, + 4985, 8083, + 13181, 15435, + 18237, 21517, + 24595, 28351, + 3808, 4925, + 6710, 10201, + 12011, 14300, + 18457, 20391, + 26525, 28956, + 2281, 3418, + 4979, 8726, + 15964, 18104, + 20250, 22771, + 25286, 28954, + 3051, 5479, + 7290, 9848, + 12744, 14503, + 18665, 23684, + 26065, 28947, + 2364, 3565, + 5502, 9621, + 14922, 16621, + 19005, 20996, + 26310, 29302, + 4093, 5212, + 6833, 9880, + 16303, 18286, + 20571, 23614, + 26067, 29128, + 2941, 3996, + 6038, 10638, + 12668, 14451, + 16798, 19392, + 26051, 28517, + 3863, 5212, + 7019, 9468, + 11039, 13214, + 19942, 22344, + 25126, 29539, + 4615, 6172, + 7853, 10252, + 12611, 14445, + 19719, 22441, + 24922, 29341, + 3566, 4512, + 6985, 8684, + 10544, 16097, + 18058, 22475, + 26066, 28167, + 4481, 5489, + 7432, 11414, + 13191, 15225, + 20161, 22258, + 26484, 29716, + 3320, 4320, + 6621, 9867, + 11581, 14034, + 21168, 23210, + 26588, 29903, + 3794, 4689, + 6916, 8655, + 10143, 16144, + 19568, 21588, + 27557, 29593, + 2446, 3276, + 5918, 12643, + 16601, 18013, + 21126, 23175, + 27300, 29634, + 2450, 3522, + 5437, 8560, + 15285, 19911, + 21826, 24097, + 26567, 29078, + 2580, 3796, + 5580, 8338, + 9969, 12675, + 18907, 22753, + 25450, 29292, + 3325, 4312, + 6241, 7709, + 9164, 14452, + 21665, 23797, + 27096, 29857, + 3338, 4163, + 7738, 11114, + 12668, 14753, + 16931, 22736, + 25671, 28093, + 3840, 4755, + 7755, 13471, + 15338, 17180, + 20077, 22353, + 27181, 29743, + 2504, 4079, + 8351, 12118, + 15046, 18595, + 21684, 24704, + 27519, 29937, + 5234, 6342, + 8267, 11821, + 15155, 16760, + 20667, 23488, + 25949, 29307, + 2681, 3562, + 6028, 10827, + 18458, 20458, + 22303, 24701, + 26912, 29956, + 3374, 4528, + 6230, 8256, + 9513, 12730, + 18666, 20720, + 26007, 28425, + 2731, 3629, + 8320, 12450, + 14112, 16431, + 18548, 22098, + 25329, 27718, + 3481, 4401, + 7321, 9319, + 11062, 13093, + 15121, 22315, + 26331, 28740, + 3577, 4945, + 6669, 8792, + 10299, 12645, + 19505, 24766, + 26996, 29634, + 4058, 5060, + 7288, 10190, + 11724, 13936, + 15849, 18539, + 26701, 29845, + 4262, 5390, + 7057, 8982, + 10187, 15264, + 20480, 22340, + 25958, 28072, + 3404, 4329, + 6629, 7946, + 10121, 17165, + 19640, 22244, + 25062, 27472, + 3157, 4168, + 6195, 9319, + 10771, 13325, + 15416, 19816, + 24672, 27634, + 2503, 3473, + 5130, 6767, + 8571, 14902, + 19033, 21926, + 26065, 28728, + 4133, 5102, + 7553, 10054, + 11757, 14924, + 17435, 20186, + 23987, 26272, + 4972, 6139, + 7894, 9633, + 11320, 14295, + 21737, 24306, + 26919, 29907, + 2958, 3816, + 6851, 9204, + 10895, 18052, + 20791, 23338, + 27556, 29609, + 5234, 6028, + 8034, 10154, + 11242, 14789, + 18948, 20966, + 26585, 29127, + 5241, 6838, + 10526, 12819, + 14681, 17328, + 19928, 22336, + 26193, 28697, + 3412, 4251, + 5988, 7094, + 9907, 18243, + 21669, 23777, + 26969, 29087, + 2470, 3217, + 7797, 15296, + 17365, 19135, + 21979, 24256, + 27322, 29442, + 4939, 5804, + 8145, 11809, + 13873, 15598, + 17234, 19423, + 26476, 29645, + 5051, 6167, + 8223, 9655, + 12159, 17995, + 20464, 22832, + 26616, 28462, + 4987, 5907, + 9319, 11245, + 13132, 15024, + 17485, 22687, + 26011, 28273, + 5137, 6884, + 11025, 14950, + 17191, 19425, + 21807, 24393, + 26938, 29288, + 7057, 7884, + 9528, 10483, + 10960, 14811, + 19070, 21675, + 25645, 28019, + 6759, 7160, + 8546, 11779, + 12295, 13023, + 16627, 21099, + 24697, 28287, + 3863, 9762, + 11068, 11445, + 12049, 13960, + 18085, 21507, + 25224, 28997, + 397, 335, + 651, 1168, + 640, 765, + 465, 331, + 214, -194, + -578, -647, + -657, 750, + 564, 613, + 549, 630, + 304, -52, + 828, 922, + 443, 111, + 138, 124, + 169, 14, + 144, 83, + 132, 58, + -413, -752, + 869, 336, + 385, 69, + 56, 830, + -227, -266, + -368, -440, + -1195, 163, + 126, -228, + 802, 156, + 188, 120, + 376, 59, + -358, -558, + -1326, -254, + -202, -789, + 296, 92, + -70, -129, + -718, -1135, + 292, -29, + -631, 487, + -157, -153, + -279, 2, + -419, -342, + -34, -514, + -799, -1571, + -687, -609, + -546, -130, + -215, -252, + -446, -574, + -1337, 207, + -72, 32, + 103, -642, + 942, 733, + 187, 29, + -211, -814, + 143, 225, + 20, 24, + -268, -377, + 1623, 1133, + 667, 164, + 307, 366, + 187, 34, + 62, -313, + -832, -1482, + -1181, 483, + -42, -39, + -450, -1406, + -587, -52, + -760, 334, + 98, -60, + -500, -488, + -1058, 299, + 131, -250, + -251, -703, + 1037, 568, + -413, -265, + 1687, 573, + 345, 323, + 98, 61, + -102, 31, + 135, 149, + 617, 365, + -39, 34, + -611, 1201, + 1421, 736, + -414, -393, + -492, -343, + -316, -532, + 528, 172, + 90, 322, + -294, -319, + -541, 503, + 639, 401, + 1, -149, + -73, -167, + 150, 118, + 308, 218, + 121, 195, + -143, -261, + -1013, -802, + 387, 436, + 130, -427, + -448, -681, + 123, -87, + -251, -113, + 274, 310, + 445, 501, + 354, 272, + 141, -285, + 569, 656, + 37, -49, + 251, -386, + -263, 1122, + 604, 606, + 336, 95, + 34, 0, + 85, 180, + 207, -367, + -622, 1070, + -6, -79, + -160, -92, + -137, -276, + -323, -371, + -696, -1036, + 407, 102, + -86, -214, + -482, -647, + -28, -291, + -97, -180, + -250, -435, + -18, -76, + -332, 410, + 407, 168, + 539, 411, + 254, 111, + 58, -145, + 200, 30, + 187, 116, + 131, -367, + -475, 781, + -559, 561, + 195, -115, + 8, -168, + 30, 55, + -122, 131, + 82, -5, + -273, -50, + -632, 668, + 4, 32, + -26, -279, + 315, 165, + 197, 377, + 155, -41, + -138, -324, + -109, -617, + 360, 98, + -53, -319, + -114, -245, + -82, 507, + 468, 263, + -137, -389, + 652, 354, + -18, -227, + -462, -135, + 317, 53, + -16, 66, + -72, -126, + -356, -347, + -328, -72, + -337, 324, + 152, 349, + 169, -196, + 179, 254, + 260, 325, + -74, -80, + 75, -31, + 270, 275, + 87, 278, + -446, -301, + 309, 71, + -25, -242, + 516, 161, + -162, -83, + 329, 230, + -311, -259, + 177, -26, + -462, 89, + 257, 6, + -130, -93, + -456, -317, + -221, -206, + -417, -182, + -74, 234, + 48, 261, + 359, 231, + 258, 85, + -282, 252, + -147, -222, + 251, -207, + 443, 123, + -417, -36, + 273, -241, + 240, -112, + 44, -167, + 126, -124, + -77, 58, + -401, 333, + -118, 82, + 126, 151, + -433, 359, + -130, -102, + 131, -244, + 86, 85, + -462, 414, + -240, 16, + 145, 28, + -205, -481, + 373, 293, + -72, -174, + 62, 259, + -8, -18, + 362, 233, + 185, 43, + 278, 27, + 193, 570, + -248, 189, + 92, 31, + -275, -3, + 243, 176, + 438, 209, + 206, -51, + 79, 109, + 168, -185, + -308, -68, + -618, 385, + -310, -108, + -164, 165, + 61, -152, + -101, -412, + -268, -257, + -40, -20, + -28, -158, + -301, 271, + 380, -338, + -367, -132, + 64, 114, + -131, -225, + -156, -260, + -63, -116, + 155, -586, + -202, 254, + -287, 178, + 227, -106, + -294, 164, + 298, -100, + 185, 317, + 193, -45, + 28, 80, + -87, -433, + 22, -48, + 48, -237, + -229, -139, + 120, -364, + 268, -136, + 396, 125, + 130, -89, + -272, 118, + -256, -68, + -451, 488, + 143, -165, + -48, -190, + 106, 219, + 47, 435, + 245, 97, + 75, -418, + 121, -187, + 570, -200, + -351, 225, + -21, -217, + 234, -111, + 194, 14, + 242, 118, + 140, -397, + 355, 361, + -45, -195 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB0_10_Stage_info[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + { 64, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 80 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 88 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 96 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 96 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 104 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 104 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_10 = +{ + NLSF_MSVQ_CB0_10_STAGES, + SKP_Silk_NLSF_CB0_10_Stage_info, + SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.h new file mode 100755 index 0000000..1e0af27 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_NLSF_CB0_10_H +#define SKP_SILK_TABLES_NLSF_CB0_10_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB0_10_STAGES 6 +#define NLSF_MSVQ_CB0_10_VECTORS 120 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ NLSF_MSVQ_CB0_10_VECTORS + NLSF_MSVQ_CB0_10_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr[ NLSF_MSVQ_CB0_10_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx[ NLSF_MSVQ_CB0_10_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10_FLP.c new file mode 100755 index 0000000..045fdee --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_10_FLP.c @@ -0,0 +1,739 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 5.32 kB */ +/**********************************************/ + +#include "SKP_Silk_tables_FLP.h" +#include "SKP_Silk_tables_NLSF_CB0_10.h" + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_10_rates[ NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 4.62500000000000000000f, 5.21875000000000000000f, + 5.28125000000000000000f, 5.31250000000000000000f, + 5.31250000000000000000f, 5.40625000000000000000f, + 5.40625000000000000000f, 5.46875000000000000000f, + 5.50000000000000000000f, 5.50000000000000000000f, + 5.50000000000000000000f, 5.53125000000000000000f, + 5.59375000000000000000f, 5.65625000000000000000f, + 5.65625000000000000000f, 5.65625000000000000000f, + 5.71875000000000000000f, 5.71875000000000000000f, + 5.71875000000000000000f, 5.75000000000000000000f, + 5.78125000000000000000f, 5.78125000000000000000f, + 5.78125000000000000000f, 5.78125000000000000000f, + 5.81250000000000000000f, 5.90625000000000000000f, + 5.90625000000000000000f, 5.90625000000000000000f, + 5.96875000000000000000f, 5.96875000000000000000f, + 5.96875000000000000000f, 6.06250000000000000000f, + 6.06250000000000000000f, 6.06250000000000000000f, + 6.09375000000000000000f, 6.09375000000000000000f, + 6.12500000000000000000f, 6.18750000000000000000f, + 6.21875000000000000000f, 6.25000000000000000000f, + 6.28125000000000000000f, 6.28125000000000000000f, + 6.31250000000000000000f, 6.34375000000000000000f, + 6.37500000000000000000f, 6.37500000000000000000f, + 6.40625000000000000000f, 6.40625000000000000000f, + 6.43750000000000000000f, 6.53125000000000000000f, + 6.56250000000000000000f, 6.56250000000000000000f, + 6.65625000000000000000f, 6.68750000000000000000f, + 6.81250000000000000000f, 6.87500000000000000000f, + 6.90625000000000000000f, 7.06250000000000000000f, + 7.21875000000000000000f, 7.31250000000000000000f, + 7.46875000000000000000f, 8.00000000000000000000f, + 8.00000000000000000000f, 8.00000000000000000000f, + 3.71875000000000000000f, 3.84375000000000000000f, + 3.84375000000000000000f, 3.84375000000000000000f, + 3.90625000000000000000f, 3.93750000000000000000f, + 3.93750000000000000000f, 3.93750000000000000000f, + 4.00000000000000000000f, 4.06250000000000000000f, + 4.06250000000000000000f, 4.09375000000000000000f, + 4.09375000000000000000f, 4.21875000000000000000f, + 4.31250000000000000000f, 4.34375000000000000000f, + 2.93750000000000000000f, 2.93750000000000000000f, + 2.96875000000000000000f, 2.96875000000000000000f, + 3.00000000000000000000f, 3.06250000000000000000f, + 3.06250000000000000000f, 3.09375000000000000000f, + 2.90625000000000000000f, 2.90625000000000000000f, + 2.96875000000000000000f, 3.00000000000000000000f, + 3.00000000000000000000f, 3.03125000000000000000f, + 3.06250000000000000000f, 3.12500000000000000000f, + 2.87500000000000000000f, 2.90625000000000000000f, + 3.03125000000000000000f, 3.03125000000000000000f, + 3.03125000000000000000f, 3.03125000000000000000f, + 3.06250000000000000000f, 3.06250000000000000000f, + 3.90625000000000000000f, 3.93750000000000000000f, + 3.93750000000000000000f, 3.96875000000000000000f, + 3.96875000000000000000f, 4.00000000000000000000f, + 4.00000000000000000000f, 4.00000000000000000000f, + 4.00000000000000000000f, 4.00000000000000000000f, + 4.03125000000000000000f, 4.03125000000000000000f, + 4.03125000000000000000f, 4.06250000000000000000f, + 4.06250000000000000000f, 4.09375000000000000000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min[ 10 + 1 ] = +{ + 0.01718139648437500000f, + 0.00009155273437500000f, + 0.00067138671874999989f, + 0.00061035156250000000f, + 0.00009155273437500000f, + 0.00009155273437500000f, + 0.00402832031250000000f, + 0.00363159179687500000f, + 0.01092529296875000000f, + 0.00262451171875000000f, + 0.02941894531250000300f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 0.06744384765625000000f, 0.12277221679687500000f, + 0.21304321289062497000f, 0.28259277343750000000f, + 0.38369750976562500000f, 0.47872924804687500000f, + 0.58615112304687500000f, 0.68307495117187489000f, + 0.79287719726562500000f, 0.88934326171875011000f, + 0.10025024414062500000f, 0.12731933593750000000f, + 0.18664550781250003000f, 0.33129882812500000000f, + 0.46658325195312494000f, 0.51348876953125000000f, + 0.60122680664062500000f, 0.67169189453125000000f, + 0.75442504882812500000f, 0.89456176757812500000f, + 0.04742431640624999300f, 0.07662963867187500000f, + 0.20071411132812500000f, 0.31546020507812500000f, + 0.42227172851562494000f, 0.50387573242187500000f, + 0.61297607421875000000f, 0.70843505859375000000f, + 0.80810546875000000000f, 0.89916992187500000000f, + 0.09344482421875000000f, 0.12258911132812500000f, + 0.17611694335937500000f, 0.30630493164062500000f, + 0.40786743164062500000f, 0.45629882812500000000f, + 0.61462402343750000000f, 0.69857788085937500000f, + 0.76992797851562500000f, 0.90341186523437500000f, + 0.06362915039062500000f, 0.10549926757812500000f, + 0.18109130859375000000f, 0.26605224609375000000f, + 0.35098266601562494000f, 0.41717529296875000000f, + 0.54922485351562500000f, 0.66580200195312500000f, + 0.76095581054687489000f, 0.87722778320312500000f, + 0.08471679687500000000f, 0.12490844726562501000f, + 0.19595336914062500000f, 0.31777954101562500000f, + 0.46115112304687500000f, 0.51287841796875000000f, + 0.63552856445312500000f, 0.72711181640625000000f, + 0.80285644531250000000f, 0.89755249023437500000f, + 0.08291625976562498600f, 0.12310791015625000000f, + 0.17385864257812500000f, 0.25827026367187500000f, + 0.43643188476562500000f, 0.49908447265625000000f, + 0.58004760742187500000f, 0.71450805664062500000f, + 0.78771972656249989000f, 0.86993408203125011000f, + 0.08764648437500000000f, 0.11297607421875001000f, + 0.17947387695312500000f, 0.33673095703124994000f, + 0.52310180664062500000f, 0.57614135742187500000f, + 0.64532470703125000000f, 0.71566772460937500000f, + 0.78787231445312500000f, 0.90332031250000000000f, + 0.09152221679687500000f, 0.12252807617187500000f, + 0.22451782226562500000f, 0.34237670898437500000f, + 0.39263916015625000000f, 0.52816772460937500000f, + 0.61282348632812500000f, 0.69104003906250000000f, + 0.81707763671875000000f, 0.88827514648437500000f, + 0.08978271484375000000f, 0.11798095703125000000f, + 0.18060302734375003000f, 0.36361694335937500000f, + 0.42446899414062500000f, 0.49047851562500000000f, + 0.62417602539062500000f, 0.67990112304687500000f, + 0.83343505859375000000f, 0.91021728515625011000f, + 0.06930541992187500000f, 0.10763549804687500000f, + 0.20159912109375000000f, 0.29690551757812500000f, + 0.39498901367187506000f, 0.53045654296875000000f, + 0.61718750000000000000f, 0.68191528320312500000f, + 0.75079345703125000000f, 0.86334228515624989000f, + 0.06735229492187500000f, 0.10101318359375000000f, + 0.17834472656250000000f, 0.28500366210937500000f, + 0.33999633789062500000f, 0.47763061523437506000f, + 0.56689453125000000000f, 0.64627075195312511000f, + 0.77975463867187489000f, 0.86145019531250011000f, + 0.12094116210937500000f, 0.15182495117187500000f, + 0.21060180664062500000f, 0.35363769531250000000f, + 0.41094970703125000000f, 0.47537231445312494000f, + 0.58688354492187500000f, 0.65209960937500000000f, + 0.77850341796875000000f, 0.84713745117187500000f, + 0.08389282226562500000f, 0.10830688476562500000f, + 0.21258544921875000000f, 0.42138671875000000000f, + 0.47769165039062500000f, 0.53848266601562500000f, + 0.61309814453125000000f, 0.68966674804687511000f, + 0.80770874023437500000f, 0.87088012695312489000f, + 0.06488037109375000000f, 0.10693359375000001000f, + 0.15591430664062500000f, 0.30377197265625000000f, + 0.38299560546875006000f, 0.44616699218750000000f, + 0.60128784179687500000f, 0.66183471679687500000f, + 0.80740356445312500000f, 0.88824462890625000000f, + 0.12103271484375000000f, 0.17532348632812500000f, + 0.22711181640625000000f, 0.29776000976562500000f, + 0.44152832031250000000f, 0.50061035156250000000f, + 0.58395385742187500000f, 0.70336914062500000000f, + 0.77438354492187489000f, 0.86642456054687500000f, + 0.09756469726562500000f, 0.14498901367187500000f, + 0.19686889648437500000f, 0.28375244140625000000f, + 0.39788818359374994000f, 0.45391845703125000000f, + 0.54815673828125000000f, 0.62948608398437500000f, + 0.72738647460937500000f, 0.86865234375000000000f, + 0.09750366210937500000f, 0.12454223632812500000f, + 0.19833374023437500000f, 0.37390136718750000000f, + 0.43606567382812500000f, 0.48950195312500000000f, + 0.56021118164062500000f, 0.63262939453125000000f, + 0.82336425781250000000f, 0.89443969726562489000f, + 0.04678344726562500000f, 0.07540893554687500000f, + 0.13690185546875000000f, 0.23791503906250000000f, + 0.37634277343750000000f, 0.48089599609375000000f, + 0.59713745117187500000f, 0.68048095703124989000f, + 0.78347778320312489000f, 0.88656616210937511000f, + 0.06109619140625000000f, 0.09066772460937500000f, + 0.15213012695312500000f, 0.24667358398437497000f, + 0.40225219726562500000f, 0.47103881835937500000f, + 0.55654907226562500000f, 0.65664672851562500000f, + 0.75057983398437500000f, 0.86520385742187500000f, + 0.11621093750000000000f, 0.15029907226562500000f, + 0.20477294921875003000f, 0.31130981445312500000f, + 0.36654663085937500000f, 0.43640136718750000000f, + 0.56326293945312500000f, 0.62228393554687500000f, + 0.80947875976562500000f, 0.88366699218750000000f, + 0.06961059570312500000f, 0.10430908203125000000f, + 0.15194702148437500000f, 0.26629638671875000000f, + 0.48718261718750000000f, 0.55249023437500000000f, + 0.61798095703125000000f, 0.69491577148437500000f, + 0.77166748046875000000f, 0.88360595703125000000f, + 0.09310913085937500000f, 0.16720581054687500000f, + 0.22247314453125000000f, 0.30053710937500000000f, + 0.38891601562500000000f, 0.44259643554687500000f, + 0.56961059570312500000f, 0.72277832031250000000f, + 0.79544067382812511000f, 0.88339233398437500000f, + 0.07214355468750000000f, 0.10879516601562499000f, + 0.16790771484375000000f, 0.29360961914062500000f, + 0.45538330078125000000f, 0.50723266601562500000f, + 0.57998657226562500000f, 0.64074707031250000000f, + 0.80291748046875000000f, 0.89422607421875000000f, + 0.12490844726562501000f, 0.15905761718750000000f, + 0.20852661132812500000f, 0.30151367187500000000f, + 0.49752807617187500000f, 0.55804443359375000000f, + 0.62777709960937500000f, 0.72064208984375000000f, + 0.79550170898437500000f, 0.88891601562500000000f, + 0.08975219726562500000f, 0.12194824218750000000f, + 0.18426513671875000000f, 0.32464599609374994000f, + 0.38659667968750000000f, 0.44100952148437500000f, + 0.51263427734375000000f, 0.59179687500000000000f, + 0.79501342773437500000f, 0.87026977539062489000f, + 0.11788940429687500000f, 0.15905761718750000000f, + 0.21420288085937500000f, 0.28894042968750000000f, + 0.33688354492187500000f, 0.40325927734374994000f, + 0.60858154296875000000f, 0.68188476562500000000f, + 0.76678466796875000000f, 0.90145874023437489000f, + 0.14083862304687500000f, 0.18835449218749997000f, + 0.23965454101562500000f, 0.31286621093750000000f, + 0.38485717773437506000f, 0.44082641601562500000f, + 0.60177612304687500000f, 0.68484497070312500000f, + 0.76055908203125000000f, 0.89541625976562500000f, + 0.10882568359375000000f, 0.13769531250000000000f, + 0.21316528320312500000f, 0.26501464843750000000f, + 0.32177734375000000000f, 0.49124145507812500000f, + 0.55108642578125000000f, 0.68588256835937500000f, + 0.79547119140625000000f, 0.85958862304687500000f, + 0.13674926757812500000f, 0.16751098632812500000f, + 0.22680664062500000000f, 0.34832763671875000000f, + 0.40255737304687500000f, 0.46463012695312500000f, + 0.61526489257812500000f, 0.67926025390625000000f, + 0.80822753906250000000f, 0.90686035156250000000f, + 0.10131835937500000000f, 0.13183593750000000000f, + 0.20205688476562500000f, 0.30111694335937500000f, + 0.35342407226562500000f, 0.42828369140625000000f, + 0.64599609375000000000f, 0.70831298828125000000f, + 0.81140136718750000000f, 0.91256713867187500000f, + 0.11578369140625000000f, 0.14309692382812500000f, + 0.21105957031250000000f, 0.26412963867187500000f, + 0.30953979492187500000f, 0.49267578125000000000f, + 0.59716796875000000000f, 0.65881347656250000000f, + 0.84097290039062500000f, 0.90310668945312489000f, + 0.07464599609375000000f, 0.09997558593750000000f, + 0.18060302734375003000f, 0.38583374023437500000f, + 0.50662231445312500000f, 0.54971313476562500000f, + 0.64471435546875011000f, 0.70724487304687489000f, + 0.83312988281250000000f, 0.90435791015625000000f, + 0.07476806640625000000f, 0.10748291015625000000f, + 0.16592407226562500000f, 0.26123046875000000000f, + 0.46646118164062500000f, 0.60763549804687500000f, + 0.66607666015625000000f, 0.73538208007812500000f, + 0.81076049804687489000f, 0.88739013671875000000f, + 0.07873535156250000000f, 0.11584472656249999000f, + 0.17028808593750000000f, 0.25445556640625000000f, + 0.30422973632812500000f, 0.38681030273437500000f, + 0.57699584960937500000f, 0.69436645507812500000f, + 0.77667236328125000000f, 0.89392089843749989000f, + 0.10147094726562500000f, 0.13159179687500000000f, + 0.19046020507812500000f, 0.23526000976562500000f, + 0.27966308593750000000f, 0.44104003906250000000f, + 0.66116333007812489000f, 0.72622680664062511000f, + 0.82690429687500000000f, 0.91116333007812489000f, + 0.10186767578125000000f, 0.12704467773437500000f, + 0.23614501953125000000f, 0.33917236328125000000f, + 0.38659667968750000000f, 0.45022583007812500000f, + 0.51669311523437500000f, 0.69384765625000000000f, + 0.78341674804687500000f, 0.85733032226562500000f, + 0.11718749999999999000f, 0.14511108398437500000f, + 0.23666381835937500000f, 0.41110229492187506000f, + 0.46807861328125000000f, 0.52429199218750000000f, + 0.61270141601562500000f, 0.68215942382812500000f, + 0.82949829101562500000f, 0.90768432617187500000f, + 0.07641601562500000000f, 0.12448120117187500000f, + 0.25485229492187500000f, 0.36981201171875000000f, + 0.45916748046875000000f, 0.56747436523437500000f, + 0.66174316406250000000f, 0.75390625000000000000f, + 0.83981323242187500000f, 0.91360473632812500000f, + 0.15972900390625000000f, 0.19354248046875000000f, + 0.25228881835937500000f, 0.36074829101562500000f, + 0.46249389648437500000f, 0.51147460937500000000f, + 0.63070678710937500000f, 0.71679687500000000000f, + 0.79190063476562500000f, 0.89437866210937500000f, + 0.08181762695312500000f, 0.10870361328125000000f, + 0.18395996093750003000f, 0.33041381835937506000f, + 0.56329345703125000000f, 0.62432861328125000000f, + 0.68063354492187500000f, 0.75381469726562500000f, + 0.82128906250000000000f, 0.91418457031250000000f, + 0.10296630859375000000f, 0.13818359375000000000f, + 0.19012451171875000000f, 0.25195312500000000000f, + 0.29031372070312500000f, 0.38848876953124994000f, + 0.56964111328125000000f, 0.63232421875000000000f, + 0.79367065429687500000f, 0.86746215820312500000f, + 0.08334350585937500000f, 0.11074829101562500000f, + 0.25390625000000000000f, 0.37994384765625000000f, + 0.43066406250000000000f, 0.50143432617187500000f, + 0.56604003906250000000f, 0.67437744140625000000f, + 0.77297973632812500000f, 0.84588623046875000000f, + 0.10623168945312500000f, 0.13430786132812500000f, + 0.22341918945312503000f, 0.28439331054687500000f, + 0.33758544921875000000f, 0.39956665039062500000f, + 0.46145629882812500000f, 0.68099975585937489000f, + 0.80355834960937500000f, 0.87707519531250000000f, + 0.10916137695312500000f, 0.15090942382812500000f, + 0.20352172851562500000f, 0.26831054687500000000f, + 0.31430053710937500000f, 0.38589477539062506000f, + 0.59524536132812500000f, 0.75579833984375000000f, + 0.82385253906250011000f, 0.90435791015625000000f, + 0.12384033203125000000f, 0.15441894531250000000f, + 0.22241210937500000000f, 0.31097412109375000000f, + 0.35778808593750000000f, 0.42529296875000000000f, + 0.48367309570312500000f, 0.56576538085937500000f, + 0.81484985351562500000f, 0.91079711914062500000f, + 0.13006591796875000000f, 0.16448974609374997000f, + 0.21536254882812503000f, 0.27410888671875000000f, + 0.31088256835937500000f, 0.46582031250000000000f, + 0.62500000000000000000f, 0.68176269531250000000f, + 0.79217529296875000000f, 0.85668945312500000000f, + 0.10388183593750000000f, 0.13211059570312500000f, + 0.20230102539062497000f, 0.24249267578125000000f, + 0.30886840820312500000f, 0.52383422851562500000f, + 0.59936523437500000000f, 0.67883300781249989000f, + 0.76483154296875000000f, 0.83837890625000000000f, + 0.09634399414062501400f, 0.12719726562500000000f, + 0.18905639648437500000f, 0.28439331054687500000f, + 0.32870483398437500000f, 0.40664672851562500000f, + 0.47045898437500000000f, 0.60473632812500000000f, + 0.75292968750000000000f, 0.84332275390625000000f, + 0.07638549804687500000f, 0.10598754882812500000f, + 0.15655517578125000000f, 0.20651245117187500000f, + 0.26156616210937500000f, 0.45477294921875000000f, + 0.58084106445312500000f, 0.66912841796874989000f, + 0.79544067382812511000f, 0.87670898437500000000f, + 0.12612915039062500000f, 0.15570068359375000000f, + 0.23049926757812503000f, 0.30682373046875000000f, + 0.35879516601562500000f, 0.45544433593750000000f, + 0.53207397460937500000f, 0.61602783203125000000f, + 0.73202514648437489000f, 0.80175781249999989000f, + 0.15173339843750000000f, 0.18734741210937500000f, + 0.24090576171875000000f, 0.29397583007812500000f, + 0.34545898437500000000f, 0.43624877929687500000f, + 0.66336059570312500000f, 0.74176025390625000000f, + 0.82150268554687489000f, 0.91268920898437500000f, + 0.09027099609375000000f, 0.11645507812500000000f, + 0.20907592773437500000f, 0.28088378906250000000f, + 0.33248901367187506000f, 0.55090332031250000000f, + 0.63449096679687500000f, 0.71221923828125000000f, + 0.84094238281250000000f, 0.90359497070312500000f, + 0.15972900390625000000f, 0.18395996093750003000f, + 0.24517822265625000000f, 0.30987548828125000000f, + 0.34307861328125000000f, 0.45132446289062500000f, + 0.57824707031250000000f, 0.63983154296875000000f, + 0.81130981445312500000f, 0.88888549804687500000f, + 0.15994262695312503000f, 0.20867919921875000000f, + 0.32122802734375006000f, 0.39120483398437500000f, + 0.44802856445312500000f, 0.52880859375000000000f, + 0.60815429687500000000f, 0.68164062500000000000f, + 0.79934692382812500000f, 0.87576293945312500000f, + 0.10412597656250000000f, 0.12973022460937500000f, + 0.18273925781250000000f, 0.21649169921875000000f, + 0.30233764648437500000f, 0.55673217773437500000f, + 0.66128540039062500000f, 0.72561645507812511000f, + 0.82302856445312500000f, 0.88766479492187500000f, + 0.07537841796875000000f, 0.09817504882812500000f, + 0.23794555664062500000f, 0.46679687499999994000f, + 0.52993774414062500000f, 0.58395385742187500000f, + 0.67074584960937500000f, 0.74023437500000000000f, + 0.83380126953124989000f, 0.89849853515625000000f, + 0.15072631835937500000f, 0.17712402343750000000f, + 0.24856567382812500000f, 0.36038208007812506000f, + 0.42337036132812500000f, 0.47601318359375000000f, + 0.52593994140625000000f, 0.59274291992187500000f, + 0.80798339843750000000f, 0.90469360351562500000f, + 0.15414428710937500000f, 0.18820190429687497000f, + 0.25094604492187500000f, 0.29464721679687500000f, + 0.37106323242187500000f, 0.54916381835937500000f, + 0.62451171875000000000f, 0.69677734375000011000f, + 0.81225585937500000000f, 0.86859130859375000000f, + 0.15219116210937500000f, 0.18026733398437500000f, + 0.28439331054687500000f, 0.34317016601562500000f, + 0.40075683593750000000f, 0.45849609375000000000f, + 0.53359985351562500000f, 0.69235229492187511000f, + 0.79379272460937511000f, 0.86282348632812489000f, + 0.15676879882812500000f, 0.21008300781250000000f, + 0.33645629882812500000f, 0.45623779296875000000f, + 0.52462768554687500000f, 0.59280395507812500000f, + 0.66549682617187489000f, 0.74441528320312511000f, + 0.82208251953125000000f, 0.89379882812500000000f, + 0.21536254882812503000f, 0.24060058593750000000f, + 0.29077148437500000000f, 0.31991577148437500000f, + 0.33447265625000000000f, 0.45199584960937500000f, + 0.58197021484375000000f, 0.66146850585937500000f, + 0.78262329101562511000f, 0.85507202148437500000f, + 0.20626831054687500000f, 0.21850585937500000000f, + 0.26080322265625000000f, 0.35946655273437500000f, + 0.37521362304687500000f, 0.39743041992187500000f, + 0.50741577148437500000f, 0.64389038085937500000f, + 0.75369262695312500000f, 0.86325073242187500000f, + 0.11788940429687500000f, 0.29791259765625000000f, + 0.33776855468749994000f, 0.34927368164062500000f, + 0.36770629882812506000f, 0.42602539062500000000f, + 0.55191040039062500000f, 0.65634155273437500000f, + 0.76977539062500000000f, 0.88491821289062489000f, + 0.01211547851562500000f, 0.01022338867187500000f, + 0.01986694335937500000f, 0.03564453125000000000f, + 0.01953125000000000000f, 0.02334594726562500000f, + 0.01419067382812500000f, 0.01010131835937500000f, + 0.00653076171875000000f, -0.00592041015625000000f, + -0.01763916015625000000f, -0.01974487304687500000f, + -0.02005004882812500000f, 0.02288818359375000000f, + 0.01721191406250000000f, 0.01870727539062500000f, + 0.01675415039062500000f, 0.01922607421875000000f, + 0.00927734375000000000f, -0.00158691406250000020f, + 0.02526855468749999700f, 0.02813720703125000000f, + 0.01351928710937500000f, 0.00338745117187500000f, + 0.00421142578125000000f, 0.00378417968750000000f, + 0.00515747070312500000f, 0.00042724609375000000f, + 0.00439453125000000000f, 0.00253295898437500040f, + 0.00402832031250000000f, 0.00177001953125000000f, + -0.01260375976562500000f, -0.02294921875000000000f, + 0.02651977539062500000f, 0.01025390625000000000f, + 0.01174926757812500200f, 0.00210571289062500000f, + 0.00170898437500000000f, 0.02532958984375000000f, + -0.00692749023437500000f, -0.00811767578125000000f, + -0.01123046875000000000f, -0.01342773437500000000f, + -0.03646850585937500000f, 0.00497436523437500000f, + 0.00384521484375000000f, -0.00695800781250000000f, + 0.02447509765625000000f, 0.00476074218750000000f, + 0.00573730468750000000f, 0.00366210937499999960f, + 0.01147460937500000000f, 0.00180053710937500000f, + -0.01092529296875000000f, -0.01702880859375000000f, + -0.04046630859375000000f, -0.00775146484375000000f, + -0.00616455078125000000f, -0.02407836914062500000f, + 0.00903320312500000000f, 0.00280761718750000000f, + -0.00213623046875000000f, -0.00393676757812500000f, + -0.02191162109375000000f, -0.03463745117187500000f, + 0.00891113281250000000f, -0.00088500976562500000f, + -0.01925659179687500000f, 0.01486206054687500000f, + -0.00479125976562500000f, -0.00466918945312500000f, + -0.00851440429687500000f, 0.00006103515625000000f, + -0.01278686523437500000f, -0.01043701171875000000f, + -0.00103759765625000000f, -0.01568603515625000000f, + -0.02438354492187499700f, -0.04794311523437500000f, + -0.02096557617187500000f, -0.01858520507812500000f, + -0.01666259765625000000f, -0.00396728515625000000f, + -0.00656127929687500000f, -0.00769042968750000000f, + -0.01361083984375000000f, -0.01751708984375000000f, + -0.04080200195312500000f, 0.00631713867187499910f, + -0.00219726562500000000f, 0.00097656250000000000f, + 0.00314331054687500000f, -0.01959228515625000000f, + 0.02874755859375000300f, 0.02236938476562499700f, + 0.00570678710937500090f, 0.00088500976562500000f, + -0.00643920898437500000f, -0.02484130859375000300f, + 0.00436401367187500000f, 0.00686645507812500000f, + 0.00061035156250000000f, 0.00073242187500000000f, + -0.00817871093750000000f, -0.01150512695312500000f, + 0.04953002929687499300f, 0.03457641601562500000f, + 0.02035522460937500000f, 0.00500488281250000000f, + 0.00936889648437500000f, 0.01116943359375000000f, + 0.00570678710937500090f, 0.00103759765625000000f, + 0.00189208984375000000f, -0.00955200195312500000f, + -0.02539062500000000300f, -0.04522705078125000000f, + -0.03604125976562500000f, 0.01473999023437500000f, + -0.00128173828125000000f, -0.00119018554687500000f, + -0.01373291015625000000f, -0.04290771484375000000f, + -0.01791381835937500000f, -0.00158691406250000020f, + -0.02319335937500000000f, 0.01019287109375000000f, + 0.00299072265625000000f, -0.00183105468749999980f, + -0.01525878906249999800f, -0.01489257812500000000f, + -0.03228759765625000000f, 0.00912475585937500000f, + 0.00399780273437500000f, -0.00762939453124999910f, + -0.00765991210937500090f, -0.02145385742187500000f, + 0.03164672851562500000f, 0.01733398437500000000f, + -0.01260375976562500000f, -0.00808715820312500000f, + 0.05148315429687500000f, 0.01748657226562500000f, + 0.01052856445312500000f, 0.00985717773437500000f, + 0.00299072265625000000f, 0.00186157226562500000f, + -0.00311279296875000000f, 0.00094604492187500000f, + 0.00411987304687500000f, 0.00454711914062500000f, + 0.01882934570312500000f, 0.01113891601562500000f, + -0.00119018554687500000f, 0.00103759765625000000f, + -0.01864624023437500000f, 0.03665161132812500000f, + 0.04336547851562500000f, 0.02246093750000000000f, + -0.01263427734374999800f, -0.01199340820312500000f, + -0.01501464843750000000f, -0.01046752929687500200f, + -0.00964355468750000000f, -0.01623535156250000000f, + 0.01611328125000000000f, 0.00524902343750000000f, + 0.00274658203125000000f, 0.00982666015625000000f, + -0.00897216796875000000f, -0.00973510742187500000f, + -0.01651000976562500000f, 0.01535034179687500000f, + 0.01950073242187500000f, 0.01223754882812500000f, + 0.00003051757812500000f, -0.00454711914062500000f, + -0.00222778320312500000f, -0.00509643554687500000f, + 0.00457763671875000000f, 0.00360107421875000000f, + 0.00939941406250000000f, 0.00665283203124999910f, + 0.00369262695312500000f, 0.00595092773437500000f, + -0.00436401367187500000f, -0.00796508789062500000f, + -0.03091430664062500000f, -0.02447509765625000000f, + 0.01181030273437500000f, 0.01330566406249999800f, + 0.00396728515625000000f, -0.01303100585937500200f, + -0.01367187500000000000f, -0.02078247070312500000f, + 0.00375366210937500000f, -0.00265502929687500000f, + -0.00765991210937500090f, -0.00344848632812500000f, + 0.00836181640625000000f, 0.00946044921875000000f, + 0.01358032226562500000f, 0.01528930664062500000f, + 0.01080322265625000200f, 0.00830078125000000000f, + 0.00430297851562500000f, -0.00869750976562500000f, + 0.01736450195312500000f, 0.02001953125000000000f, + 0.00112915039062500000f, -0.00149536132812500000f, + 0.00765991210937500090f, -0.01177978515625000000f, + -0.00802612304687500000f, 0.03424072265625000000f, + 0.01843261718750000000f, 0.01849365234375000000f, + 0.01025390625000000000f, 0.00289916992187500000f, + 0.00103759765625000000f, 0.00000000000000000000f, + 0.00259399414062500000f, 0.00549316406250000000f, + 0.00631713867187499910f, -0.01119995117187500000f, + -0.01898193359375000000f, 0.03265380859375000000f, + -0.00018310546875000000f, -0.00241088867187500000f, + -0.00488281250000000000f, -0.00280761718750000000f, + -0.00418090820312500000f, -0.00842285156250000000f, + -0.00985717773437500000f, -0.01132202148437500000f, + -0.02124023437500000000f, -0.03161621093750000000f, + 0.01242065429687500200f, 0.00311279296875000000f, + -0.00262451171875000000f, -0.00653076171875000000f, + -0.01470947265625000200f, -0.01974487304687500000f, + -0.00085449218750000000f, -0.00888061523437500000f, + -0.00296020507812500000f, -0.00549316406250000000f, + -0.00762939453124999910f, -0.01327514648437500000f, + -0.00054931640625000000f, -0.00231933593750000000f, + -0.01013183593750000200f, 0.01251220703125000000f, + 0.01242065429687500200f, 0.00512695312500000000f, + 0.01644897460937500000f, 0.01254272460937500000f, + 0.00775146484375000000f, 0.00338745117187500000f, + 0.00177001953125000000f, -0.00442504882812500000f, + 0.00610351562500000000f, 0.00091552734374999989f, + 0.00570678710937500090f, 0.00354003906250000000f, + 0.00399780273437500000f, -0.01119995117187500000f, + -0.01449584960937500000f, 0.02383422851562500300f, + -0.01705932617187500000f, 0.01712036132812500000f, + 0.00595092773437500000f, -0.00350952148437500040f, + 0.00024414062500000000f, -0.00512695312500000000f, + 0.00091552734374999989f, 0.00167846679687500000f, + -0.00372314453125000000f, 0.00399780273437500000f, + 0.00250244140625000000f, -0.00015258789062500000f, + -0.00833129882812500000f, -0.00152587890625000000f, + -0.01928710937500000000f, 0.02038574218750000000f, + 0.00012207031250000000f, 0.00097656250000000000f, + -0.00079345703125000011f, -0.00851440429687500000f, + 0.00961303710937500000f, 0.00503540039062499910f, + 0.00601196289062499910f, 0.01150512695312500000f, + 0.00473022460937500000f, -0.00125122070312500000f, + -0.00421142578125000000f, -0.00988769531250000000f, + -0.00332641601562499960f, -0.01882934570312500000f, + 0.01098632812500000000f, 0.00299072265625000000f, + -0.00161743164062500000f, -0.00973510742187500000f, + -0.00347900390625000000f, -0.00747680664062500000f, + -0.00250244140625000000f, 0.01547241210937500000f, + 0.01428222656250000000f, 0.00802612304687500000f, + -0.00418090820312500000f, -0.01187133789062500000f, + 0.01989746093750000000f, 0.01080322265625000200f, + -0.00054931640625000000f, -0.00692749023437500000f, + -0.01409912109375000000f, -0.00411987304687500000f, + 0.00967407226562500000f, 0.00161743164062500000f, + -0.00048828125000000000f, 0.00201416015625000000f, + -0.00219726562500000000f, -0.00384521484375000000f, + -0.01086425781250000000f, -0.01058959960937500000f, + -0.01000976562500000000f, -0.00219726562500000000f, + -0.01028442382812500000f, 0.00988769531250000000f, + 0.00463867187500000000f, 0.01065063476562500000f, + 0.00515747070312500000f, -0.00598144531250000000f, + 0.00546264648437500000f, 0.00775146484375000000f, + 0.00793457031250000000f, 0.00991821289062500000f, + -0.00225830078125000000f, -0.00244140625000000000f, + 0.00228881835937500000f, -0.00094604492187500000f, + 0.00823974609375000000f, 0.00839233398437500000f, + 0.00265502929687500000f, 0.00848388671875000000f, + -0.01361083984375000000f, -0.00918579101562500000f, + 0.00942993164062500000f, 0.00216674804687500000f, + -0.00076293945312500000f, -0.00738525390625000000f, + 0.01574707031250000000f, 0.00491333007812500000f, + -0.00494384765625000000f, -0.00253295898437500040f, + 0.01004028320312500000f, 0.00701904296875000090f, + -0.00949096679687500000f, -0.00790405273437500000f, + 0.00540161132812500090f, -0.00079345703125000011f, + -0.01409912109375000000f, 0.00271606445312500000f, + 0.00784301757812500000f, 0.00018310546875000000f, + -0.00396728515625000000f, -0.00283813476562499960f, + -0.01391601562500000000f, -0.00967407226562500000f, + -0.00674438476562500000f, -0.00628662109375000000f, + -0.01272583007812500000f, -0.00555419921875000000f, + -0.00225830078125000000f, 0.00714111328125000000f, + 0.00146484375000000000f, 0.00796508789062500000f, + 0.01095581054687500000f, 0.00704956054687500000f, + 0.00787353515625000000f, 0.00259399414062500000f, + -0.00860595703125000000f, 0.00769042968750000000f, + -0.00448608398437500000f, -0.00677490234375000000f, + 0.00765991210937500090f, -0.00631713867187499910f, + 0.01351928710937500000f, 0.00375366210937500000f, + -0.01272583007812500000f, -0.00109863281250000000f, + 0.00833129882812500000f, -0.00735473632812500090f, + 0.00732421874999999910f, -0.00341796875000000000f, + 0.00134277343749999980f, -0.00509643554687500000f, + 0.00384521484375000000f, -0.00378417968750000000f, + -0.00234985351562500000f, 0.00177001953125000000f, + -0.01223754882812500000f, 0.01016235351562500000f, + -0.00360107421875000000f, 0.00250244140625000000f, + 0.00384521484375000000f, 0.00460815429687500000f, + -0.01321411132812500000f, 0.01095581054687500000f, + -0.00396728515625000000f, -0.00311279296875000000f, + 0.00399780273437500000f, -0.00744628906250000000f, + 0.00262451171875000000f, 0.00259399414062500000f, + -0.01409912109375000000f, 0.01263427734374999800f, + -0.00732421874999999910f, 0.00048828125000000000f, + 0.00442504882812500000f, 0.00085449218750000000f, + -0.00625610351562500000f, -0.01467895507812500000f, + 0.01138305664062500000f, 0.00894165039062500000f, + -0.00219726562500000000f, -0.00531005859375000000f, + 0.00189208984375000000f, 0.00790405273437500000f, + -0.00024414062500000000f, -0.00054931640625000000f, + 0.01104736328125000000f, 0.00711059570312500000f, + 0.00564575195312500000f, 0.00131225585937500000f, + 0.00848388671875000000f, 0.00082397460937500000f, + 0.00588989257812500000f, 0.01739501953125000000f, + -0.00756835937500000000f, 0.00576782226562500000f, + 0.00280761718750000000f, 0.00094604492187500000f, + -0.00839233398437500000f, -0.00009155273437500000f, + 0.00741577148437500000f, 0.00537109374999999910f, + 0.01336669921875000200f, 0.00637817382812500090f, + 0.00628662109375000000f, -0.00155639648437500000f, + 0.00241088867187500000f, 0.00332641601562499960f, + 0.00512695312500000000f, -0.00564575195312500000f, + -0.00939941406250000000f, -0.00207519531250000000f, + -0.01885986328125000000f, 0.01174926757812500200f, + -0.00946044921875000000f, -0.00329589843750000000f, + -0.00500488281250000000f, 0.00503540039062499910f, + 0.00186157226562500000f, -0.00463867187500000000f, + -0.00308227539062500000f, -0.01257324218750000000f, + -0.00817871093750000000f, -0.00784301757812500000f, + -0.00122070312500000000f, -0.00061035156250000000f, + -0.00085449218750000000f, -0.00482177734375000000f, + -0.00918579101562500000f, 0.00827026367187500000f, + 0.01159667968750000000f, -0.01031494140625000000f, + -0.01119995117187500000f, -0.00402832031250000000f, + 0.00195312500000000000f, 0.00347900390625000000f, + -0.00399780273437500000f, -0.00686645507812500000f, + -0.00476074218750000000f, -0.00793457031250000000f, + -0.00192260742187500000f, -0.00354003906250000000f, + 0.00473022460937500000f, -0.01788330078125000000f, + -0.00616455078125000000f, 0.00775146484375000000f, + -0.00875854492187500000f, 0.00543212890625000000f, + 0.00692749023437500000f, -0.00323486328125000000f, + -0.00897216796875000000f, 0.00500488281250000000f, + 0.00909423828125000000f, -0.00305175781250000000f, + 0.00564575195312500000f, 0.00967407226562500000f, + 0.00588989257812500000f, -0.00137329101562500000f, + 0.00085449218750000000f, 0.00244140625000000000f, + -0.00265502929687500000f, -0.01321411132812500000f, + 0.00067138671874999989f, -0.00146484375000000000f, + 0.00146484375000000000f, -0.00723266601562500000f, + -0.00698852539062499910f, -0.00424194335937500000f, + 0.00366210937499999960f, -0.01110839843750000000f, + 0.00817871093750000000f, -0.00415039062500000000f, + 0.01208496093750000200f, 0.00381469726562499960f, + 0.00396728515625000000f, -0.00271606445312500000f, + -0.00830078125000000000f, 0.00360107421875000000f, + -0.00781250000000000000f, -0.00207519531250000000f, + -0.01376342773437500000f, 0.01489257812500000000f, + 0.00436401367187500000f, -0.00503540039062499910f, + -0.00146484375000000000f, -0.00579833984375000000f, + 0.00323486328125000000f, 0.00668334960937500090f, + 0.00143432617187500000f, 0.01327514648437500000f, + 0.00747680664062500000f, 0.00296020507812500000f, + 0.00228881835937500000f, -0.01275634765625000200f, + 0.00369262695312500000f, -0.00570678710937500090f, + 0.01739501953125000000f, -0.00610351562500000000f, + -0.01071166992187500000f, 0.00686645507812500000f, + -0.00064086914062500000f, -0.00662231445312500000f, + 0.00714111328125000000f, -0.00338745117187500000f, + 0.00592041015625000000f, 0.00042724609375000000f, + 0.00738525390625000000f, 0.00360107421875000000f, + 0.00427246093750000000f, -0.01211547851562500000f, + 0.01083374023437500000f, 0.01101684570312499800f, + -0.00137329101562500000f, -0.00595092773437500000f +}; + +const SKP_Silk_NLSF_CBS_FLP SKP_Silk_NLSF_CB0_10_Stage_info_FLP[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + { 64, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 80 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 88 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 96 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 96 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10[ 10 * 104 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates[ 104 ] } +}; + +const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB0_10_FLP = +{ + NLSF_MSVQ_CB0_10_STAGES, + SKP_Silk_NLSF_CB0_10_Stage_info_FLP, + SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.c new file mode 100755 index 0000000..143d2c2 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.c @@ -0,0 +1,1320 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.51 + 7.38 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB0_16.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ NLSF_MSVQ_CB0_16_VECTORS + NLSF_MSVQ_CB0_16_STAGES ] = +{ + 0, + 1449, + 2749, + 4022, + 5267, + 6434, + 7600, + 8647, + 9695, + 10742, + 11681, + 12601, + 13444, + 14251, + 15008, + 15764, + 16521, + 17261, + 18002, + 18710, + 19419, + 20128, + 20837, + 21531, + 22225, + 22919, + 23598, + 24277, + 24956, + 25620, + 26256, + 26865, + 27475, + 28071, + 28667, + 29263, + 29859, + 30443, + 31026, + 31597, + 32168, + 32727, + 33273, + 33808, + 34332, + 34855, + 35379, + 35902, + 36415, + 36927, + 37439, + 37941, + 38442, + 38932, + 39423, + 39914, + 40404, + 40884, + 41364, + 41844, + 42324, + 42805, + 43285, + 43754, + 44224, + 44694, + 45164, + 45623, + 46083, + 46543, + 46993, + 47443, + 47892, + 48333, + 48773, + 49213, + 49653, + 50084, + 50515, + 50946, + 51377, + 51798, + 52211, + 52614, + 53018, + 53422, + 53817, + 54212, + 54607, + 55002, + 55388, + 55775, + 56162, + 56548, + 56910, + 57273, + 57635, + 57997, + 58352, + 58698, + 59038, + 59370, + 59702, + 60014, + 60325, + 60630, + 60934, + 61239, + 61537, + 61822, + 62084, + 62346, + 62602, + 62837, + 63072, + 63302, + 63517, + 63732, + 63939, + 64145, + 64342, + 64528, + 64701, + 64867, + 65023, + 65151, + 65279, + 65407, + 65535, + 0, + 5099, + 9982, + 14760, + 19538, + 24213, + 28595, + 32976, + 36994, + 41012, + 44944, + 48791, + 52557, + 56009, + 59388, + 62694, + 65535, + 0, + 9955, + 19697, + 28825, + 36842, + 44686, + 52198, + 58939, + 65535, + 0, + 8949, + 17335, + 25720, + 33926, + 41957, + 49987, + 57845, + 65535, + 0, + 9724, + 18642, + 26998, + 35355, + 43532, + 51534, + 59365, + 65535, + 0, + 8750, + 17499, + 26249, + 34448, + 42471, + 50494, + 58178, + 65535, + 0, + 8730, + 17273, + 25816, + 34176, + 42536, + 50203, + 57869, + 65535, + 0, + 8769, + 17538, + 26307, + 34525, + 42742, + 50784, + 58319, + 65535, + 0, + 8736, + 17101, + 25466, + 33653, + 41839, + 50025, + 57864, + 65535, + 0, + 4368, + 8735, + 12918, + 17100, + 21283, + 25465, + 29558, + 33651, + 37744, + 41836, + 45929, + 50022, + 54027, + 57947, + 61782, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 129 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 146 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 155 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 164 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 173 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 182 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 191 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 200 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 209 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + 42, + 8, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 9 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 176, 181, + 182, 183, + 186, 186, + 191, 191, + 191, 196, + 197, 201, + 203, 206, + 206, 206, + 207, 207, + 209, 209, + 209, 209, + 210, 210, + 210, 211, + 211, 211, + 212, 214, + 216, 216, + 217, 217, + 217, 217, + 218, 218, + 219, 219, + 220, 221, + 222, 223, + 223, 223, + 223, 224, + 224, 224, + 225, 225, + 226, 226, + 226, 226, + 227, 227, + 227, 227, + 227, 227, + 228, 228, + 228, 228, + 229, 229, + 229, 230, + 230, 230, + 231, 231, + 231, 231, + 232, 232, + 232, 232, + 233, 234, + 235, 235, + 235, 236, + 236, 236, + 236, 237, + 237, 237, + 237, 240, + 240, 240, + 240, 241, + 242, 243, + 244, 244, + 247, 247, + 248, 248, + 248, 249, + 251, 255, + 255, 256, + 260, 260, + 261, 264, + 264, 266, + 266, 268, + 271, 274, + 276, 279, + 288, 288, + 288, 288, + 118, 120, + 121, 121, + 122, 125, + 125, 129, + 129, 130, + 131, 132, + 136, 137, + 138, 145, + 87, 88, + 91, 97, + 98, 100, + 105, 106, + 92, 95, + 95, 96, + 97, 97, + 98, 99, + 88, 92, + 95, 95, + 96, 97, + 98, 109, + 93, 93, + 93, 96, + 97, 97, + 99, 101, + 93, 94, + 94, 95, + 95, 99, + 99, 99, + 93, 93, + 93, 96, + 96, 97, + 100, 102, + 93, 95, + 95, 96, + 96, 96, + 98, 99, + 125, 125, + 127, 127, + 127, 127, + 128, 128, + 128, 128, + 128, 128, + 129, 130, + 131, 132 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min_Q15[ 16 + 1 ] = +{ + 266, + 3, + 40, + 3, + 3, + 16, + 78, + 89, + 107, + 141, + 188, + 146, + 272, + 240, + 235, + 215, + 632 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 1170, 2278, 3658, 5374, + 7666, 9113, 11298, 13304, + 15371, 17549, 19587, 21487, + 23798, 26038, 28318, 30201, + 1628, 2334, 4115, 6036, + 7818, 9544, 11777, 14021, + 15787, 17408, 19466, 21261, + 22886, 24565, 26714, 28059, + 1724, 2670, 4056, 6532, + 8357, 10119, 12093, 14061, + 16491, 18795, 20417, 22402, + 24251, 26224, 28410, 29956, + 1493, 3427, 4789, 6399, + 8435, 10168, 12000, 14066, + 16229, 18210, 20040, 22098, + 24153, 26095, 28183, 30121, + 1119, 2089, 4295, 6245, + 8691, 10741, 12688, 15057, + 17028, 18792, 20717, 22514, + 24497, 26548, 28619, 30630, + 1363, 2417, 3927, 5556, + 7422, 9315, 11879, 13767, + 16143, 18520, 20458, 22578, + 24539, 26436, 28318, 30318, + 1122, 2503, 5216, 7148, + 9310, 11078, 13175, 14800, + 16864, 18700, 20436, 22488, + 24572, 26602, 28555, 30426, + 600, 1317, 2970, 5609, + 7694, 9784, 12169, 14087, + 16379, 18378, 20551, 22686, + 24739, 26697, 28646, 30355, + 941, 1882, 4274, 5540, + 8482, 9858, 11940, 14287, + 16091, 18501, 20326, 22612, + 24711, 26638, 28814, 30430, + 635, 1699, 4376, 5948, + 8097, 10115, 12274, 14178, + 16111, 17813, 19695, 21773, + 23927, 25866, 28022, 30134, + 1408, 2222, 3524, 5615, + 7345, 8849, 10989, 12772, + 15352, 17026, 18919, 21062, + 23329, 25215, 27209, 29023, + 701, 1307, 3548, 6301, + 7744, 9574, 11227, 12978, + 15170, 17565, 19775, 22097, + 24230, 26335, 28377, 30231, + 1752, 2364, 4879, 6569, + 7813, 9796, 11199, 14290, + 15795, 18000, 20396, 22417, + 24308, 26124, 28360, 30633, + 901, 1629, 3356, 4635, + 7256, 8767, 9971, 11558, + 15215, 17544, 19523, 21852, + 23900, 25978, 28133, 30184, + 981, 1669, 3323, 4693, + 6213, 8692, 10614, 12956, + 15211, 17711, 19856, 22122, + 24344, 26592, 28723, 30481, + 1607, 2577, 4220, 5512, + 8532, 10388, 11627, 13671, + 15752, 17199, 19840, 21859, + 23494, 25786, 28091, 30131, + 811, 1471, 3144, 5041, + 7430, 9389, 11174, 13255, + 15157, 16741, 19583, 22167, + 24115, 26142, 28383, 30395, + 1543, 2144, 3629, 6347, + 7333, 9339, 10710, 13596, + 15099, 17340, 20102, 21886, + 23732, 25637, 27818, 29917, + 492, 1185, 2940, 5488, + 7095, 8751, 11596, 13579, + 16045, 18015, 20178, 22127, + 24265, 26406, 28484, 30357, + 1547, 2282, 3693, 6341, + 7758, 9607, 11848, 13236, + 16564, 18069, 19759, 21404, + 24110, 26606, 28786, 30655, + 685, 1338, 3409, 5262, + 6950, 9222, 11414, 14523, + 16337, 17893, 19436, 21298, + 23293, 25181, 27973, 30520, + 887, 1581, 3057, 4318, + 7192, 8617, 10047, 13106, + 16265, 17893, 20233, 22350, + 24379, 26384, 28314, 30189, + 2285, 3745, 5662, 7576, + 9323, 11320, 13239, 15191, + 17175, 19225, 21108, 22972, + 24821, 26655, 28561, 30460, + 1496, 2108, 3448, 6898, + 8328, 9656, 11252, 12823, + 14979, 16482, 18180, 20085, + 22962, 25160, 27705, 29629, + 575, 1261, 3861, 6627, + 8294, 10809, 12705, 14768, + 17076, 19047, 20978, 23055, + 24972, 26703, 28720, 30345, + 1682, 2213, 3882, 6238, + 7208, 9646, 10877, 13431, + 14805, 16213, 17941, 20873, + 23550, 25765, 27756, 29461, + 888, 1616, 3924, 5195, + 7206, 8647, 9842, 11473, + 16067, 18221, 20343, 22774, + 24503, 26412, 28054, 29731, + 805, 1454, 2683, 4472, + 7936, 9360, 11398, 14345, + 16205, 17832, 19453, 21646, + 23899, 25928, 28387, 30463, + 1640, 2383, 3484, 5082, + 6032, 8606, 11640, 12966, + 15842, 17368, 19346, 21182, + 23638, 25889, 28368, 30299, + 1632, 2204, 4510, 7580, + 8718, 10512, 11962, 14096, + 15640, 17194, 19143, 22247, + 24563, 26561, 28604, 30509, + 2043, 2612, 3985, 6851, + 8038, 9514, 10979, 12789, + 15426, 16728, 18899, 20277, + 22902, 26209, 28711, 30618, + 2224, 2798, 4465, 5320, + 7108, 9436, 10986, 13222, + 14599, 18317, 20141, 21843, + 23601, 25700, 28184, 30582, + 835, 1541, 4083, 5769, + 7386, 9399, 10971, 12456, + 15021, 18642, 20843, 23100, + 25292, 26966, 28952, 30422, + 1795, 2343, 4809, 5896, + 7178, 8545, 10223, 13370, + 14606, 16469, 18273, 20736, + 23645, 26257, 28224, 30390, + 1734, 2254, 4031, 5188, + 6506, 7872, 9651, 13025, + 14419, 17305, 19495, 22190, + 24403, 26302, 28195, 30177, + 1841, 2349, 3968, 4764, + 6376, 9825, 11048, 13345, + 14682, 16252, 18183, 21363, + 23918, 26156, 28031, 29935, + 1432, 2047, 5631, 6927, + 8198, 9675, 11358, 13506, + 14802, 16419, 18339, 22019, + 24124, 26177, 28130, 30586, + 1730, 2320, 3744, 4808, + 6007, 9666, 10997, 13622, + 15234, 17495, 20088, 22002, + 23603, 25400, 27379, 29254, + 1267, 1915, 5483, 6812, + 8229, 9919, 11589, 13337, + 14747, 17965, 20552, 22167, + 24519, 26819, 28883, 30642, + 1526, 2229, 4240, 7388, + 8953, 10450, 11899, 13718, + 16861, 18323, 20379, 22672, + 24797, 26906, 28906, 30622, + 2175, 2791, 4104, 6875, + 8612, 9798, 12152, 13536, + 15623, 17682, 19213, 21060, + 24382, 26760, 28633, 30248, + 454, 1231, 4339, 5738, + 7550, 9006, 10320, 13525, + 16005, 17849, 20071, 21992, + 23949, 26043, 28245, 30175, + 2250, 2791, 4230, 5283, + 6762, 10607, 11879, 13821, + 15797, 17264, 20029, 22266, + 24588, 26437, 28244, 30419, + 1696, 2216, 4308, 8385, + 9766, 11030, 12556, 14099, + 16322, 17640, 19166, 20590, + 23967, 26858, 28798, 30562, + 2452, 3236, 4369, 6118, + 7156, 9003, 11509, 12796, + 15749, 17291, 19491, 22241, + 24530, 26474, 28273, 30073, + 1811, 2541, 3555, 5480, + 9123, 10527, 11894, 13659, + 15262, 16899, 19366, 21069, + 22694, 24314, 27256, 29983, + 1553, 2246, 4559, 5500, + 6754, 7874, 11739, 13571, + 15188, 17879, 20281, 22510, + 24614, 26649, 28786, 30755, + 1982, 2768, 3834, 5964, + 8732, 9908, 11797, 14813, + 16311, 17946, 21097, 22851, + 24456, 26304, 28166, 29755, + 1824, 2529, 3817, 5449, + 6854, 8714, 10381, 12286, + 14194, 15774, 19524, 21374, + 23695, 26069, 28096, 30212, + 2212, 2854, 3947, 5898, + 9930, 11556, 12854, 14788, + 16328, 17700, 20321, 22098, + 23672, 25291, 26976, 28586, + 2023, 2599, 4024, 4916, + 6613, 11149, 12457, 14626, + 16320, 17822, 19673, 21172, + 23115, 26051, 28825, 30758, + 1628, 2206, 3467, 4364, + 8679, 10173, 11864, 13679, + 14998, 16938, 19207, 21364, + 23850, 26115, 28124, 30273, + 2014, 2603, 4114, 7254, + 8516, 10043, 11822, 13503, + 16329, 17826, 19697, 21280, + 23151, 24661, 26807, 30161, + 2376, 2980, 4422, 5770, + 7016, 9723, 11125, 13516, + 15485, 16985, 19160, 20587, + 24401, 27180, 29046, 30647, + 2454, 3502, 4624, 6019, + 7632, 8849, 10792, 13964, + 15523, 17085, 19611, 21238, + 22856, 25108, 28106, 29890, + 1573, 2274, 3308, 5999, + 8977, 10104, 12457, 14258, + 15749, 18180, 19974, 21253, + 23045, 25058, 27741, 30315, + 1943, 2730, 4140, 6160, + 7491, 8986, 11309, 12775, + 14820, 16558, 17909, 19757, + 21512, 23605, 27274, 29527, + 2021, 2582, 4494, 5835, + 6993, 8245, 9827, 14733, + 16462, 17894, 19647, 21083, + 23764, 26667, 29072, 30990, + 1052, 1775, 3218, 4378, + 7666, 9403, 11248, 13327, + 14972, 17962, 20758, 22354, + 25071, 27209, 29001, 30609, + 2218, 2866, 4223, 5352, + 6581, 9980, 11587, 13121, + 15193, 16583, 18386, 20080, + 22013, 25317, 28127, 29880, + 2146, 2840, 4397, 5840, + 7449, 8721, 10512, 11936, + 13595, 17253, 19310, 20891, + 23417, 25627, 27749, 30231, + 1972, 2619, 3756, 6367, + 7641, 8814, 12286, 13768, + 15309, 18036, 19557, 20904, + 22582, 24876, 27800, 30440, + 2005, 2577, 4272, 7373, + 8558, 10223, 11770, 13402, + 16502, 18000, 19645, 21104, + 22990, 26806, 29505, 30942, + 1153, 1822, 3724, 5443, + 6990, 8702, 10289, 11899, + 13856, 15315, 17601, 21064, + 23692, 26083, 28586, 30639, + 1304, 1869, 3318, 7195, + 9613, 10733, 12393, 13728, + 15822, 17474, 18882, 20692, + 23114, 25540, 27684, 29244, + 2093, 2691, 4018, 6658, + 7947, 9147, 10497, 11881, + 15888, 17821, 19333, 21233, + 23371, 25234, 27553, 29998, + 575, 1331, 5304, 6910, + 8425, 10086, 11577, 13498, + 16444, 18527, 20565, 22847, + 24914, 26692, 28759, 30157, + 1435, 2024, 3283, 4156, + 7611, 10592, 12049, 13927, + 15459, 18413, 20495, 22270, + 24222, 26093, 28065, 30099, + 1632, 2168, 5540, 7478, + 8630, 10391, 11644, 14321, + 15741, 17357, 18756, 20434, + 22799, 26060, 28542, 30696, + 1407, 2245, 3405, 5639, + 9419, 10685, 12104, 13495, + 15535, 18357, 19996, 21689, + 24351, 26550, 28853, 30564, + 1675, 2226, 4005, 8223, + 9975, 11155, 12822, 14316, + 16504, 18137, 19574, 21050, + 22759, 24912, 28296, 30634, + 1080, 1614, 3622, 7565, + 8748, 10303, 11713, 13848, + 15633, 17434, 19761, 21825, + 23571, 25393, 27406, 29063, + 1693, 2229, 3456, 4354, + 5670, 10890, 12563, 14167, + 15879, 17377, 19817, 21971, + 24094, 26131, 28298, 30099, + 2042, 2959, 4195, 5740, + 7106, 8267, 11126, 14973, + 16914, 18295, 20532, 21982, + 23711, 25769, 27609, 29351, + 984, 1612, 3808, 5265, + 6885, 8411, 9547, 10889, + 12522, 16520, 19549, 21639, + 23746, 26058, 28310, 30374, + 2036, 2538, 4166, 7761, + 9146, 10412, 12144, 13609, + 15588, 17169, 18559, 20113, + 21820, 24313, 28029, 30612, + 1871, 2355, 4061, 5143, + 7464, 10129, 11941, 15001, + 16680, 18354, 19957, 22279, + 24861, 26872, 28988, 30615, + 2566, 3161, 4643, 6227, + 7406, 9970, 11618, 13416, + 15889, 17364, 19121, 20817, + 22592, 24720, 28733, 31082, + 1700, 2327, 4828, 5939, + 7567, 9154, 11087, 12771, + 14209, 16121, 20222, 22671, + 24648, 26656, 28696, 30745, + 3169, 3873, 5046, 6868, + 8184, 9480, 12335, 14068, + 15774, 17971, 20231, 21711, + 23520, 25245, 27026, 28730, + 1564, 2391, 4229, 6730, + 8905, 10459, 13026, 15033, + 17265, 19809, 21849, 23741, + 25490, 27312, 29061, 30527, + 2864, 3559, 4719, 6441, + 9592, 11055, 12763, 14784, + 16428, 18164, 20486, 22262, + 24183, 26263, 28383, 30224, + 2673, 3449, 4581, 5983, + 6863, 8311, 12464, 13911, + 15738, 17791, 19416, 21182, + 24025, 26561, 28723, 30440, + 2419, 3049, 4274, 6384, + 8564, 9661, 11288, 12676, + 14447, 17578, 19816, 21231, + 23099, 25270, 26899, 28926, + 1278, 2001, 3000, 5353, + 9995, 11777, 13018, 14570, + 16050, 17762, 19982, 21617, + 23371, 25083, 27656, 30172, + 932, 1624, 2798, 4570, + 8592, 9988, 11552, 13050, + 16921, 18677, 20415, 22810, + 24817, 26819, 28804, 30385, + 2324, 2973, 4156, 5702, + 6919, 8806, 10259, 12503, + 15015, 16567, 19418, 21375, + 22943, 24550, 27024, 29849, + 1564, 2373, 3455, 4907, + 5975, 7436, 11786, 14505, + 16107, 18148, 20019, 21653, + 23740, 25814, 28578, 30372, + 3025, 3729, 4866, 6520, + 9487, 10943, 12358, 14258, + 16174, 17501, 19476, 21408, + 23227, 24906, 27347, 29407, + 1270, 1965, 6802, 7995, + 9204, 10828, 12507, 14230, + 15759, 17860, 20369, 22502, + 24633, 26514, 28535, 30525, + 2210, 2749, 4266, 7487, + 9878, 11018, 12823, 14431, + 16247, 18626, 20450, 22054, + 23739, 25291, 27074, 29169, + 1275, 1926, 4330, 6573, + 8441, 10920, 13260, 15008, + 16927, 18573, 20644, 22217, + 23983, 25474, 27372, 28645, + 3015, 3670, 5086, 6372, + 7888, 9309, 10966, 12642, + 14495, 16172, 18080, 19972, + 22454, 24899, 27362, 29975, + 2882, 3733, 5113, 6482, + 8125, 9685, 11598, 13288, + 15405, 17192, 20178, 22426, + 24801, 27014, 29212, 30811, + 2300, 2968, 4101, 5442, + 6327, 7910, 12455, 13862, + 15747, 17505, 19053, 20679, + 22615, 24658, 27499, 30065, + 2257, 2940, 4430, 5991, + 7042, 8364, 9414, 11224, + 15723, 17420, 19253, 21469, + 23915, 26053, 28430, 30384, + 1227, 2045, 3818, 5011, + 6990, 9231, 11024, 13011, + 17341, 19017, 20583, 22799, + 25195, 26876, 29351, 30805, + 1354, 1924, 3789, 8077, + 10453, 11639, 13352, 14817, + 16743, 18189, 20095, 22014, + 24593, 26677, 28647, 30256, + 3142, 4049, 6197, 7417, + 8753, 10156, 11533, 13181, + 15947, 17655, 19606, 21402, + 23487, 25659, 28123, 30304, + 1317, 2263, 4725, 7611, + 9667, 11634, 14143, 16258, + 18724, 20698, 22379, 24007, + 25775, 27251, 28930, 30593, + 1570, 2323, 3818, 6215, + 9893, 11556, 13070, 14631, + 16152, 18290, 21386, 23346, + 25114, 26923, 28712, 30168, + 2297, 3905, 6287, 8558, + 10668, 12766, 15019, 17102, + 19036, 20677, 22341, 23871, + 25478, 27085, 28851, 30520, + 1915, 2507, 4033, 5749, + 7059, 8871, 10659, 12198, + 13937, 15383, 16869, 18707, + 23175, 25818, 28514, 30501, + 2404, 2918, 5190, 6252, + 7426, 9887, 12387, 14795, + 16754, 18368, 20338, 22003, + 24236, 26456, 28490, 30397, + 1621, 2227, 3479, 5085, + 9425, 12892, 14246, 15652, + 17205, 18674, 20446, 22209, + 23778, 25867, 27931, 30093, + 1869, 2390, 4105, 7021, + 11221, 12775, 14059, 15590, + 17024, 18608, 20595, 22075, + 23649, 25154, 26914, 28671, + 2551, 3252, 4688, 6562, + 7869, 9125, 10475, 11800, + 15402, 18780, 20992, 22555, + 24289, 25968, 27465, 29232, + 2705, 3493, 4735, 6360, + 7905, 9352, 11538, 13430, + 15239, 16919, 18619, 20094, + 21800, 23342, 25200, 29257, + 2166, 2791, 4011, 5081, + 5896, 9038, 13407, 14703, + 16543, 18189, 19896, 21857, + 24872, 26971, 28955, 30514, + 1865, 3021, 4696, 6534, + 8343, 9914, 12789, 14103, + 16533, 17729, 21340, 22439, + 24873, 26330, 28428, 30154, + 3369, 4345, 6573, 8763, + 10309, 11713, 13367, 14784, + 16483, 18145, 19839, 21247, + 23292, 25477, 27555, 29447, + 1265, 2184, 5443, 7893, + 10591, 13139, 15105, 16639, + 18402, 19826, 21419, 22995, + 24719, 26437, 28363, 30125, + 1584, 2004, 3535, 4450, + 8662, 10764, 12832, 14978, + 16972, 18794, 20932, 22547, + 24636, 26521, 28701, 30567, + 3419, 4528, 6602, 7890, + 9508, 10875, 12771, 14357, + 16051, 18330, 20630, 22490, + 25070, 26936, 28946, 30542, + 1726, 2252, 4597, 6950, + 8379, 9823, 11363, 12794, + 14306, 15476, 16798, 18018, + 21671, 25550, 28148, 30367, + 3385, 3870, 5307, 6388, + 7141, 8684, 12695, 14939, + 16480, 18277, 20537, 22048, + 23947, 25965, 28214, 29956, + 2771, 3306, 4450, 5560, + 6453, 9493, 13548, 14754, + 16743, 18447, 20028, 21736, + 23746, 25353, 27141, 29066, + 3028, 3900, 6617, 7893, + 9211, 10480, 12047, 13583, + 15182, 16662, 18502, 20092, + 22190, 24358, 26302, 28957, + 2000, 2550, 4067, 6837, + 9628, 11002, 12594, 14098, + 15589, 17195, 18679, 20099, + 21530, 23085, 24641, 29022, + 2844, 3302, 5103, 6107, + 6911, 8598, 12416, 14054, + 16026, 18567, 20672, 22270, + 23952, 25771, 27658, 30026, + 4043, 5150, 7268, 9056, + 10916, 12638, 14543, 16184, + 17948, 19691, 21357, 22981, + 24825, 26591, 28479, 30233, + 2109, 2625, 4320, 5525, + 7454, 10220, 12980, 14698, + 17627, 19263, 20485, 22381, + 24279, 25777, 27847, 30458, + 1550, 2667, 6473, 9496, + 10985, 12352, 13795, 15233, + 17099, 18642, 20461, 22116, + 24197, 26291, 28403, 30132, + 2411, 3084, 4145, 5394, + 6367, 8154, 13125, 16049, + 17561, 19125, 21258, 22762, + 24459, 26317, 28255, 29702, + 4159, 4516, 5956, 7635, + 8254, 8980, 11208, 14133, + 16210, 17875, 20196, 21864, + 23840, 25747, 28058, 30012, + 2026, 2431, 2845, 3618, + 7950, 9802, 12721, 14460, + 16576, 18984, 21376, 23319, + 24961, 26718, 28971, 30640, + 3429, 3833, 4472, 4912, + 7723, 10386, 12981, 15322, + 16699, 18807, 20778, 22551, + 24627, 26494, 28334, 30482, + 4740, 5169, 5796, 6485, + 6998, 8830, 11777, 14414, + 16831, 18413, 20789, 22369, + 24236, 25835, 27807, 30021, + 150, 168, -17, -107, + -142, -229, -320, -406, + -503, -620, -867, -935, + -902, -680, -398, -114, + -398, -355, 49, 255, + 114, 260, 399, 264, + 317, 431, 514, 531, + 435, 356, 238, 106, + -43, -36, -169, -224, + -391, -633, -776, -970, + -844, -455, -181, -12, + 85, 85, 164, 195, + 122, 85, -158, -640, + -903, 9, 7, -124, + 149, 32, 220, 369, + 242, 115, 79, 84, + -146, -216, -70, 1024, + 751, 574, 440, 377, + 352, 203, 30, 16, + -3, 81, 161, 100, + -148, -176, 933, 750, + 404, 171, -2, -146, + -411, -442, -541, -552, + -442, -269, -240, -52, + 603, 635, 405, 178, + 215, 19, -153, -167, + -290, -219, 151, 271, + 151, 119, 303, 266, + 100, 69, -293, -657, + 939, 659, 442, 351, + 132, 98, -16, -1, + -135, -200, -223, -89, + 167, 154, 172, 237, + -45, -183, -228, -486, + 263, 608, 158, -125, + -390, -227, -118, 43, + -457, -392, -769, -840, + 20, -117, -194, -189, + -173, -173, -33, 32, + 174, 144, 115, 167, + 57, 44, 14, 147, + 96, -54, -142, -129, + -254, -331, 304, 310, + -52, -419, -846, -1060, + -88, -123, -202, -343, + -554, -961, -951, 327, + 159, 81, 255, 227, + 120, 203, 256, 192, + 164, 224, 290, 195, + 216, 209, 128, 832, + 1028, 889, 698, 504, + 408, 355, 218, 32, + -115, -84, -276, -100, + -312, -484, 899, 682, + 465, 456, 241, -12, + -275, -425, -461, -367, + -33, -28, -102, -194, + -527, 863, 906, 463, + 245, 13, -212, -305, + -105, 163, 279, 176, + 93, 67, 115, 192, + 61, -50, -132, -175, + -224, -271, -629, -252, + 1158, 972, 638, 280, + 300, 326, 143, -152, + -214, -287, 53, -42, + -236, -352, -423, -248, + -129, -163, -178, -119, + 85, 57, 514, 382, + 374, 402, 424, 423, + 271, 197, 97, 40, + 39, -97, -191, -164, + -230, -256, -410, 396, + 327, 127, 10, -119, + -167, -291, -274, -141, + -99, -226, -218, -139, + -224, -209, -268, -442, + -413, 222, 58, 521, + 344, 258, 76, -42, + -142, -165, -123, -92, + 47, 8, -3, -191, + -11, -164, -167, -351, + -740, 311, 538, 291, + 184, 29, -105, 9, + -30, -54, -17, -77, + -271, -412, -622, -648, + 476, 186, -66, -197, + -73, -94, -15, 47, + 28, 112, -58, -33, + 65, 19, 84, 86, + 276, 114, 472, 786, + 799, 625, 415, 178, + -35, -26, 5, 9, + 83, 39, 37, 39, + -184, -374, -265, -362, + -501, 337, 716, 478, + -60, -125, -163, 362, + 17, -122, -233, 279, + 138, 157, 318, 193, + 189, 209, 266, 252, + -46, -56, -277, -429, + 464, 386, 142, 44, + -43, 66, 264, 182, + 47, 14, -26, -79, + 49, 15, -128, -203, + -400, -478, 325, 27, + 234, 411, 205, 129, + 12, 58, 123, 57, + 171, 137, 96, 128, + -32, 134, -12, 57, + 119, 26, -22, -165, + -500, -701, -528, -116, + 64, -8, 97, -9, + -162, -66, -156, -194, + -303, -546, -341, 546, + 358, 95, 45, 76, + 270, 403, 205, 100, + 123, 50, -53, -144, + -110, -13, 32, -228, + -130, 353, 296, 56, + -372, -253, 365, 73, + 10, -34, -139, -191, + -96, 5, 44, -85, + -179, -129, -192, -246, + -85, -110, -155, -44, + -27, 145, 138, 79, + 32, -148, -577, -634, + 191, 94, -9, -35, + -77, -84, -56, -171, + -298, -271, -243, -156, + -328, -235, -76, -128, + -121, 129, 13, -22, + 32, 45, -248, -65, + 193, -81, 299, 57, + -147, 192, -165, -354, + -334, -106, -156, -40, + -3, -68, 124, -257, + 78, 124, 170, 412, + 227, 105, -104, 12, + 154, 250, 274, 258, + 4, -27, 235, 152, + 51, 338, 300, 7, + -314, -411, 215, 170, + -9, -93, -77, 76, + 67, 54, 200, 315, + 163, 72, -91, -402, + 158, 187, -156, -91, + 290, 267, 167, 91, + 140, 171, 112, 9, + -42, -177, -440, 385, + 80, 15, 172, 129, + 41, -129, -372, -24, + -75, -30, -170, 10, + -118, 57, 78, -101, + 232, 161, 123, 256, + 277, 101, -192, -629, + -100, -60, -232, 66, + 13, -13, -80, -239, + 239, 37, 32, 89, + -319, -579, 450, 360, + 3, -29, -299, -89, + -54, -110, -246, -164, + 6, -188, 338, 176, + -92, 197, 137, 134, + 12, -2, 56, -183, + 114, -36, -131, -204, + 75, -25, -174, 191, + -15, -290, -429, -267, + 79, 37, 106, 23, + -384, 425, 70, -14, + 212, 105, 15, -2, + -42, -37, -123, 108, + 28, -48, 193, 197, + 173, -33, 37, 73, + -57, 256, 137, -58, + -430, -228, 217, -51, + -10, -58, -6, 22, + 104, 61, -119, 169, + 144, 16, -46, -394, + 60, 454, -80, -298, + -65, 25, 0, -24, + -65, -417, 465, 276, + -3, -194, -13, 130, + 19, -6, -21, -24, + -180, -53, -85, 20, + 118, 147, 113, -75, + -289, 226, -122, 227, + 270, 125, 109, 197, + 125, 138, 44, 60, + 25, -55, -167, -32, + -139, -193, -173, -316, + 287, -208, 253, 239, + 27, -80, -188, -28, + -182, -235, 156, -117, + 128, -48, -58, -226, + 172, 181, 167, 19, + 62, 10, 2, 181, + 151, 108, -16, -11, + -78, -331, 411, 133, + 17, 104, 64, -184, + 24, -30, -3, -283, + 121, 204, -8, -199, + -21, -80, -169, -157, + -191, -136, 81, 155, + 14, -131, 244, 74, + -57, -47, -280, 347, + 111, -77, -128, -142, + -194, -125, -6, -68, + 91, 1, 23, 14, + -154, -34, 23, -38, + -343, 503, 146, -38, + -46, -41, 58, 31, + 63, -48, -117, 45, + 28, 1, -89, -5, + -44, -29, -448, 487, + 204, 81, 46, -106, + -302, 380, 120, -38, + -12, -39, 70, -3, + 25, -65, 30, -11, + 34, -15, 22, -115, + 0, -79, -83, 45, + 114, 43, 150, 36, + 233, 149, 195, 5, + 25, -52, -475, 274, + 28, -39, -8, -66, + -255, 258, 56, 143, + -45, -190, 165, -60, + 20, 2, 125, -129, + 51, -8, -335, 288, + 38, 59, 25, -42, + 23, -118, -112, 11, + -55, -133, -109, 24, + -105, 78, -64, -245, + 202, -65, -127, 162, + 40, -94, 89, -85, + -119, -103, 97, 9, + -70, -28, 194, 86, + -112, -92, -114, 74, + -49, 46, -84, -178, + 113, 52, -205, 333, + 88, 222, 56, -55, + 13, 86, 4, -77, + 224, 114, -105, 112, + 125, -29, -18, -144, + 22, -58, -99, 28, + 114, -66, -32, -169, + -314, 285, 72, -74, + 179, 28, -79, -182, + 13, -55, 147, 13, + 12, -54, 31, -84, + -17, -75, -228, 83, + -375, 436, 110, -63, + -27, -136, 169, -56, + -8, -171, 184, -42, + 148, 68, 204, 235, + 110, -229, 91, 171, + -43, -3, -26, -99, + -111, 71, -170, 202, + -67, 181, -37, 109, + -120, 3, -55, -260, + -16, 152, 91, 142, + 42, 44, 134, 47, + 17, -35, 22, 79, + -169, 41, 46, 277, + -93, -49, -126, 37, + -103, -34, -22, -90, + -134, -205, 92, -9, + 1, -195, -239, 45, + 54, 18, -23, -1, + -80, -98, -20, -261, + 306, 72, 20, -89, + -217, 11, 6, -82, + 89, 13, -129, -89, + 83, -71, -55, 130, + -98, -146, -27, -57, + 53, 275, 17, 170, + -5, -54, 132, -64, + 72, 160, -125, -168, + 72, 40, 170, 78, + 248, 116, 20, 84, + 31, -34, 190, 38, + 13, -106, 225, 27, + -168, 24, -157, -122, + 165, 11, -161, -213, + -12, -51, -101, 42, + 101, 27, 55, 111, + 75, 71, -96, -1, + 65, -277, 393, -26, + -44, -68, -84, -66, + -95, 235, 179, -25, + -41, 27, -91, -128, + -222, 146, -72, -30, + -24, 55, -126, -68, + -58, -127, 13, -97, + -106, 174, -100, 155, + 101, -146, -21, 261, + 22, 38, -66, 65, + 4, 70, 64, 144, + 59, 213, 71, -337, + 303, -52, 51, -56, + 1, 10, -15, -5, + 34, 52, 228, 131, + 161, -127, -214, 238, + 123, 64, -147, -50, + -34, -127, 204, 162, + 85, 41, 5, -140, + 73, -150, 56, -96, + -66, -20, 2, -235, + 59, -22, -107, 150, + -16, -47, -4, 81, + -67, 167, 149, 149, + -157, 288, -156, -27, + -8, 18, 83, -24, + -41, -167, 158, -100, + 93, 53, 201, 15, + 42, 266, 278, -12, + -6, -37, 85, 6, + 20, -188, -271, 107, + -13, -80, 51, 202, + 173, -69, 78, -188, + 46, 4, 153, 12, + -138, 169, 5, -58, + -123, -108, -243, 150, + 10, -191, 246, -15, + 38, 25, -10, 14, + 61, 50, -206, -215, + -220, 90, 5, -149, + -219, 56, 142, 24, + -376, 77, -80, 75, + 6, 42, -101, 16, + 56, 14, -57, 3, + -17, 80, 57, -36, + 88, -59, -97, -19, + -148, 46, -219, 226, + 114, -4, -72, -15, + 37, -49, -28, 247, + 44, 123, 47, -122, + -38, 17, 4, -113, + -32, -224, 154, -134, + 196, 71, -267, -85, + 28, -70, 89, -120, + 99, -2, 64, 76, + -166, -48, 189, -35, + -92, -169, -123, 339, + 38, -25, 38, -35, + 225, -139, -50, -63, + 246, 60, -185, -109, + -49, -53, -167, 51, + 149, 60, -101, -33, + 25, -76, 120, 32, + -30, -83, 102, 91, + -186, -261, 131, -197 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB0_16_Stage_info[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + { 128, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 128 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 128 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 144 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 144 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 152 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 152 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 160 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 160 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 168 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 168 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 176 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 176 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 184 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 184 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 192 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 192 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 200 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 200 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_16 = +{ + NLSF_MSVQ_CB0_16_STAGES, + SKP_Silk_NLSF_CB0_16_Stage_info, + SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.h new file mode 100755 index 0000000..ef4028d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_NLSF_CB0_16_H +#define SKP_SILK_TABLES_NLSF_CB0_16_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB0_16_STAGES 10 +#define NLSF_MSVQ_CB0_16_VECTORS 216 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ NLSF_MSVQ_CB0_16_VECTORS + NLSF_MSVQ_CB0_16_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr[ NLSF_MSVQ_CB0_16_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx[ NLSF_MSVQ_CB0_16_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16_FLP.c new file mode 100755 index 0000000..6cf71f7 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB0_16_FLP.c @@ -0,0 +1,1925 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 14.76 kB */ +/**********************************************/ + +#include "SKP_Silk_tables_FLP.h" +#include "SKP_Silk_tables_NLSF_CB0_16.h" + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_16_rates[ NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 5.50000000000000000000f, 5.65625000000000000000f, + 5.68750000000000000000f, 5.71875000000000000000f, + 5.81250000000000000000f, 5.81250000000000000000f, + 5.96875000000000000000f, 5.96875000000000000000f, + 5.96875000000000000000f, 6.12500000000000000000f, + 6.15625000000000000000f, 6.28125000000000000000f, + 6.34375000000000000000f, 6.43750000000000000000f, + 6.43750000000000000000f, 6.43750000000000000000f, + 6.46875000000000000000f, 6.46875000000000000000f, + 6.53125000000000000000f, 6.53125000000000000000f, + 6.53125000000000000000f, 6.53125000000000000000f, + 6.56250000000000000000f, 6.56250000000000000000f, + 6.56250000000000000000f, 6.59375000000000000000f, + 6.59375000000000000000f, 6.59375000000000000000f, + 6.62500000000000000000f, 6.68750000000000000000f, + 6.75000000000000000000f, 6.75000000000000000000f, + 6.78125000000000000000f, 6.78125000000000000000f, + 6.78125000000000000000f, 6.78125000000000000000f, + 6.81250000000000000000f, 6.81250000000000000000f, + 6.84375000000000000000f, 6.84375000000000000000f, + 6.87500000000000000000f, 6.90625000000000000000f, + 6.93750000000000000000f, 6.96875000000000000000f, + 6.96875000000000000000f, 6.96875000000000000000f, + 6.96875000000000000000f, 7.00000000000000000000f, + 7.00000000000000000000f, 7.00000000000000000000f, + 7.03125000000000000000f, 7.03125000000000000000f, + 7.06250000000000000000f, 7.06250000000000000000f, + 7.06250000000000000000f, 7.06250000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.12500000000000000000f, 7.12500000000000000000f, + 7.12500000000000000000f, 7.12500000000000000000f, + 7.15625000000000000000f, 7.15625000000000000000f, + 7.15625000000000000000f, 7.18750000000000000000f, + 7.18750000000000000000f, 7.18750000000000000000f, + 7.21875000000000000000f, 7.21875000000000000000f, + 7.21875000000000000000f, 7.21875000000000000000f, + 7.25000000000000000000f, 7.25000000000000000000f, + 7.25000000000000000000f, 7.25000000000000000000f, + 7.28125000000000000000f, 7.31250000000000000000f, + 7.34375000000000000000f, 7.34375000000000000000f, + 7.34375000000000000000f, 7.37500000000000000000f, + 7.37500000000000000000f, 7.37500000000000000000f, + 7.37500000000000000000f, 7.40625000000000000000f, + 7.40625000000000000000f, 7.40625000000000000000f, + 7.40625000000000000000f, 7.50000000000000000000f, + 7.50000000000000000000f, 7.50000000000000000000f, + 7.50000000000000000000f, 7.53125000000000000000f, + 7.56250000000000000000f, 7.59375000000000000000f, + 7.62500000000000000000f, 7.62500000000000000000f, + 7.71875000000000000000f, 7.71875000000000000000f, + 7.75000000000000000000f, 7.75000000000000000000f, + 7.75000000000000000000f, 7.78125000000000000000f, + 7.84375000000000000000f, 7.96875000000000000000f, + 7.96875000000000000000f, 8.00000000000000000000f, + 8.12500000000000000000f, 8.12500000000000000000f, + 8.15625000000000000000f, 8.25000000000000000000f, + 8.25000000000000000000f, 8.31250000000000000000f, + 8.31250000000000000000f, 8.37500000000000000000f, + 8.46875000000000000000f, 8.56250000000000000000f, + 8.62500000000000000000f, 8.71875000000000000000f, + 9.00000000000000000000f, 9.00000000000000000000f, + 9.00000000000000000000f, 9.00000000000000000000f, + 3.68750000000000000000f, 3.75000000000000000000f, + 3.78125000000000000000f, 3.78125000000000000000f, + 3.81250000000000000000f, 3.90625000000000000000f, + 3.90625000000000000000f, 4.03125000000000000000f, + 4.03125000000000000000f, 4.06250000000000000000f, + 4.09375000000000000000f, 4.12500000000000000000f, + 4.25000000000000000000f, 4.28125000000000000000f, + 4.31250000000000000000f, 4.53125000000000000000f, + 2.71875000000000000000f, 2.75000000000000000000f, + 2.84375000000000000000f, 3.03125000000000000000f, + 3.06250000000000000000f, 3.12500000000000000000f, + 3.28125000000000000000f, 3.31250000000000000000f, + 2.87500000000000000000f, 2.96875000000000000000f, + 2.96875000000000000000f, 3.00000000000000000000f, + 3.03125000000000000000f, 3.03125000000000000000f, + 3.06250000000000000000f, 3.09375000000000000000f, + 2.75000000000000000000f, 2.87500000000000000000f, + 2.96875000000000000000f, 2.96875000000000000000f, + 3.00000000000000000000f, 3.03125000000000000000f, + 3.06250000000000000000f, 3.40625000000000000000f, + 2.90625000000000000000f, 2.90625000000000000000f, + 2.90625000000000000000f, 3.00000000000000000000f, + 3.03125000000000000000f, 3.03125000000000000000f, + 3.09375000000000000000f, 3.15625000000000000000f, + 2.90625000000000000000f, 2.93750000000000000000f, + 2.93750000000000000000f, 2.96875000000000000000f, + 2.96875000000000000000f, 3.09375000000000000000f, + 3.09375000000000000000f, 3.09375000000000000000f, + 2.90625000000000000000f, 2.90625000000000000000f, + 2.90625000000000000000f, 3.00000000000000000000f, + 3.00000000000000000000f, 3.03125000000000000000f, + 3.12500000000000000000f, 3.18750000000000000000f, + 2.90625000000000000000f, 2.96875000000000000000f, + 2.96875000000000000000f, 3.00000000000000000000f, + 3.00000000000000000000f, 3.00000000000000000000f, + 3.06250000000000000000f, 3.09375000000000000000f, + 3.90625000000000000000f, 3.90625000000000000000f, + 3.96875000000000000000f, 3.96875000000000000000f, + 3.96875000000000000000f, 3.96875000000000000000f, + 4.00000000000000000000f, 4.00000000000000000000f, + 4.00000000000000000000f, 4.00000000000000000000f, + 4.00000000000000000000f, 4.00000000000000000000f, + 4.03125000000000000000f, 4.06250000000000000000f, + 4.09375000000000000000f, 4.12500000000000000000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min[ 16 + 1 ] = +{ + 0.00811767578125000000f, + 0.00009155273437500000f, + 0.00122070312500000000f, + 0.00009155273437500000f, + 0.00009155273437500000f, + 0.00048828125000000000f, + 0.00238037109375000000f, + 0.00271606445312500000f, + 0.00326538085937500000f, + 0.00430297851562500000f, + 0.00573730468750000000f, + 0.00445556640625000000f, + 0.00830078125000000000f, + 0.00732421874999999910f, + 0.00717163085937500000f, + 0.00656127929687500000f, + 0.01928710937500000000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 0.03570556640625000000f, 0.06951904296875000000f, + 0.11163330078125001000f, 0.16400146484375000000f, + 0.23394775390625000000f, 0.27810668945312500000f, + 0.34478759765624994000f, 0.40600585937500000000f, + 0.46908569335937500000f, 0.53555297851562500000f, + 0.59774780273437500000f, 0.65573120117187500000f, + 0.72625732421875000000f, 0.79461669921875000000f, + 0.86419677734375000000f, 0.92166137695312500000f, + 0.04968261718750000700f, 0.07122802734375000000f, + 0.12557983398437500000f, 0.18420410156250000000f, + 0.23858642578125000000f, 0.29125976562500000000f, + 0.35940551757812500000f, 0.42788696289062500000f, + 0.48178100585937500000f, 0.53125000000000000000f, + 0.59405517578125000000f, 0.64883422851562500000f, + 0.69842529296875000000f, 0.74966430664062500000f, + 0.81524658203125000000f, 0.85629272460937500000f, + 0.05261230468750000000f, 0.08148193359375000000f, + 0.12377929687500000000f, 0.19934082031250000000f, + 0.25503540039062500000f, 0.30880737304687500000f, + 0.36904907226562506000f, 0.42910766601562500000f, + 0.50326538085937500000f, 0.57357788085937500000f, + 0.62307739257812500000f, 0.68365478515625000000f, + 0.74008178710937511000f, 0.80029296875000011000f, + 0.86700439453125000000f, 0.91418457031250000000f, + 0.04556274414062500000f, 0.10458374023437501000f, + 0.14614868164062500000f, 0.19528198242187500000f, + 0.25741577148437500000f, 0.31030273437500000000f, + 0.36621093750000000000f, 0.42926025390625000000f, + 0.49526977539062500000f, 0.55572509765625000000f, + 0.61157226562500000000f, 0.67437744140625000000f, + 0.73709106445312500000f, 0.79635620117187500000f, + 0.86007690429687500000f, 0.91921997070312489000f, + 0.03414916992187500000f, 0.06375122070312500000f, + 0.13107299804687500000f, 0.19058227539062500000f, + 0.26522827148437500000f, 0.32778930664062500000f, + 0.38720703125000000000f, 0.45950317382812500000f, + 0.51965332031250000000f, 0.57348632812500000000f, + 0.63223266601562500000f, 0.68707275390625011000f, + 0.74758911132812500000f, 0.81018066406250000000f, + 0.87338256835937500000f, 0.93475341796875000000f, + 0.04159545898437500000f, 0.07376098632812500000f, + 0.11984252929687500000f, 0.16955566406249997000f, + 0.22650146484375000000f, 0.28427124023437500000f, + 0.36251831054687500000f, 0.42013549804687500000f, + 0.49264526367187500000f, 0.56518554687500000000f, + 0.62432861328125000000f, 0.68902587890625000000f, + 0.74887084960937500000f, 0.80676269531250000000f, + 0.86419677734375000000f, 0.92523193359375000000f, + 0.03424072265625000000f, 0.07638549804687500000f, + 0.15917968750000000000f, 0.21813964843750000000f, + 0.28411865234375000000f, 0.33807373046874994000f, + 0.40206909179687500000f, 0.45166015625000000000f, + 0.51464843750000000000f, 0.57067871093750000000f, + 0.62365722656250000000f, 0.68627929687499989000f, + 0.74987792968750011000f, 0.81182861328125000000f, + 0.87142944335937500000f, 0.92852783203125000000f, + 0.01831054687500000000f, 0.04019165039062500700f, + 0.09063720703125001400f, 0.17117309570312500000f, + 0.23480224609375000000f, 0.29858398437500000000f, + 0.37136840820312500000f, 0.42990112304687506000f, + 0.49984741210937494000f, 0.56085205078125000000f, + 0.62716674804687500000f, 0.69232177734375000000f, + 0.75497436523437489000f, 0.81472778320312500000f, + 0.87420654296875000000f, 0.92636108398437500000f, + 0.02871704101562500000f, 0.05743408203125000000f, + 0.13043212890625000000f, 0.16906738281250000000f, + 0.25885009765625000000f, 0.30084228515625000000f, + 0.36437988281250000000f, 0.43600463867187494000f, + 0.49105834960937506000f, 0.56460571289062500000f, + 0.62030029296875000000f, 0.69006347656250000000f, + 0.75411987304687511000f, 0.81292724609374989000f, + 0.87933349609375000000f, 0.92864990234375000000f, + 0.01937866210937500000f, 0.05184936523437500000f, + 0.13354492187500000000f, 0.18151855468750000000f, + 0.24710083007812500000f, 0.30868530273437500000f, + 0.37457275390625000000f, 0.43267822265625000000f, + 0.49166870117187500000f, 0.54360961914062500000f, + 0.60104370117187500000f, 0.66445922851562511000f, + 0.73019409179687500000f, 0.78936767578124989000f, + 0.85516357421875000000f, 0.91961669921875000000f, + 0.04296874999999999300f, 0.06781005859375000000f, + 0.10754394531250000000f, 0.17135620117187503000f, + 0.22415161132812497000f, 0.27005004882812500000f, + 0.33535766601562500000f, 0.38977050781250000000f, + 0.46850585937500000000f, 0.51959228515625000000f, + 0.57736206054687500000f, 0.64276123046875000000f, + 0.71194458007812500000f, 0.76950073242187500000f, + 0.83035278320312511000f, 0.88571166992187500000f, + 0.02139282226562500000f, 0.03988647460937500000f, + 0.10827636718750001000f, 0.19229125976562500000f, + 0.23632812500000000000f, 0.29217529296875000000f, + 0.34262084960937494000f, 0.39605712890625000000f, + 0.46295166015625000000f, 0.53604125976562500000f, + 0.60348510742187500000f, 0.67434692382812500000f, + 0.73944091796875000000f, 0.80368041992187500000f, + 0.86599731445312500000f, 0.92257690429687500000f, + 0.05346679687500000700f, 0.07214355468750000000f, + 0.14889526367187500000f, 0.20046997070312500000f, + 0.23843383789062500000f, 0.29895019531250000000f, + 0.34176635742187500000f, 0.43609619140625006000f, + 0.48202514648437500000f, 0.54931640625000000000f, + 0.62243652343750000000f, 0.68411254882812489000f, + 0.74182128906250011000f, 0.79724121093750000000f, + 0.86547851562500000000f, 0.93484497070312500000f, + 0.02749633789062500000f, 0.04971313476562500000f, + 0.10241699218749999000f, 0.14144897460937500000f, + 0.22143554687500000000f, 0.26754760742187500000f, + 0.30429077148437500000f, 0.35272216796875000000f, + 0.46432495117187500000f, 0.53540039062500000000f, + 0.59579467773437500000f, 0.66687011718750000000f, + 0.72937011718750000000f, 0.79278564453125000000f, + 0.85855102539062500000f, 0.92114257812500000000f, + 0.02993774414062500000f, 0.05093383789062500000f, + 0.10140991210937499000f, 0.14321899414062500000f, + 0.18960571289062500000f, 0.26525878906250000000f, + 0.32391357421875006000f, 0.39538574218750000000f, + 0.46420288085937506000f, 0.54049682617187500000f, + 0.60595703125000000000f, 0.67510986328124989000f, + 0.74291992187500000000f, 0.81152343750000000000f, + 0.87655639648437500000f, 0.93020629882812500000f, + 0.04904174804687500000f, 0.07864379882812500000f, + 0.12878417968750000000f, 0.16821289062499997000f, + 0.26037597656250000000f, 0.31701660156250000000f, + 0.35482788085937500000f, 0.41720581054687494000f, + 0.48071289062500000000f, 0.52487182617187500000f, + 0.60546875000000000000f, 0.66708374023437500000f, + 0.71697998046875000000f, 0.78692626953125000000f, + 0.85726928710937500000f, 0.91952514648437500000f, + 0.02474975585937500000f, 0.04489135742187500000f, + 0.09594726562500000000f, 0.15383911132812500000f, + 0.22674560546875000000f, 0.28652954101562500000f, + 0.34100341796875000000f, 0.40451049804687500000f, + 0.46255493164062494000f, 0.51089477539062500000f, + 0.59762573242187500000f, 0.67648315429687500000f, + 0.73593139648437511000f, 0.79779052734375000000f, + 0.86618041992187500000f, 0.92758178710937500000f, + 0.04708862304687499300f, 0.06542968750000000000f, + 0.11074829101562500000f, 0.19369506835937500000f, + 0.22378540039062503000f, 0.28500366210937500000f, + 0.32684326171875000000f, 0.41491699218750006000f, + 0.46078491210937506000f, 0.52917480468750000000f, + 0.61346435546875000000f, 0.66790771484375000000f, + 0.72424316406250000000f, 0.78237915039062500000f, + 0.84893798828125000000f, 0.91299438476562511000f, + 0.01501464843750000000f, 0.03616333007812500000f, + 0.08972167968750000000f, 0.16748046875000003000f, + 0.21652221679687500000f, 0.26705932617187500000f, + 0.35388183593749994000f, 0.41439819335937500000f, + 0.48965454101562500000f, 0.54977416992187500000f, + 0.61578369140625000000f, 0.67526245117187500000f, + 0.74050903320312489000f, 0.80584716796875000000f, + 0.86926269531250000000f, 0.92642211914062500000f, + 0.04721069335937500000f, 0.06964111328125000000f, + 0.11270141601562500000f, 0.19351196289062500000f, + 0.23675537109374997000f, 0.29318237304687500000f, + 0.36157226562500000000f, 0.40393066406250000000f, + 0.50549316406250000000f, 0.55142211914062500000f, + 0.60299682617187500000f, 0.65319824218750011000f, + 0.73577880859375000000f, 0.81195068359375000000f, + 0.87847900390625000000f, 0.93551635742187511000f, + 0.02090454101562500000f, 0.04083251953125000000f, + 0.10403442382812500000f, 0.16058349609375000000f, + 0.21209716796875000000f, 0.28143310546875000000f, + 0.34832763671875000000f, 0.44320678710937500000f, + 0.49856567382812500000f, 0.54605102539062500000f, + 0.59313964843750000000f, 0.64996337890625000000f, + 0.71084594726562500000f, 0.76846313476562500000f, + 0.85366821289062500000f, 0.93139648437500000000f, + 0.02706909179687500300f, 0.04824829101562500000f, + 0.09329223632812500000f, 0.13177490234375000000f, + 0.21948242187500000000f, 0.26296997070312500000f, + 0.30661010742187500000f, 0.39996337890625000000f, + 0.49636840820312500000f, 0.54605102539062500000f, + 0.61746215820312500000f, 0.68206787109375000000f, + 0.74398803710937511000f, 0.80517578125000000000f, + 0.86407470703125000000f, 0.92129516601562489000f, + 0.06973266601562500000f, 0.11428833007812500000f, + 0.17279052734375000000f, 0.23120117187500000000f, + 0.28451538085937500000f, 0.34545898437500000000f, + 0.40402221679687500000f, 0.46359252929687494000f, + 0.52413940429687500000f, 0.58670043945312500000f, + 0.64416503906250000000f, 0.70104980468750000000f, + 0.75747680664062500000f, 0.81344604492187489000f, + 0.87161254882812500000f, 0.92956542968750000000f, + 0.04565429687500000700f, 0.06433105468750000000f, + 0.10522460937500000000f, 0.21051025390625003000f, + 0.25415039062500000000f, 0.29467773437500000000f, + 0.34338378906250000000f, 0.39132690429687500000f, + 0.45712280273437500000f, 0.50299072265625000000f, + 0.55480957031250000000f, 0.61294555664062500000f, + 0.70074462890624989000f, 0.76782226562500000000f, + 0.84548950195312500000f, 0.90420532226562500000f, + 0.01754760742187500000f, 0.03848266601562500000f, + 0.11782836914062500000f, 0.20223999023437500000f, + 0.25311279296875000000f, 0.32986450195312500000f, + 0.38772583007812500000f, 0.45068359375000000000f, + 0.52111816406250000000f, 0.58126831054687500000f, + 0.64019775390624989000f, 0.70358276367187500000f, + 0.76208496093750011000f, 0.81491088867187500000f, + 0.87646484375000000000f, 0.92605590820312500000f, + 0.05133056640625000000f, 0.06753540039062500000f, + 0.11846923828125000000f, 0.19036865234374997000f, + 0.21997070312500000000f, 0.29437255859375000000f, + 0.33193969726562500000f, 0.40988159179687500000f, + 0.45181274414062494000f, 0.49478149414062506000f, + 0.54751586914062500000f, 0.63699340820312489000f, + 0.71868896484375011000f, 0.78628540039062500000f, + 0.84704589843750000000f, 0.89907836914062500000f, + 0.02709960937500000000f, 0.04931640625000000000f, + 0.11975097656250000000f, 0.15853881835937500000f, + 0.21990966796875003000f, 0.26388549804687500000f, + 0.30035400390625000000f, 0.35012817382812500000f, + 0.49032592773437500000f, 0.55606079101562500000f, + 0.62081909179687500000f, 0.69500732421875000000f, + 0.74777221679687500000f, 0.80603027343750000000f, + 0.85614013671875000000f, 0.90731811523437500000f, + 0.02456665039062500000f, 0.04437255859375000000f, + 0.08187866210937500000f, 0.13647460937500000000f, + 0.24218750000000000000f, 0.28564453125000000000f, + 0.34783935546875000000f, 0.43777465820312500000f, + 0.49453735351562500000f, 0.54418945312500000000f, + 0.59365844726562500000f, 0.66058349609375000000f, + 0.72933959960937489000f, 0.79125976562500000000f, + 0.86630249023437511000f, 0.92965698242187500000f, + 0.05004882812500000000f, 0.07272338867187500000f, + 0.10632324218750000000f, 0.15509033203125000000f, + 0.18408203125000000000f, 0.26263427734375000000f, + 0.35522460937499994000f, 0.39569091796875000000f, + 0.48345947265625000000f, 0.53002929687500000000f, + 0.59039306640625000000f, 0.64642333984375000000f, + 0.72137451171875011000f, 0.79006958007812511000f, + 0.86572265625000000000f, 0.92465209960937500000f, + 0.04980468750000000000f, 0.06726074218750000000f, + 0.13763427734375000000f, 0.23132324218750003000f, + 0.26605224609375000000f, 0.32080078125000000000f, + 0.36505126953125000000f, 0.43017578125000000000f, + 0.47729492187500000000f, 0.52471923828125000000f, + 0.58419799804687500000f, 0.67892456054687511000f, + 0.74960327148437489000f, 0.81057739257812500000f, + 0.87292480468750000000f, 0.93106079101562500000f, + 0.06234741210937500000f, 0.07971191406250001400f, + 0.12161254882812500000f, 0.20907592773437500000f, + 0.24530029296875000000f, 0.29034423828125000000f, + 0.33505249023437500000f, 0.39028930664062500000f, + 0.47076416015625000000f, 0.51049804687500000000f, + 0.57675170898437500000f, 0.61880493164062500000f, + 0.69891357421875000000f, 0.79983520507812500000f, + 0.87619018554687500000f, 0.93438720703125011000f, + 0.06787109375000000000f, 0.08538818359375000000f, + 0.13626098632812500000f, 0.16235351562500000000f, + 0.21691894531249997000f, 0.28796386718750000000f, + 0.33526611328125000000f, 0.40350341796875000000f, + 0.44552612304687500000f, 0.55899047851562500000f, + 0.61465454101562500000f, 0.66659545898437500000f, + 0.72024536132812511000f, 0.78430175781250000000f, + 0.86010742187500000000f, 0.93328857421875000000f, + 0.02548217773437500000f, 0.04702758789062500000f, + 0.12460327148437500000f, 0.17605590820312503000f, + 0.22540283203125000000f, 0.28683471679687500000f, + 0.33480834960937500000f, 0.38012695312500000000f, + 0.45840454101562500000f, 0.56890869140625000000f, + 0.63607788085937500000f, 0.70495605468750000000f, + 0.77185058593750000000f, 0.82293701171875000000f, + 0.88354492187500000000f, 0.92840576171875011000f, + 0.05477905273437500000f, 0.07150268554687500000f, + 0.14675903320312500000f, 0.17993164062500003000f, + 0.21905517578125000000f, 0.26077270507812500000f, + 0.31198120117187500000f, 0.40802001953125000000f, + 0.44573974609375000000f, 0.50259399414062500000f, + 0.55764770507812500000f, 0.63281250000000000000f, + 0.72158813476562500000f, 0.80130004882812500000f, + 0.86132812500000000000f, 0.92742919921875000000f, + 0.05291748046875000000f, 0.06878662109375000000f, + 0.12301635742187500000f, 0.15832519531250000000f, + 0.19854736328125000000f, 0.24023437500000000000f, + 0.29452514648437500000f, 0.39749145507812500000f, + 0.44003295898437494000f, 0.52810668945312500000f, + 0.59494018554687500000f, 0.67718505859374989000f, + 0.74472045898437500000f, 0.80267333984375000000f, + 0.86044311523437500000f, 0.92092895507812500000f, + 0.05618286132812500000f, 0.07168579101562500000f, + 0.12109375000000000000f, 0.14538574218750000000f, + 0.19458007812500000000f, 0.29983520507812500000f, + 0.33715820312500000000f, 0.40725708007812500000f, + 0.44805908203125000000f, 0.49597167968750000000f, + 0.55490112304687500000f, 0.65194702148437500000f, + 0.72991943359375000000f, 0.79821777343750000000f, + 0.85543823242187500000f, 0.91354370117187500000f, + 0.04370117187500000000f, 0.06246948242187500000f, + 0.17184448242187500000f, 0.21139526367187500000f, + 0.25018310546875000000f, 0.29525756835937500000f, + 0.34661865234375000000f, 0.41217041015625000000f, + 0.45172119140625000000f, 0.50106811523437500000f, + 0.55966186523437500000f, 0.67196655273437500000f, + 0.73620605468750000000f, 0.79885864257812500000f, + 0.85845947265625000000f, 0.93341064453125000000f, + 0.05279541015625000700f, 0.07080078125000000000f, + 0.11425781250000000000f, 0.14672851562500000000f, + 0.18331909179687500000f, 0.29498291015625000000f, + 0.33560180664062500000f, 0.41571044921875000000f, + 0.46490478515625000000f, 0.53390502929687500000f, + 0.61303710937500000000f, 0.67144775390625000000f, + 0.72030639648437500000f, 0.77514648437500000000f, + 0.83554077148437489000f, 0.89276123046875000000f, + 0.03866577148437500000f, 0.05844116210937500000f, + 0.16732788085937503000f, 0.20788574218750000000f, + 0.25112915039062500000f, 0.30270385742187500000f, + 0.35366821289062494000f, 0.40701293945312500000f, + 0.45004272460937506000f, 0.54824829101562500000f, + 0.62719726562500000000f, 0.67648315429687500000f, + 0.74826049804687500000f, 0.81845092773437500000f, + 0.88143920898437500000f, 0.93511962890625000000f, + 0.04656982421875000000f, 0.06802368164062500000f, + 0.12939453125000000000f, 0.22546386718750000000f, + 0.27322387695312500000f, 0.31890869140625000000f, + 0.36312866210937500000f, 0.41864013671875006000f, + 0.51455688476562500000f, 0.55917358398437500000f, + 0.62191772460937500000f, 0.69189453125000000000f, + 0.75674438476562500000f, 0.82110595703125000000f, + 0.88214111328124989000f, 0.93450927734375000000f, + 0.06637573242187500000f, 0.08517456054687500000f, + 0.12524414062500000000f, 0.20980834960937500000f, + 0.26281738281250000000f, 0.29901123046875000000f, + 0.37084960937500000000f, 0.41308593750000000000f, + 0.47677612304687500000f, 0.53961181640625000000f, + 0.58633422851562500000f, 0.64270019531250000000f, + 0.74407958984375000000f, 0.81665039062499989000f, + 0.87380981445312500000f, 0.92309570312500000000f, + 0.01385498046875000000f, 0.03756713867187500000f, + 0.13241577148437500000f, 0.17510986328125000000f, + 0.23040771484375000000f, 0.27484130859375000000f, + 0.31494140625000000000f, 0.41275024414062506000f, + 0.48843383789062500000f, 0.54470825195312500000f, + 0.61251831054687500000f, 0.67114257812500000000f, + 0.73086547851562500000f, 0.79476928710937500000f, + 0.86196899414062511000f, 0.92086791992187489000f, + 0.06866455078125000000f, 0.08517456054687500000f, + 0.12908935546875000000f, 0.16122436523437500000f, + 0.20635986328125000000f, 0.32369995117187506000f, + 0.36251831054687500000f, 0.42178344726562500000f, + 0.48208618164062494000f, 0.52685546875000000000f, + 0.61123657226562500000f, 0.67950439453125000000f, + 0.75036621093750000000f, 0.80679321289062500000f, + 0.86193847656250000000f, 0.92831420898437489000f, + 0.05175781250000000000f, 0.06762695312500000000f, + 0.13146972656250000000f, 0.25588989257812500000f, + 0.29803466796875000000f, 0.33660888671875000000f, + 0.38317871093750000000f, 0.43026733398437500000f, + 0.49810791015625000000f, 0.53833007812500000000f, + 0.58489990234375000000f, 0.62835693359375000000f, + 0.73141479492187489000f, 0.81964111328125000000f, + 0.87884521484375000000f, 0.93267822265625000000f, + 0.07482910156250000000f, 0.09875488281250000000f, + 0.13333129882812500000f, 0.18670654296875000000f, + 0.21838378906250000000f, 0.27474975585937500000f, + 0.35122680664062500000f, 0.39050292968750000000f, + 0.48062133789062506000f, 0.52767944335937500000f, + 0.59481811523437500000f, 0.67874145507812500000f, + 0.74859619140625000000f, 0.80792236328125000000f, + 0.86282348632812489000f, 0.91775512695312511000f, + 0.05526733398437500000f, 0.07754516601562500000f, + 0.10848999023437500000f, 0.16723632812500000000f, + 0.27841186523437500000f, 0.32125854492187500000f, + 0.36297607421875000000f, 0.41683959960937500000f, + 0.46575927734374994000f, 0.51571655273437500000f, + 0.59100341796875000000f, 0.64297485351562511000f, + 0.69256591796875000000f, 0.74200439453125000000f, + 0.83178710937500000000f, 0.91500854492187500000f, + 0.04739379882812500000f, 0.06854248046875000000f, + 0.13912963867187500000f, 0.16784667968749997000f, + 0.20611572265625003000f, 0.24029541015625000000f, + 0.35824584960937500000f, 0.41415405273437500000f, + 0.46350097656250000000f, 0.54562377929687500000f, + 0.61892700195312500000f, 0.68695068359375000000f, + 0.75115966796875000000f, 0.81326293945312500000f, + 0.87847900390625000000f, 0.93856811523437500000f, + 0.06048583984375000000f, 0.08447265625000000000f, + 0.11700439453125001000f, 0.18200683593750000000f, + 0.26647949218750000000f, 0.30236816406250000000f, + 0.36001586914062500000f, 0.45205688476562500000f, + 0.49777221679687506000f, 0.54766845703125000000f, + 0.64382934570312500000f, 0.69735717773437500000f, + 0.74633789062500000000f, 0.80273437500000000000f, + 0.85955810546875000000f, 0.90805053710937511000f, + 0.05566406250000000000f, 0.07717895507812500000f, + 0.11648559570312500000f, 0.16629028320312500000f, + 0.20916748046875003000f, 0.26593017578125000000f, + 0.31680297851562500000f, 0.37493896484375006000f, + 0.43316650390625000000f, 0.48138427734375000000f, + 0.59582519531250000000f, 0.65228271484375000000f, + 0.72311401367187500000f, 0.79556274414062500000f, + 0.85742187500000000000f, 0.92199707031250011000f, + 0.06750488281250000000f, 0.08709716796875001400f, + 0.12045288085937500000f, 0.17999267578125000000f, + 0.30303955078125000000f, 0.35266113281250000000f, + 0.39227294921875000000f, 0.45129394531249994000f, + 0.49829101562500006000f, 0.54016113281250000000f, + 0.62014770507812500000f, 0.67437744140625000000f, + 0.72241210937500011000f, 0.77182006835937500000f, + 0.82324218750000011000f, 0.87237548828125000000f, + 0.06173706054687500000f, 0.07931518554687500000f, + 0.12280273437500000000f, 0.15002441406250000000f, + 0.20181274414062500000f, 0.34024047851562494000f, + 0.38015747070312500000f, 0.44635009765625000000f, + 0.49804687500000000000f, 0.54388427734375000000f, + 0.60037231445312500000f, 0.64611816406250000000f, + 0.70541381835937500000f, 0.79501342773437500000f, + 0.87966918945312500000f, 0.93865966796875000000f, + 0.04968261718750000700f, 0.06732177734375000000f, + 0.10580444335937500000f, 0.13317871093750000000f, + 0.26486206054687500000f, 0.31045532226562500000f, + 0.36206054687500000000f, 0.41744995117187500000f, + 0.45770263671874994000f, 0.51690673828125000000f, + 0.58615112304687500000f, 0.65197753906249989000f, + 0.72784423828125000000f, 0.79696655273437500000f, + 0.85827636718750000000f, 0.92385864257812500000f, + 0.06146240234375000000f, 0.07943725585937500000f, + 0.12554931640625000000f, 0.22137451171875000000f, + 0.25988769531250000000f, 0.30648803710937500000f, + 0.36077880859375000000f, 0.41207885742187500000f, + 0.49832153320312500000f, 0.54400634765625000000f, + 0.60110473632812500000f, 0.64941406250000000000f, + 0.70651245117187500000f, 0.75259399414062500000f, + 0.81808471679687500000f, 0.92044067382812511000f, + 0.07250976562500000000f, 0.09094238281250000000f, + 0.13494873046875000000f, 0.17608642578125000000f, + 0.21411132812500000000f, 0.29672241210937500000f, + 0.33950805664062506000f, 0.41247558593750000000f, + 0.47256469726562506000f, 0.51834106445312500000f, + 0.58471679687500000000f, 0.62826538085937500000f, + 0.74465942382812500000f, 0.82946777343750000000f, + 0.88641357421875000000f, 0.93527221679687500000f, + 0.07489013671875000000f, 0.10687255859375000000f, + 0.14111328125000000000f, 0.18368530273437500000f, + 0.23291015625000000000f, 0.27005004882812500000f, + 0.32934570312500000000f, 0.42614746093750000000f, + 0.47372436523437500000f, 0.52139282226562500000f, + 0.59848022460937500000f, 0.64813232421875000000f, + 0.69750976562500000000f, 0.76623535156249989000f, + 0.85772705078125011000f, 0.91217041015625000000f, + 0.04800415039062500700f, 0.06939697265625000000f, + 0.10095214843750000000f, 0.18307495117187500000f, + 0.27395629882812500000f, 0.30834960937500000000f, + 0.38015747070312500000f, 0.43511962890625000000f, + 0.48062133789062506000f, 0.55480957031250000000f, + 0.60955810546875000000f, 0.64859008789062500000f, + 0.70327758789062500000f, 0.76470947265625000000f, + 0.84658813476562500000f, 0.92514038085937500000f, + 0.05929565429687500000f, 0.08331298828125000000f, + 0.12634277343750000000f, 0.18798828125000003000f, + 0.22860717773437500000f, 0.27423095703125000000f, + 0.34512329101562500000f, 0.38986206054687500000f, + 0.45227050781250000000f, 0.50531005859375000000f, + 0.54653930664062500000f, 0.60293579101562500000f, + 0.65649414062500011000f, 0.72036743164062500000f, + 0.83233642578124989000f, 0.90109252929687500000f, + 0.06167602539062500000f, 0.07879638671875000000f, + 0.13714599609375000000f, 0.17807006835937503000f, + 0.21340942382812497000f, 0.25161743164062500000f, + 0.29989624023437500000f, 0.44961547851562500000f, + 0.50238037109375000000f, 0.54608154296875000000f, + 0.59957885742187500000f, 0.64340209960937489000f, + 0.72521972656250000000f, 0.81381225585937500000f, + 0.88720703125000000000f, 0.94573974609375000000f, + 0.03210449218750000000f, 0.05416870117187500000f, + 0.09820556640624998600f, 0.13360595703125000000f, + 0.23394775390625000000f, 0.28695678710937500000f, + 0.34326171875000000000f, 0.40670776367187500000f, + 0.45690917968750000000f, 0.54815673828125000000f, + 0.63348388671875000000f, 0.68218994140625000000f, + 0.76510620117187500000f, 0.83035278320312511000f, + 0.88504028320312500000f, 0.93411254882812489000f, + 0.06768798828125000000f, 0.08746337890624998600f, + 0.12887573242187500000f, 0.16333007812500000000f, + 0.20083618164062500000f, 0.30456542968750000000f, + 0.35360717773437500000f, 0.40042114257812500000f, + 0.46365356445312500000f, 0.50607299804687500000f, + 0.56109619140625000000f, 0.61279296875000000000f, + 0.67178344726562500000f, 0.77261352539062500000f, + 0.85836791992187500000f, 0.91186523437500011000f, + 0.06549072265625000000f, 0.08666992187500000000f, + 0.13418579101562500000f, 0.17822265625000000000f, + 0.22732543945312500000f, 0.26614379882812500000f, + 0.32080078125000000000f, 0.36425781250000000000f, + 0.41488647460937500000f, 0.52651977539062500000f, + 0.58929443359375000000f, 0.63754272460937500000f, + 0.71463012695312500000f, 0.78207397460937500000f, + 0.84683227539062500000f, 0.92257690429687500000f, + 0.06018066406250000000f, 0.07992553710937500000f, + 0.11462402343750000000f, 0.19430541992187500000f, + 0.23318481445312503000f, 0.26898193359375000000f, + 0.37493896484375006000f, 0.42016601562500000000f, + 0.46719360351562506000f, 0.55041503906250000000f, + 0.59683227539062500000f, 0.63793945312500000000f, + 0.68914794921875011000f, 0.75915527343750000000f, + 0.84838867187500000000f, 0.92895507812500000000f, + 0.06118774414062500000f, 0.07864379882812500000f, + 0.13037109375000000000f, 0.22500610351562500000f, + 0.26116943359375000000f, 0.31198120117187500000f, + 0.35919189453125000000f, 0.40899658203125000000f, + 0.50360107421875000000f, 0.54931640625000000000f, + 0.59951782226562500000f, 0.64404296875000000000f, + 0.70159912109375000000f, 0.81805419921875000000f, + 0.90042114257812489000f, 0.94427490234375000000f, + 0.03518676757812500000f, 0.05560302734375000000f, + 0.11364746093750001000f, 0.16610717773437500000f, + 0.21331787109375000000f, 0.26556396484375000000f, + 0.31399536132812500000f, 0.36312866210937500000f, + 0.42285156250000000000f, 0.46737670898437500000f, + 0.53713989257812500000f, 0.64282226562500000000f, + 0.72302246093750011000f, 0.79598999023437500000f, + 0.87237548828125000000f, 0.93502807617187500000f, + 0.03979492187500000000f, 0.05703735351562500000f, + 0.10125732421875000000f, 0.21957397460937500000f, + 0.29336547851562500000f, 0.32754516601562500000f, + 0.37820434570312500000f, 0.41894531250000000000f, + 0.48284912109375000000f, 0.53326416015625000000f, + 0.57623291015625000000f, 0.63146972656250000000f, + 0.70538330078125000000f, 0.77941894531250000000f, + 0.84484863281250000000f, 0.89245605468750011000f, + 0.06387329101562500000f, 0.08212280273437500000f, + 0.12261962890625000000f, 0.20318603515625000000f, + 0.24252319335937500000f, 0.27914428710937500000f, + 0.32034301757812500000f, 0.36257934570312500000f, + 0.48486328125000006000f, 0.54385375976562500000f, + 0.58999633789062500000f, 0.64797973632812500000f, + 0.71322631835937489000f, 0.77008056640625000000f, + 0.84085083007812500000f, 0.91546630859375000000f, + 0.01754760742187500000f, 0.04061889648437499300f, + 0.16186523437500000000f, 0.21087646484374997000f, + 0.25711059570312500000f, 0.30780029296875000000f, + 0.35330200195312500000f, 0.41192626953125006000f, + 0.50183105468750000000f, 0.56539916992187500000f, + 0.62759399414062500000f, 0.69723510742187500000f, + 0.76031494140625000000f, 0.81457519531249989000f, + 0.87765502929687500000f, 0.92031860351562500000f, + 0.04379272460937500000f, 0.06176757812500000000f, + 0.10018920898437500000f, 0.12683105468750000000f, + 0.23226928710937500000f, 0.32324218750000000000f, + 0.36770629882812506000f, 0.42501831054687500000f, + 0.47177124023437500000f, 0.56192016601562500000f, + 0.62545776367187500000f, 0.67962646484375000000f, + 0.73919677734375000000f, 0.79629516601562489000f, + 0.85647583007812500000f, 0.91854858398437500000f, + 0.04980468750000000000f, 0.06616210937500000000f, + 0.16906738281250000000f, 0.22821044921875000000f, + 0.26336669921875000000f, 0.31710815429687500000f, + 0.35534667968750000000f, 0.43704223632812494000f, + 0.48037719726562500000f, 0.52969360351562500000f, + 0.57238769531250000000f, 0.62359619140625000000f, + 0.69577026367187500000f, 0.79528808593750000000f, + 0.87103271484375000000f, 0.93676757812500000000f, + 0.04293823242187500000f, 0.06851196289062500000f, + 0.10391235351562501000f, 0.17208862304687500000f, + 0.28744506835937500000f, 0.32608032226562506000f, + 0.36938476562500000000f, 0.41183471679687494000f, + 0.47409057617187500000f, 0.56021118164062500000f, + 0.61022949218750000000f, 0.66189575195312500000f, + 0.74313354492187500000f, 0.81024169921874989000f, + 0.88052368164062500000f, 0.93273925781250011000f, + 0.05111694335937500700f, 0.06793212890625000000f, + 0.12222290039062501000f, 0.25094604492187500000f, + 0.30441284179687500000f, 0.34042358398437500000f, + 0.39129638671875000000f, 0.43688964843750000000f, + 0.50366210937500000000f, 0.55349731445312500000f, + 0.59735107421875000000f, 0.64239501953125000000f, + 0.69454956054687500000f, 0.76025390625000000000f, + 0.86352539062500011000f, 0.93487548828125000000f, + 0.03295898437500000000f, 0.04925537109375000000f, + 0.11053466796875000000f, 0.23086547851562497000f, + 0.26696777343750000000f, 0.31442260742187500000f, + 0.35745239257812500000f, 0.42260742187500000000f, + 0.47708129882812500000f, 0.53204345703125000000f, + 0.60305786132812500000f, 0.66604614257812500000f, + 0.71932983398437500000f, 0.77493286132812500000f, + 0.83636474609375000000f, 0.88693237304687500000f, + 0.05166625976562500000f, 0.06802368164062500000f, + 0.10546875000000000000f, 0.13287353515625000000f, + 0.17303466796875000000f, 0.33233642578125000000f, + 0.38339233398437500000f, 0.43234252929687500000f, + 0.48458862304687500000f, 0.53030395507812500000f, + 0.60476684570312500000f, 0.67050170898437500000f, + 0.73529052734375000000f, 0.79745483398437500000f, + 0.86358642578125000000f, 0.91854858398437500000f, + 0.06231689453125000000f, 0.09030151367187501400f, + 0.12802124023437500000f, 0.17517089843750000000f, + 0.21685791015625000000f, 0.25228881835937500000f, + 0.33953857421875000000f, 0.45693969726562500000f, + 0.51617431640625000000f, 0.55831909179687500000f, + 0.62658691406250000000f, 0.67083740234375000000f, + 0.72360229492187500000f, 0.78640747070312500000f, + 0.84255981445312511000f, 0.89572143554687500000f, + 0.03002929687500000000f, 0.04919433593750000000f, + 0.11621093750000000000f, 0.16067504882812500000f, + 0.21011352539062500000f, 0.25668334960937500000f, + 0.29135131835937500000f, 0.33230590820312500000f, + 0.38214111328125000000f, 0.50415039062500000000f, + 0.59658813476562500000f, 0.66036987304687500000f, + 0.72467041015625011000f, 0.79522705078125000000f, + 0.86395263671874989000f, 0.92694091796875011000f, + 0.06213378906250000000f, 0.07745361328125000000f, + 0.12713623046875000000f, 0.23684692382812500000f, + 0.27911376953125000000f, 0.31774902343750000000f, + 0.37060546875000006000f, 0.41531372070312500000f, + 0.47570800781250000000f, 0.52395629882812500000f, + 0.56637573242187500000f, 0.61380004882812500000f, + 0.66589355468750000000f, 0.74197387695312500000f, + 0.85537719726562489000f, 0.93420410156249989000f, + 0.05709838867187500000f, 0.07186889648437500000f, + 0.12393188476562500000f, 0.15695190429687500000f, + 0.22778320312500000000f, 0.30911254882812500000f, + 0.36441040039062506000f, 0.45779418945312506000f, + 0.50903320312500000000f, 0.56011962890625000000f, + 0.60903930664062500000f, 0.67990112304687500000f, + 0.75869750976562489000f, 0.82006835937500000000f, + 0.88464355468750000000f, 0.93429565429687511000f, + 0.07830810546875000000f, 0.09646606445312500000f, + 0.14169311523437500000f, 0.19003295898437500000f, + 0.22601318359375000000f, 0.30426025390625000000f, + 0.35455322265625000000f, 0.40942382812500000000f, + 0.48489379882812500000f, 0.52990722656250000000f, + 0.58352661132812500000f, 0.63528442382812500000f, + 0.68945312500000000000f, 0.75439453125000000000f, + 0.87686157226562489000f, 0.94854736328125000000f, + 0.05187988281249999300f, 0.07101440429687500000f, + 0.14733886718750000000f, 0.18124389648437500000f, + 0.23092651367187500000f, 0.27935791015625000000f, + 0.33834838867187500000f, 0.38973999023437500000f, + 0.43362426757812506000f, 0.49197387695312500000f, + 0.61712646484375000000f, 0.69186401367187500000f, + 0.75219726562500000000f, 0.81347656250000000000f, + 0.87573242187499989000f, 0.93826293945312500000f, + 0.09671020507812500000f, 0.11819458007812501000f, + 0.15399169921875000000f, 0.20959472656250000000f, + 0.24975585937500000000f, 0.28930664062500000000f, + 0.37643432617187500000f, 0.42932128906250000000f, + 0.48138427734375000000f, 0.54843139648437500000f, + 0.61740112304687500000f, 0.66256713867187500000f, + 0.71777343750000000000f, 0.77041625976562500000f, + 0.82476806640625000000f, 0.87677001953124989000f, + 0.04772949218750000000f, 0.07296752929687500000f, + 0.12905883789062500000f, 0.20538330078125000000f, + 0.27175903320312500000f, 0.31918334960937500000f, + 0.39752197265625000000f, 0.45877075195312500000f, + 0.52688598632812500000f, 0.60452270507812500000f, + 0.66677856445312500000f, 0.72451782226562500000f, + 0.77789306640625000000f, 0.83349609375000000000f, + 0.88687133789062500000f, 0.93161010742187511000f, + 0.08740234375000000000f, 0.10861206054687501000f, + 0.14401245117187500000f, 0.19656372070312503000f, + 0.29272460937500000000f, 0.33737182617187500000f, + 0.38949584960937500000f, 0.45117187500000000000f, + 0.50134277343750000000f, 0.55432128906250000000f, + 0.62518310546875000000f, 0.67938232421875000000f, + 0.73800659179687511000f, 0.80148315429687500000f, + 0.86618041992187500000f, 0.92236328125000000000f, + 0.08157348632812498600f, 0.10525512695312501000f, + 0.13980102539062500000f, 0.18258666992187500000f, + 0.20944213867187500000f, 0.25363159179687500000f, + 0.38037109375000000000f, 0.42453002929687506000f, + 0.48028564453125000000f, 0.54293823242187500000f, + 0.59252929687500000000f, 0.64642333984375000000f, + 0.73318481445312500000f, 0.81057739257812500000f, + 0.87655639648437500000f, 0.92895507812500000000f, + 0.07382202148437500000f, 0.09304809570312500000f, + 0.13043212890625000000f, 0.19482421875000000000f, + 0.26135253906250000000f, 0.29483032226562500000f, + 0.34448242187499994000f, 0.38684082031250000000f, + 0.44088745117187500000f, 0.53643798828125000000f, + 0.60473632812500000000f, 0.64791870117187511000f, + 0.70492553710937500000f, 0.77117919921874989000f, + 0.82089233398437500000f, 0.88275146484374989000f, + 0.03900146484375000000f, 0.06106567382812500000f, + 0.09155273437500000000f, 0.16336059570312500000f, + 0.30502319335937500000f, 0.35940551757812500000f, + 0.39727783203125000000f, 0.44464111328125000000f, + 0.48980712890625000000f, 0.54205322265625000000f, + 0.60980224609375000000f, 0.65969848632812511000f, + 0.71322631835937489000f, 0.76547241210937500000f, + 0.84399414062500000000f, 0.92077636718749989000f, + 0.02844238281250000000f, 0.04956054687500000000f, + 0.08538818359375000000f, 0.13946533203125000000f, + 0.26220703125000000000f, 0.30480957031250000000f, + 0.35253906249999994000f, 0.39825439453125000000f, + 0.51638793945312500000f, 0.56997680664062500000f, + 0.62301635742187500000f, 0.69610595703125000000f, + 0.75735473632812500000f, 0.81845092773437500000f, + 0.87902832031250011000f, 0.92727661132812489000f, + 0.07092285156250000000f, 0.09072875976562500000f, + 0.12683105468750000000f, 0.17401123046875000000f, + 0.21115112304687500000f, 0.26873779296875000000f, + 0.31307983398437500000f, 0.38156127929687494000f, + 0.45822143554687494000f, 0.50558471679687500000f, + 0.59259033203125000000f, 0.65231323242187500000f, + 0.70016479492187500000f, 0.74920654296875000000f, + 0.82470703124999989000f, 0.91091918945312500000f, + 0.04772949218750000000f, 0.07241821289062500000f, + 0.10543823242187499000f, 0.14974975585937500000f, + 0.18234252929687500000f, 0.22692871093750000000f, + 0.35968017578125000000f, 0.44265747070312500000f, + 0.49154663085937500000f, 0.55383300781250000000f, + 0.61093139648437500000f, 0.66079711914062500000f, + 0.72448730468749989000f, 0.78778076171875000000f, + 0.87213134765625000000f, 0.92687988281250000000f, + 0.09231567382812501400f, 0.11380004882812500000f, + 0.14849853515625000000f, 0.19897460937500000000f, + 0.28952026367187500000f, 0.33395385742187500000f, + 0.37713623046875000000f, 0.43511962890625000000f, + 0.49359130859375000000f, 0.53408813476562500000f, + 0.59436035156250000000f, 0.65332031250000000000f, + 0.70883178710937500000f, 0.76007080078125000000f, + 0.83456420898437500000f, 0.89743041992187500000f, + 0.03875732421875000000f, 0.05996704101562500000f, + 0.20758056640625000000f, 0.24398803710937500000f, + 0.28088378906250000000f, 0.33044433593750000000f, + 0.38168334960937500000f, 0.43426513671875000000f, + 0.48092651367187500000f, 0.54504394531250000000f, + 0.62161254882812500000f, 0.68670654296875000000f, + 0.75173950195312500000f, 0.80914306640625000000f, + 0.87081909179687500000f, 0.93154907226562500000f, + 0.06744384765625000000f, 0.08389282226562500000f, + 0.13018798828125000000f, 0.22848510742187503000f, + 0.30145263671875000000f, 0.33624267578125000000f, + 0.39132690429687500000f, 0.44039916992187500000f, + 0.49581909179687494000f, 0.56842041015625000000f, + 0.62408447265625000000f, 0.67303466796875011000f, + 0.72445678710937500000f, 0.77182006835937500000f, + 0.82623291015625000000f, 0.89016723632812500000f, + 0.03890991210937500000f, 0.05877685546875000000f, + 0.13214111328125000000f, 0.20059204101562503000f, + 0.25759887695312500000f, 0.33325195312500000000f, + 0.40466308593750000000f, 0.45800781249999994000f, + 0.51657104492187500000f, 0.56680297851562500000f, + 0.63000488281250000000f, 0.67800903320312500000f, + 0.73190307617187500000f, 0.77740478515625000000f, + 0.83532714843750000000f, 0.87417602539062489000f, + 0.09201049804687500000f, 0.11199951171875000000f, + 0.15521240234375000000f, 0.19445800781250000000f, + 0.24072265625000000000f, 0.28408813476562500000f, + 0.33465576171875006000f, 0.38580322265624994000f, + 0.44235229492187500000f, 0.49353027343750000000f, + 0.55175781250000000000f, 0.60949707031250000000f, + 0.68524169921874989000f, 0.75985717773437500000f, + 0.83502197265624989000f, 0.91476440429687500000f, + 0.08795166015625001400f, 0.11392211914062500000f, + 0.15603637695312500000f, 0.19781494140625000000f, + 0.24795532226562503000f, 0.29556274414062500000f, + 0.35394287109375000000f, 0.40551757812500006000f, + 0.47012329101562500000f, 0.52465820312500000000f, + 0.61578369140625000000f, 0.68438720703125011000f, + 0.75686645507812500000f, 0.82440185546875000000f, + 0.89147949218750000000f, 0.94027709960937511000f, + 0.07019042968750000000f, 0.09057617187500000000f, + 0.12515258789062500000f, 0.16607666015625000000f, + 0.19308471679687500000f, 0.24139404296875000000f, + 0.38009643554687500000f, 0.42303466796875000000f, + 0.48056030273437500000f, 0.53421020507812500000f, + 0.58145141601562500000f, 0.63107299804687500000f, + 0.69015502929687500000f, 0.75250244140625000000f, + 0.83920288085937500000f, 0.91751098632812500000f, + 0.06887817382812500000f, 0.08972167968750000000f, + 0.13519287109375000000f, 0.18283081054687497000f, + 0.21490478515624997000f, 0.25524902343750000000f, + 0.28729248046875000000f, 0.34252929687500000000f, + 0.47982788085937500000f, 0.53161621093750000000f, + 0.58755493164062500000f, 0.65518188476562489000f, + 0.72982788085937500000f, 0.79507446289062500000f, + 0.86761474609375000000f, 0.92724609375000000000f, + 0.03744506835937500000f, 0.06240844726562500000f, + 0.11651611328124999000f, 0.15292358398437500000f, + 0.21331787109375000000f, 0.28170776367187500000f, + 0.33642578124999994000f, 0.39706420898437494000f, + 0.52920532226562500000f, 0.58035278320312500000f, + 0.62814331054687500000f, 0.69577026367187500000f, + 0.76889038085937500000f, 0.82019042968750000000f, + 0.89572143554687500000f, 0.94009399414062489000f, + 0.04132080078125000000f, 0.05871582031250000000f, + 0.11563110351562500000f, 0.24649047851562500000f, + 0.31900024414062500000f, 0.35519409179687500000f, + 0.40747070312500000000f, 0.45217895507812500000f, + 0.51095581054687500000f, 0.55508422851562500000f, + 0.61325073242187500000f, 0.67181396484374989000f, + 0.75051879882812500000f, 0.81411743164062500000f, + 0.87423706054687500000f, 0.92333984375000000000f, + 0.09588623046875000000f, 0.12356567382812501000f, + 0.18911743164062500000f, 0.22634887695312500000f, + 0.26712036132812500000f, 0.30993652343750000000f, + 0.35195922851562500000f, 0.40225219726562500000f, + 0.48666381835937500000f, 0.53878784179687500000f, + 0.59832763671875000000f, 0.65313720703125000000f, + 0.71676635742187500000f, 0.78305053710937511000f, + 0.85824584960937511000f, 0.92480468750000000000f, + 0.04019165039062500700f, 0.06906127929687500000f, + 0.14419555664062500000f, 0.23226928710937500000f, + 0.29501342773437500000f, 0.35504150390625000000f, + 0.43161010742187500000f, 0.49615478515625000000f, + 0.57141113281250000000f, 0.63165283203125000000f, + 0.68295288085937500000f, 0.73263549804687511000f, + 0.78659057617187489000f, 0.83163452148437500000f, + 0.88287353515625000000f, 0.93362426757812500000f, + 0.04791259765625000000f, 0.07089233398437500000f, + 0.11651611328124999000f, 0.18966674804687500000f, + 0.30191040039062500000f, 0.35266113281250000000f, + 0.39886474609375000000f, 0.44650268554687500000f, + 0.49291992187500006000f, 0.55816650390625000000f, + 0.65264892578125000000f, 0.71246337890625000000f, + 0.76641845703125011000f, 0.82162475585937500000f, + 0.87622070312500000000f, 0.92065429687500000000f, + 0.07009887695312500000f, 0.11917114257812500000f, + 0.19186401367187503000f, 0.26116943359375000000f, + 0.32556152343750006000f, 0.38958740234375000000f, + 0.45834350585937500000f, 0.52191162109375000000f, + 0.58093261718750000000f, 0.63101196289062500000f, + 0.68179321289062500000f, 0.72848510742187500000f, + 0.77752685546875000000f, 0.82656860351562500000f, + 0.88046264648437500000f, 0.93139648437500000000f, + 0.05844116210937500000f, 0.07650756835937500000f, + 0.12307739257812499000f, 0.17544555664062500000f, + 0.21542358398437497000f, 0.27072143554687500000f, + 0.32528686523437500000f, 0.37225341796875006000f, + 0.42532348632812500000f, 0.46945190429687500000f, + 0.51480102539062500000f, 0.57089233398437500000f, + 0.70724487304687489000f, 0.78790283203125011000f, + 0.87017822265625000000f, 0.93081665039062500000f, + 0.07336425781250000000f, 0.08905029296875000000f, + 0.15838623046875000000f, 0.19079589843750000000f, + 0.22662353515625003000f, 0.30172729492187500000f, + 0.37802124023437500000f, 0.45150756835937494000f, + 0.51129150390625000000f, 0.56054687500000000000f, + 0.62066650390625000000f, 0.67147827148437511000f, + 0.73962402343750000000f, 0.80737304687500000000f, + 0.86944580078125000000f, 0.92764282226562500000f, + 0.04946899414062500000f, 0.06796264648437500000f, + 0.10617065429687500000f, 0.15518188476562500000f, + 0.28762817382812500000f, 0.39343261718750006000f, + 0.43475341796875006000f, 0.47766113281250000000f, + 0.52505493164062500000f, 0.56988525390625000000f, + 0.62396240234375000000f, 0.67776489257812500000f, + 0.72564697265625000000f, 0.78939819335937500000f, + 0.85238647460937500000f, 0.91836547851562500000f, + 0.05703735351562500000f, 0.07293701171875000000f, + 0.12527465820312500000f, 0.21426391601562500000f, + 0.34243774414062500000f, 0.38986206054687500000f, + 0.42904663085937500000f, 0.47576904296875006000f, + 0.51953125000000000000f, 0.56787109375000000000f, + 0.62850952148437500000f, 0.67367553710937500000f, + 0.72171020507812489000f, 0.76763916015625000000f, + 0.82135009765625000000f, 0.87496948242187500000f, + 0.07785034179687500000f, 0.09924316406250000000f, + 0.14306640625000000000f, 0.20025634765625000000f, + 0.24014282226562500000f, 0.27847290039062500000f, + 0.31967163085937506000f, 0.36010742187500000000f, + 0.47003173828125000000f, 0.57312011718750000000f, + 0.64062500000000000000f, 0.68832397460937500000f, + 0.74124145507812500000f, 0.79248046874999989000f, + 0.83816528320312500000f, 0.89208984375000000000f, + 0.08255004882812500000f, 0.10659790039062501000f, + 0.14450073242187500000f, 0.19409179687500000000f, + 0.24124145507812503000f, 0.28540039062500000000f, + 0.35211181640625006000f, 0.40985107421875000000f, + 0.46505737304687500000f, 0.51632690429687500000f, + 0.56820678710937500000f, 0.61322021484375000000f, + 0.66528320312500000000f, 0.71234130859375000000f, + 0.76904296875000000000f, 0.89285278320312500000f, + 0.06610107421875000000f, 0.08517456054687500000f, + 0.12240600585937499000f, 0.15505981445312500000f, + 0.17993164062500003000f, 0.27581787109375000000f, + 0.40914916992187494000f, 0.44869995117187506000f, + 0.50485229492187500000f, 0.55508422851562500000f, + 0.60717773437500000000f, 0.66702270507812500000f, + 0.75903320312500000000f, 0.82308959960937500000f, + 0.88363647460937500000f, 0.93121337890625000000f, + 0.05691528320312499300f, 0.09219360351562500000f, + 0.14331054687500000000f, 0.19940185546875003000f, + 0.25460815429687500000f, 0.30255126953125000000f, + 0.39028930664062500000f, 0.43038940429687500000f, + 0.50454711914062500000f, 0.54104614257812500000f, + 0.65124511718750000000f, 0.68478393554687500000f, + 0.75906372070312500000f, 0.80352783203125000000f, + 0.86755371093750000000f, 0.92022705078125000000f, + 0.10281372070312500000f, 0.13259887695312500000f, + 0.20059204101562503000f, 0.26742553710937500000f, + 0.31460571289062500000f, 0.35745239257812500000f, + 0.40792846679687500000f, 0.45117187500000000000f, + 0.50302124023437500000f, 0.55374145507812500000f, + 0.60543823242187500000f, 0.64840698242187500000f, + 0.71081542968750000000f, 0.77749633789062489000f, + 0.84091186523437489000f, 0.89865112304687500000f, + 0.03860473632812500000f, 0.06665039062500000000f, + 0.16610717773437500000f, 0.24087524414062500000f, + 0.32321166992187500000f, 0.40097045898437506000f, + 0.46096801757812500000f, 0.50778198242187500000f, + 0.56158447265625000000f, 0.60504150390625000000f, + 0.65365600585937500000f, 0.70175170898437500000f, + 0.75436401367187500000f, 0.80679321289062500000f, + 0.86557006835937500000f, 0.91934204101562500000f, + 0.04833984375000000700f, 0.06115722656250000000f, + 0.10787963867187500000f, 0.13580322265625000000f, + 0.26434326171875000000f, 0.32849121093750000000f, + 0.39160156250000000000f, 0.45709228515625000000f, + 0.51794433593750000000f, 0.57354736328125000000f, + 0.63879394531250000000f, 0.68807983398437500000f, + 0.75183105468750000000f, 0.80935668945312500000f, + 0.87588500976562500000f, 0.93283081054687511000f, + 0.10433959960937500000f, 0.13818359375000000000f, + 0.20147705078124997000f, 0.24078369140624997000f, + 0.29016113281250000000f, 0.33187866210937494000f, + 0.38973999023437500000f, 0.43814086914062500000f, + 0.48983764648437500000f, 0.55938720703125000000f, + 0.62957763671875000000f, 0.68634033203125000000f, + 0.76507568359375000000f, 0.82202148437499989000f, + 0.88336181640625011000f, 0.93206787109375000000f, + 0.05267333984375000000f, 0.06872558593750000000f, + 0.14028930664062500000f, 0.21209716796875000000f, + 0.25570678710937500000f, 0.29977416992187500000f, + 0.34677124023437500000f, 0.39044189453125006000f, + 0.43658447265625000000f, 0.47229003906250000000f, + 0.51263427734375000000f, 0.54986572265625000000f, + 0.66134643554687511000f, 0.77972412109375000000f, + 0.85900878906249989000f, 0.92672729492187500000f, + 0.10330200195312500000f, 0.11810302734375000000f, + 0.16195678710937503000f, 0.19494628906250000000f, + 0.21792602539062500000f, 0.26501464843750000000f, + 0.38742065429687500000f, 0.45590209960937500000f, + 0.50292968750000000000f, 0.55776977539062500000f, + 0.62673950195312500000f, 0.67285156249999989000f, + 0.73080444335937489000f, 0.79238891601562500000f, + 0.86102294921875000000f, 0.91418457031250000000f, + 0.08456420898437500000f, 0.10089111328124999000f, + 0.13580322265625000000f, 0.16967773437500000000f, + 0.19692993164062497000f, 0.28970336914062500000f, + 0.41345214843750000000f, 0.45025634765625006000f, + 0.51095581054687500000f, 0.56295776367187500000f, + 0.61120605468750000000f, 0.66333007812499989000f, + 0.72467041015625011000f, 0.77371215820312500000f, + 0.82827758789062500000f, 0.88702392578125000000f, + 0.09240722656250000000f, 0.11901855468750001000f, + 0.20193481445312503000f, 0.24087524414062500000f, + 0.28109741210937500000f, 0.31982421875000000000f, + 0.36764526367187500000f, 0.41452026367187494000f, + 0.46331787109375000000f, 0.50848388671875000000f, + 0.56463623046875000000f, 0.61315917968750000000f, + 0.67718505859374989000f, 0.74334716796875000000f, + 0.80267333984375000000f, 0.88369750976562489000f, + 0.06103515624999999300f, 0.07781982421875000000f, + 0.12411499023437500000f, 0.20864868164062503000f, + 0.29382324218750000000f, 0.33575439453125000000f, + 0.38433837890625006000f, 0.43023681640625000000f, + 0.47573852539062500000f, 0.52474975585937500000f, + 0.57003784179687500000f, 0.61337280273437500000f, + 0.65704345703125000000f, 0.70449829101562500000f, + 0.75198364257812500000f, 0.88568115234375000000f, + 0.08679199218749998600f, 0.10076904296875000000f, + 0.15573120117187500000f, 0.18637084960937500000f, + 0.21090698242187500000f, 0.26239013671875000000f, + 0.37890625000000000000f, 0.42889404296875000000f, + 0.48907470703125000000f, 0.56661987304687500000f, + 0.63085937500000000000f, 0.67962646484375000000f, + 0.73095703125000000000f, 0.78646850585937500000f, + 0.84405517578125000000f, 0.91632080078125000000f, + 0.12338256835937500000f, 0.15716552734375000000f, + 0.22180175781250000000f, 0.27636718750000000000f, + 0.33312988281250000000f, 0.38568115234375006000f, + 0.44381713867187500000f, 0.49389648437500000000f, + 0.54772949218750000000f, 0.60092163085937500000f, + 0.65176391601562500000f, 0.70132446289062500000f, + 0.75759887695312500000f, 0.81149291992187500000f, + 0.86911010742187500000f, 0.92263793945312500000f, + 0.06436157226562500000f, 0.08010864257812500000f, + 0.13183593750000000000f, 0.16860961914062500000f, + 0.22747802734375000000f, 0.31188964843750000000f, + 0.39611816406250006000f, 0.44854736328125000000f, + 0.53793334960937500000f, 0.58786010742187500000f, + 0.62515258789062500000f, 0.68301391601562500000f, + 0.74093627929687500000f, 0.78665161132812500000f, + 0.84982299804687500000f, 0.92950439453125000000f, + 0.04730224609375000000f, 0.08139038085937501400f, + 0.19754028320312500000f, 0.28979492187500000000f, + 0.33523559570312500000f, 0.37695312500000000000f, + 0.42098999023437500000f, 0.46487426757812500000f, + 0.52182006835937500000f, 0.56890869140625000000f, + 0.62442016601562500000f, 0.67492675781250000000f, + 0.73843383789062489000f, 0.80233764648437500000f, + 0.86679077148437500000f, 0.91955566406250000000f, + 0.07357788085937500000f, 0.09411621093750000000f, + 0.12649536132812500000f, 0.16461181640625000000f, + 0.19430541992187500000f, 0.24884033203124997000f, + 0.40054321289062500000f, 0.48977661132812500000f, + 0.53591918945312500000f, 0.58364868164062500000f, + 0.64874267578125000000f, 0.69464111328125000000f, + 0.74642944335937500000f, 0.80313110351562500000f, + 0.86227416992187500000f, 0.90643310546875000000f, + 0.12692260742187500000f, 0.13781738281250000000f, + 0.18176269531250000000f, 0.23300170898437500000f, + 0.25189208984375000000f, 0.27404785156250000000f, + 0.34204101562500000000f, 0.43130493164062500000f, + 0.49468994140624994000f, 0.54550170898437500000f, + 0.61633300781250000000f, 0.66723632812500011000f, + 0.72753906250000000000f, 0.78573608398437511000f, + 0.85626220703125000000f, 0.91589355468750000000f, + 0.06182861328125000000f, 0.07418823242187500000f, + 0.08682250976562500000f, 0.11041259765625000000f, + 0.24261474609375000000f, 0.29913330078125000000f, + 0.38821411132812500000f, 0.44128417968750000000f, + 0.50585937500000000000f, 0.57934570312500000000f, + 0.65234375000000000000f, 0.71163940429687500000f, + 0.76174926757812500000f, 0.81536865234375000000f, + 0.88412475585937500000f, 0.93505859375000000000f, + 0.10464477539062500000f, 0.11697387695312500000f, + 0.13647460937500000000f, 0.14990234375000000000f, + 0.23568725585937500000f, 0.31695556640625000000f, + 0.39614868164062500000f, 0.46759033203125000000f, + 0.50961303710937500000f, 0.57394409179687500000f, + 0.63409423828125000000f, 0.68820190429687511000f, + 0.75155639648437500000f, 0.80853271484375000000f, + 0.86468505859375000000f, 0.93023681640625000000f, + 0.14465332031250000000f, 0.15774536132812500000f, + 0.17687988281250003000f, 0.19790649414062503000f, + 0.21356201171874997000f, 0.26947021484375000000f, + 0.35940551757812500000f, 0.43988037109375000000f, + 0.51364135742187500000f, 0.56192016601562500000f, + 0.63442993164062500000f, 0.68264770507812489000f, + 0.73962402343750000000f, 0.78842163085937511000f, + 0.84860229492187500000f, 0.91616821289062500000f, + 0.00457763671875000000f, 0.00512695312500000000f, + -0.00051879882812500000f, -0.00326538085937500000f, + -0.00433349609375000000f, -0.00698852539062499910f, + -0.00976562500000000000f, -0.01239013671875000000f, + -0.01535034179687500000f, -0.01892089843750000000f, + -0.02645874023437500000f, -0.02853393554687500000f, + -0.02752685546875000000f, -0.02075195312500000000f, + -0.01214599609375000000f, -0.00347900390625000000f, + -0.01214599609375000000f, -0.01083374023437500000f, + 0.00149536132812500000f, 0.00778198242187500000f, + 0.00347900390625000000f, 0.00793457031250000000f, + 0.01217651367187500000f, 0.00805664062500000000f, + 0.00967407226562500000f, 0.01315307617187500000f, + 0.01568603515625000000f, 0.01620483398437500000f, + 0.01327514648437500000f, 0.01086425781250000000f, + 0.00726318359375000000f, 0.00323486328125000000f, + -0.00131225585937500000f, -0.00109863281250000000f, + -0.00515747070312500000f, -0.00683593750000000000f, + -0.01193237304687500000f, -0.01931762695312500000f, + -0.02368164062500000000f, -0.02960205078125000000f, + -0.02575683593750000000f, -0.01388549804687500000f, + -0.00552368164062500000f, -0.00036621093750000000f, + 0.00259399414062500000f, 0.00259399414062500000f, + 0.00500488281250000000f, 0.00595092773437500000f, + 0.00372314453125000000f, 0.00259399414062500000f, + -0.00482177734375000000f, -0.01953125000000000000f, + -0.02755737304687500000f, 0.00027465820312500000f, + 0.00021362304687500000f, -0.00378417968750000000f, + 0.00454711914062500000f, 0.00097656250000000000f, + 0.00671386718750000000f, 0.01126098632812500000f, + 0.00738525390625000000f, 0.00350952148437500040f, + 0.00241088867187500000f, 0.00256347656250000000f, + -0.00445556640625000000f, -0.00659179687500000000f, + -0.00213623046875000000f, 0.03125000000000000000f, + 0.02291870117187500000f, 0.01751708984375000000f, + 0.01342773437500000000f, 0.01150512695312500000f, + 0.01074218749999999800f, 0.00619506835937500000f, + 0.00091552734374999989f, 0.00048828125000000000f, + -0.00009155273437500000f, 0.00247192382812500000f, + 0.00491333007812500000f, 0.00305175781250000000f, + -0.00451660156250000000f, -0.00537109374999999910f, + 0.02847290039062500000f, 0.02288818359375000000f, + 0.01232910156250000000f, 0.00521850585937500000f, + -0.00006103515625000000f, -0.00445556640625000000f, + -0.01254272460937500000f, -0.01348876953125000000f, + -0.01651000976562500000f, -0.01684570312500000000f, + -0.01348876953125000000f, -0.00820922851562500000f, + -0.00732421874999999910f, -0.00158691406250000020f, + 0.01840209960937500000f, 0.01937866210937500000f, + 0.01235961914062499800f, 0.00543212890625000000f, + 0.00656127929687500000f, 0.00057983398437500000f, + -0.00466918945312500000f, -0.00509643554687500000f, + -0.00885009765625000000f, -0.00668334960937500090f, + 0.00460815429687500000f, 0.00827026367187500000f, + 0.00460815429687500000f, 0.00363159179687500000f, + 0.00924682617187500000f, 0.00811767578125000000f, + 0.00305175781250000000f, 0.00210571289062500000f, + -0.00894165039062500000f, -0.02005004882812500000f, + 0.02865600585937500000f, 0.02011108398437500000f, + 0.01348876953125000000f, 0.01071166992187500000f, + 0.00402832031250000000f, 0.00299072265625000000f, + -0.00048828125000000000f, -0.00003051757812500000f, + -0.00411987304687500000f, -0.00610351562500000000f, + -0.00680541992187500000f, -0.00271606445312500000f, + 0.00509643554687500000f, 0.00469970703125000000f, + 0.00524902343750000000f, 0.00723266601562500000f, + -0.00137329101562500000f, -0.00558471679687500000f, + -0.00695800781250000000f, -0.01483154296875000000f, + 0.00802612304687500000f, 0.01855468750000000000f, + 0.00482177734375000000f, -0.00381469726562499960f, + -0.01190185546875000000f, -0.00692749023437500000f, + -0.00360107421875000000f, 0.00131225585937500000f, + -0.01394653320312500000f, -0.01196289062500000000f, + -0.02346801757812500000f, -0.02563476562500000000f, + 0.00061035156250000000f, -0.00357055664062500000f, + -0.00592041015625000000f, -0.00576782226562500000f, + -0.00527954101562500000f, -0.00527954101562500000f, + -0.00100708007812500000f, 0.00097656250000000000f, + 0.00531005859375000000f, 0.00439453125000000000f, + 0.00350952148437500040f, 0.00509643554687500000f, + 0.00173950195312500000f, 0.00134277343749999980f, + 0.00042724609375000000f, 0.00448608398437500000f, + 0.00292968750000000000f, -0.00164794921875000000f, + -0.00433349609375000000f, -0.00393676757812500000f, + -0.00775146484375000000f, -0.01010131835937500000f, + 0.00927734375000000000f, 0.00946044921875000000f, + -0.00158691406250000020f, -0.01278686523437500000f, + -0.02581787109375000000f, -0.03234863281250000000f, + -0.00268554687499999960f, -0.00375366210937500000f, + -0.00616455078125000000f, -0.01046752929687500200f, + -0.01690673828125000000f, -0.02932739257812500000f, + -0.02902221679687500000f, 0.00997924804687500000f, + 0.00485229492187500000f, 0.00247192382812500000f, + 0.00778198242187500000f, 0.00692749023437500000f, + 0.00366210937499999960f, 0.00619506835937500000f, + 0.00781250000000000000f, 0.00585937500000000000f, + 0.00500488281250000000f, 0.00683593750000000000f, + 0.00885009765625000000f, 0.00595092773437500000f, + 0.00659179687500000000f, 0.00637817382812500090f, + 0.00390625000000000000f, 0.02539062500000000300f, + 0.03137207031250000000f, 0.02713012695312500000f, + 0.02130126953125000000f, 0.01538085937500000000f, + 0.01245117187500000000f, 0.01083374023437500000f, + 0.00665283203124999910f, 0.00097656250000000000f, + -0.00350952148437500040f, -0.00256347656250000000f, + -0.00842285156250000000f, -0.00305175781250000000f, + -0.00952148437500000000f, -0.01477050781250000000f, + 0.02743530273437500000f, 0.02081298828124999700f, + 0.01419067382812500000f, 0.01391601562500000000f, + 0.00735473632812500090f, -0.00036621093750000000f, + -0.00839233398437500000f, -0.01296997070312499800f, + -0.01406860351562500000f, -0.01119995117187500000f, + -0.00100708007812500000f, -0.00085449218750000000f, + -0.00311279296875000000f, -0.00592041015625000000f, + -0.01608276367187500000f, 0.02633666992187500000f, + 0.02764892578125000000f, 0.01412963867187500000f, + 0.00747680664062500000f, 0.00039672851562500005f, + -0.00646972656250000000f, -0.00930786132812500000f, + -0.00320434570312500000f, 0.00497436523437500000f, + 0.00851440429687500000f, 0.00537109374999999910f, + 0.00283813476562499960f, 0.00204467773437500000f, + 0.00350952148437500040f, 0.00585937500000000000f, + 0.00186157226562500000f, -0.00152587890625000000f, + -0.00402832031250000000f, -0.00534057617187499910f, + -0.00683593750000000000f, -0.00827026367187500000f, + -0.01919555664062500000f, -0.00769042968750000000f, + 0.03533935546875000000f, 0.02966308593750000000f, + 0.01947021484375000000f, 0.00854492187500000000f, + 0.00915527343750000000f, 0.00994873046875000000f, + 0.00436401367187500000f, -0.00463867187500000000f, + -0.00653076171875000000f, -0.00875854492187500000f, + 0.00161743164062500000f, -0.00128173828125000000f, + -0.00720214843750000000f, -0.01074218749999999800f, + -0.01290893554687500000f, -0.00756835937500000000f, + -0.00393676757812500000f, -0.00497436523437500000f, + -0.00543212890625000000f, -0.00363159179687500000f, + 0.00259399414062500000f, 0.00173950195312500000f, + 0.01568603515625000000f, 0.01165771484375000000f, + 0.01141357421875000200f, 0.01226806640625000000f, + 0.01293945312500000000f, 0.01290893554687500000f, + 0.00827026367187500000f, 0.00601196289062499910f, + 0.00296020507812500000f, 0.00122070312500000000f, + 0.00119018554687500000f, -0.00296020507812500000f, + -0.00582885742187500000f, -0.00500488281250000000f, + -0.00701904296875000090f, -0.00781250000000000000f, + -0.01251220703125000000f, 0.01208496093750000200f, + 0.00997924804687500000f, 0.00387573242187500000f, + 0.00030517578125000000f, -0.00363159179687500000f, + -0.00509643554687500000f, -0.00888061523437500000f, + -0.00836181640625000000f, -0.00430297851562500000f, + -0.00302124023437500040f, -0.00689697265625000000f, + -0.00665283203124999910f, -0.00424194335937500000f, + -0.00683593750000000000f, -0.00637817382812500090f, + -0.00817871093750000000f, -0.01348876953125000000f, + -0.01260375976562500000f, 0.00677490234375000000f, + 0.00177001953125000000f, 0.01589965820312500000f, + 0.01049804687500000000f, 0.00787353515625000000f, + 0.00231933593750000000f, -0.00128173828125000000f, + -0.00433349609375000000f, -0.00503540039062499910f, + -0.00375366210937500000f, -0.00280761718750000000f, + 0.00143432617187500000f, 0.00024414062500000000f, + -0.00009155273437500000f, -0.00582885742187500000f, + -0.00033569335937499995f, -0.00500488281250000000f, + -0.00509643554687500000f, -0.01071166992187500000f, + -0.02258300781250000000f, 0.00949096679687500000f, + 0.01641845703125000000f, 0.00888061523437500000f, + 0.00561523437500000000f, 0.00088500976562500000f, + -0.00320434570312500000f, 0.00027465820312500000f, + -0.00091552734374999989f, -0.00164794921875000000f, + -0.00051879882812500000f, -0.00234985351562500000f, + -0.00827026367187500000f, -0.01257324218750000000f, + -0.01898193359375000000f, -0.01977539062500000000f, + 0.01452636718750000000f, 0.00567626953124999910f, + -0.00201416015625000000f, -0.00601196289062499910f, + -0.00222778320312500000f, -0.00286865234375000000f, + -0.00045776367187499995f, 0.00143432617187500000f, + 0.00085449218750000000f, 0.00341796875000000000f, + -0.00177001953125000000f, -0.00100708007812500000f, + 0.00198364257812500000f, 0.00057983398437500000f, + 0.00256347656250000000f, 0.00262451171875000000f, + 0.00842285156250000000f, 0.00347900390625000000f, + 0.01440429687500000000f, 0.02398681640625000000f, + 0.02438354492187499700f, 0.01907348632812500000f, + 0.01266479492187500000f, 0.00543212890625000000f, + -0.00106811523437500000f, -0.00079345703125000011f, + 0.00015258789062500000f, 0.00027465820312500000f, + 0.00253295898437500040f, 0.00119018554687500000f, + 0.00112915039062500000f, 0.00119018554687500000f, + -0.00561523437500000000f, -0.01141357421875000200f, + -0.00808715820312500000f, -0.01104736328125000000f, + -0.01528930664062500000f, 0.01028442382812500000f, + 0.02185058593750000000f, 0.01458740234374999800f, + -0.00183105468749999980f, -0.00381469726562499960f, + -0.00497436523437500000f, 0.01104736328125000000f, + 0.00051879882812500000f, -0.00372314453125000000f, + -0.00711059570312500000f, 0.00851440429687500000f, + 0.00421142578125000000f, 0.00479125976562500000f, + 0.00970458984375000000f, 0.00588989257812500000f, + 0.00576782226562500000f, 0.00637817382812500090f, + 0.00811767578125000000f, 0.00769042968750000000f, + -0.00140380859375000000f, -0.00170898437500000000f, + -0.00845336914062500000f, -0.01309204101562500000f, + 0.01416015625000000000f, 0.01177978515625000000f, + 0.00433349609375000000f, 0.00134277343749999980f, + -0.00131225585937500000f, 0.00201416015625000000f, + 0.00805664062500000000f, 0.00555419921875000000f, + 0.00143432617187500000f, 0.00042724609375000000f, + -0.00079345703125000011f, -0.00241088867187500000f, + 0.00149536132812500000f, 0.00045776367187499995f, + -0.00390625000000000000f, -0.00619506835937500000f, + -0.01220703125000000000f, -0.01458740234374999800f, + 0.00991821289062500000f, 0.00082397460937500000f, + 0.00714111328125000000f, 0.01254272460937500000f, + 0.00625610351562500000f, 0.00393676757812500000f, + 0.00036621093750000000f, 0.00177001953125000000f, + 0.00375366210937500000f, 0.00173950195312500000f, + 0.00521850585937500000f, 0.00418090820312500000f, + 0.00292968750000000000f, 0.00390625000000000000f, + -0.00097656250000000000f, 0.00408935546875000000f, + -0.00036621093750000000f, 0.00173950195312500000f, + 0.00363159179687500000f, 0.00079345703125000011f, + -0.00067138671874999989f, -0.00503540039062499910f, + -0.01525878906249999800f, -0.02139282226562500000f, + -0.01611328125000000000f, -0.00354003906250000000f, + 0.00195312500000000000f, -0.00024414062500000000f, + 0.00296020507812500000f, -0.00027465820312500000f, + -0.00494384765625000000f, -0.00201416015625000000f, + -0.00476074218750000000f, -0.00592041015625000000f, + -0.00924682617187500000f, -0.01666259765625000000f, + -0.01040649414062499800f, 0.01666259765625000000f, + 0.01092529296875000000f, 0.00289916992187500000f, + 0.00137329101562500000f, 0.00231933593750000000f, + 0.00823974609375000000f, 0.01229858398437500000f, + 0.00625610351562500000f, 0.00305175781250000000f, + 0.00375366210937500000f, 0.00152587890625000000f, + -0.00161743164062500000f, -0.00439453125000000000f, + -0.00335693359375000000f, -0.00039672851562500005f, + 0.00097656250000000000f, -0.00695800781250000000f, + -0.00396728515625000000f, 0.01077270507812500000f, + 0.00903320312500000000f, 0.00170898437500000000f, + -0.01135253906249999800f, -0.00772094726562500000f, + 0.01113891601562500000f, 0.00222778320312500000f, + 0.00030517578125000000f, -0.00103759765625000000f, + -0.00424194335937500000f, -0.00582885742187500000f, + -0.00292968750000000000f, 0.00015258789062500000f, + 0.00134277343749999980f, -0.00259399414062500000f, + -0.00546264648437500000f, -0.00393676757812500000f, + -0.00585937500000000000f, -0.00750732421875000000f, + -0.00259399414062500000f, -0.00335693359375000000f, + -0.00473022460937500000f, -0.00134277343749999980f, + -0.00082397460937500000f, 0.00442504882812500000f, + 0.00421142578125000000f, 0.00241088867187500000f, + 0.00097656250000000000f, -0.00451660156250000000f, + -0.01760864257812500000f, -0.01934814453125000000f, + 0.00582885742187500000f, 0.00286865234375000000f, + -0.00027465820312500000f, -0.00106811523437500000f, + -0.00234985351562500000f, -0.00256347656250000000f, + -0.00170898437500000000f, -0.00521850585937500000f, + -0.00909423828125000000f, -0.00827026367187500000f, + -0.00741577148437500000f, -0.00476074218750000000f, + -0.01000976562500000000f, -0.00717163085937500000f, + -0.00231933593750000000f, -0.00390625000000000000f, + -0.00369262695312500000f, 0.00393676757812500000f, + 0.00039672851562500005f, -0.00067138671874999989f, + 0.00097656250000000000f, 0.00137329101562500000f, + -0.00756835937500000000f, -0.00198364257812500000f, + 0.00588989257812500000f, -0.00247192382812500000f, + 0.00912475585937500000f, 0.00173950195312500000f, + -0.00448608398437500000f, 0.00585937500000000000f, + -0.00503540039062499910f, -0.01080322265625000200f, + -0.01019287109375000000f, -0.00323486328125000000f, + -0.00476074218750000000f, -0.00122070312500000000f, + -0.00009155273437500000f, -0.00207519531250000000f, + 0.00378417968750000000f, -0.00784301757812500000f, + 0.00238037109375000000f, 0.00378417968750000000f, + 0.00518798828125000000f, 0.01257324218750000000f, + 0.00692749023437500000f, 0.00320434570312500000f, + -0.00317382812500000040f, 0.00036621093750000000f, + 0.00469970703125000000f, 0.00762939453124999910f, + 0.00836181640625000000f, 0.00787353515625000000f, + 0.00012207031250000000f, -0.00082397460937500000f, + 0.00717163085937500000f, 0.00463867187500000000f, + 0.00155639648437500000f, 0.01031494140625000000f, + 0.00915527343750000000f, 0.00021362304687500000f, + -0.00958251953125000000f, -0.01254272460937500000f, + 0.00656127929687500000f, 0.00518798828125000000f, + -0.00027465820312500000f, -0.00283813476562499960f, + -0.00234985351562500000f, 0.00231933593750000000f, + 0.00204467773437500000f, 0.00164794921875000000f, + 0.00610351562500000000f, 0.00961303710937500000f, + 0.00497436523437500000f, 0.00219726562500000000f, + -0.00277709960937500000f, -0.01226806640625000000f, + 0.00482177734375000000f, 0.00570678710937500090f, + -0.00476074218750000000f, -0.00277709960937500000f, + 0.00885009765625000000f, 0.00814819335937500000f, + 0.00509643554687500000f, 0.00277709960937500000f, + 0.00427246093750000000f, 0.00521850585937500000f, + 0.00341796875000000000f, 0.00027465820312500000f, + -0.00128173828125000000f, -0.00540161132812500090f, + -0.01342773437500000000f, 0.01174926757812500200f, + 0.00244140625000000000f, 0.00045776367187499995f, + 0.00524902343750000000f, 0.00393676757812500000f, + 0.00125122070312500000f, -0.00393676757812500000f, + -0.01135253906249999800f, -0.00073242187500000000f, + -0.00228881835937500000f, -0.00091552734374999989f, + -0.00518798828125000000f, 0.00030517578125000000f, + -0.00360107421875000000f, 0.00173950195312500000f, + 0.00238037109375000000f, -0.00308227539062500000f, + 0.00708007812500000000f, 0.00491333007812500000f, + 0.00375366210937500000f, 0.00781250000000000000f, + 0.00845336914062500000f, 0.00308227539062500000f, + -0.00585937500000000000f, -0.01919555664062500000f, + -0.00305175781250000000f, -0.00183105468749999980f, + -0.00708007812500000000f, 0.00201416015625000000f, + 0.00039672851562500005f, -0.00039672851562500005f, + -0.00244140625000000000f, -0.00729370117187499910f, + 0.00729370117187499910f, 0.00112915039062500000f, + 0.00097656250000000000f, 0.00271606445312500000f, + -0.00973510742187500000f, -0.01766967773437500000f, + 0.01373291015625000000f, 0.01098632812500000000f, + 0.00009155273437500000f, -0.00088500976562500000f, + -0.00912475585937500000f, -0.00271606445312500000f, + -0.00164794921875000000f, -0.00335693359375000000f, + -0.00750732421875000000f, -0.00500488281250000000f, + 0.00018310546875000000f, -0.00573730468750000000f, + 0.01031494140625000000f, 0.00537109374999999910f, + -0.00280761718750000000f, 0.00601196289062499910f, + 0.00418090820312500000f, 0.00408935546875000000f, + 0.00036621093750000000f, -0.00006103515625000000f, + 0.00170898437500000000f, -0.00558471679687500000f, + 0.00347900390625000000f, -0.00109863281250000000f, + -0.00399780273437500000f, -0.00622558593750000000f, + 0.00228881835937500000f, -0.00076293945312500000f, + -0.00531005859375000000f, 0.00582885742187500000f, + -0.00045776367187499995f, -0.00885009765625000000f, + -0.01309204101562500000f, -0.00814819335937500000f, + 0.00241088867187500000f, 0.00112915039062500000f, + 0.00323486328125000000f, 0.00070190429687500000f, + -0.01171875000000000000f, 0.01296997070312499800f, + 0.00213623046875000000f, -0.00042724609375000000f, + 0.00646972656250000000f, 0.00320434570312500000f, + 0.00045776367187499995f, -0.00006103515625000000f, + -0.00128173828125000000f, -0.00112915039062500000f, + -0.00375366210937500000f, 0.00329589843750000000f, + 0.00085449218750000000f, -0.00146484375000000000f, + 0.00588989257812500000f, 0.00601196289062499910f, + 0.00527954101562500000f, -0.00100708007812500000f, + 0.00112915039062500000f, 0.00222778320312500000f, + -0.00173950195312500000f, 0.00781250000000000000f, + 0.00418090820312500000f, -0.00177001953125000000f, + -0.01312255859375000000f, -0.00695800781250000000f, + 0.00662231445312500000f, -0.00155639648437500000f, + -0.00030517578125000000f, -0.00177001953125000000f, + -0.00018310546875000000f, 0.00067138671874999989f, + 0.00317382812500000040f, 0.00186157226562500000f, + -0.00363159179687500000f, 0.00515747070312500000f, + 0.00439453125000000000f, 0.00048828125000000000f, + -0.00140380859375000000f, -0.01202392578124999800f, + 0.00183105468749999980f, 0.01385498046875000000f, + -0.00244140625000000000f, -0.00909423828125000000f, + -0.00198364257812500000f, 0.00076293945312500000f, + 0.00000000000000000000f, -0.00073242187500000000f, + -0.00198364257812500000f, -0.01272583007812500000f, + 0.01419067382812500000f, 0.00842285156250000000f, + -0.00009155273437500000f, -0.00592041015625000000f, + -0.00039672851562500005f, 0.00396728515625000000f, + 0.00057983398437500000f, -0.00018310546875000000f, + -0.00064086914062500000f, -0.00073242187500000000f, + -0.00549316406250000000f, -0.00161743164062500000f, + -0.00259399414062500000f, 0.00061035156250000000f, + 0.00360107421875000000f, 0.00448608398437500000f, + 0.00344848632812500000f, -0.00228881835937500000f, + -0.00881958007812500000f, 0.00689697265625000000f, + -0.00372314453125000000f, 0.00692749023437500000f, + 0.00823974609375000000f, 0.00381469726562499960f, + 0.00332641601562499960f, 0.00601196289062499910f, + 0.00381469726562499960f, 0.00421142578125000000f, + 0.00134277343749999980f, 0.00183105468749999980f, + 0.00076293945312500000f, -0.00167846679687500000f, + -0.00509643554687500000f, -0.00097656250000000000f, + -0.00424194335937500000f, -0.00588989257812500000f, + -0.00527954101562500000f, -0.00964355468750000000f, + 0.00875854492187500000f, -0.00634765625000000090f, + 0.00772094726562500000f, 0.00729370117187499910f, + 0.00082397460937500000f, -0.00244140625000000000f, + -0.00573730468750000000f, -0.00085449218750000000f, + -0.00555419921875000000f, -0.00717163085937500000f, + 0.00476074218750000000f, -0.00357055664062500000f, + 0.00390625000000000000f, -0.00146484375000000000f, + -0.00177001953125000000f, -0.00689697265625000000f, + 0.00524902343750000000f, 0.00552368164062500000f, + 0.00509643554687500000f, 0.00057983398437500000f, + 0.00189208984375000000f, 0.00030517578125000000f, + 0.00006103515625000000f, 0.00552368164062500000f, + 0.00460815429687500000f, 0.00329589843750000000f, + -0.00048828125000000000f, -0.00033569335937499995f, + -0.00238037109375000000f, -0.01010131835937500000f, + 0.01254272460937500000f, 0.00405883789062500000f, + 0.00051879882812500000f, 0.00317382812500000040f, + 0.00195312500000000000f, -0.00561523437500000000f, + 0.00073242187500000000f, -0.00091552734374999989f, + -0.00009155273437500000f, -0.00863647460937500000f, + 0.00369262695312500000f, 0.00622558593750000000f, + -0.00024414062500000000f, -0.00607299804687500000f, + -0.00064086914062500000f, -0.00244140625000000000f, + -0.00515747070312500000f, -0.00479125976562500000f, + -0.00582885742187500000f, -0.00415039062500000000f, + 0.00247192382812500000f, 0.00473022460937500000f, + 0.00042724609375000000f, -0.00399780273437500000f, + 0.00744628906250000000f, 0.00225830078125000000f, + -0.00173950195312500000f, -0.00143432617187500000f, + -0.00854492187500000000f, 0.01058959960937500000f, + 0.00338745117187500000f, -0.00234985351562500000f, + -0.00390625000000000000f, -0.00433349609375000000f, + -0.00592041015625000000f, -0.00381469726562499960f, + -0.00018310546875000000f, -0.00207519531250000000f, + 0.00277709960937500000f, 0.00003051757812500000f, + 0.00070190429687500000f, 0.00042724609375000000f, + -0.00469970703125000000f, -0.00103759765625000000f, + 0.00070190429687500000f, -0.00115966796875000000f, + -0.01046752929687500200f, 0.01535034179687500000f, + 0.00445556640625000000f, -0.00115966796875000000f, + -0.00140380859375000000f, -0.00125122070312500000f, + 0.00177001953125000000f, 0.00094604492187500000f, + 0.00192260742187500000f, -0.00146484375000000000f, + -0.00357055664062500000f, 0.00137329101562500000f, + 0.00085449218750000000f, 0.00003051757812500000f, + -0.00271606445312500000f, -0.00015258789062500000f, + -0.00134277343749999980f, -0.00088500976562500000f, + -0.01367187500000000000f, 0.01486206054687500000f, + 0.00622558593750000000f, 0.00247192382812500000f, + 0.00140380859375000000f, -0.00323486328125000000f, + -0.00921630859375000000f, 0.01159667968750000000f, + 0.00366210937499999960f, -0.00115966796875000000f, + -0.00036621093750000000f, -0.00119018554687500000f, + 0.00213623046875000000f, -0.00009155273437500000f, + 0.00076293945312500000f, -0.00198364257812500000f, + 0.00091552734374999989f, -0.00033569335937499995f, + 0.00103759765625000000f, -0.00045776367187499995f, + 0.00067138671874999989f, -0.00350952148437500040f, + 0.00000000000000000000f, -0.00241088867187500000f, + -0.00253295898437500040f, 0.00137329101562500000f, + 0.00347900390625000000f, 0.00131225585937500000f, + 0.00457763671875000000f, 0.00109863281250000000f, + 0.00711059570312500000f, 0.00454711914062500000f, + 0.00595092773437500000f, 0.00015258789062500000f, + 0.00076293945312500000f, -0.00158691406250000020f, + -0.01449584960937500000f, 0.00836181640625000000f, + 0.00085449218750000000f, -0.00119018554687500000f, + -0.00024414062500000000f, -0.00201416015625000000f, + -0.00778198242187500000f, 0.00787353515625000000f, + 0.00170898437500000000f, 0.00436401367187500000f, + -0.00137329101562500000f, -0.00579833984375000000f, + 0.00503540039062499910f, -0.00183105468749999980f, + 0.00061035156250000000f, 0.00006103515625000000f, + 0.00381469726562499960f, -0.00393676757812500000f, + 0.00155639648437500000f, -0.00024414062500000000f, + -0.01022338867187500000f, 0.00878906250000000000f, + 0.00115966796875000000f, 0.00180053710937500000f, + 0.00076293945312500000f, -0.00128173828125000000f, + 0.00070190429687500000f, -0.00360107421875000000f, + -0.00341796875000000000f, 0.00033569335937499995f, + -0.00167846679687500000f, -0.00405883789062500000f, + -0.00332641601562499960f, 0.00073242187500000000f, + -0.00320434570312500000f, 0.00238037109375000000f, + -0.00195312500000000000f, -0.00747680664062500000f, + 0.00616455078125000000f, -0.00198364257812500000f, + -0.00387573242187500000f, 0.00494384765625000000f, + 0.00122070312500000000f, -0.00286865234375000000f, + 0.00271606445312500000f, -0.00259399414062500000f, + -0.00363159179687500000f, -0.00314331054687500000f, + 0.00296020507812500000f, 0.00027465820312500000f, + -0.00213623046875000000f, -0.00085449218750000000f, + 0.00592041015625000000f, 0.00262451171875000000f, + -0.00341796875000000000f, -0.00280761718750000000f, + -0.00347900390625000000f, 0.00225830078125000000f, + -0.00149536132812500000f, 0.00140380859375000000f, + -0.00256347656250000000f, -0.00543212890625000000f, + 0.00344848632812500000f, 0.00158691406250000020f, + -0.00625610351562500000f, 0.01016235351562500000f, + 0.00268554687499999960f, 0.00677490234375000000f, + 0.00170898437500000000f, -0.00167846679687500000f, + 0.00039672851562500005f, 0.00262451171875000000f, + 0.00012207031250000000f, -0.00234985351562500000f, + 0.00683593750000000000f, 0.00347900390625000000f, + -0.00320434570312500000f, 0.00341796875000000000f, + 0.00381469726562499960f, -0.00088500976562500000f, + -0.00054931640625000000f, -0.00439453125000000000f, + 0.00067138671874999989f, -0.00177001953125000000f, + -0.00302124023437500040f, 0.00085449218750000000f, + 0.00347900390625000000f, -0.00201416015625000000f, + -0.00097656250000000000f, -0.00515747070312500000f, + -0.00958251953125000000f, 0.00869750976562500000f, + 0.00219726562500000000f, -0.00225830078125000000f, + 0.00546264648437500000f, 0.00085449218750000000f, + -0.00241088867187500000f, -0.00555419921875000000f, + 0.00039672851562500005f, -0.00167846679687500000f, + 0.00448608398437500000f, 0.00039672851562500005f, + 0.00036621093750000000f, -0.00164794921875000000f, + 0.00094604492187500000f, -0.00256347656250000000f, + -0.00051879882812500000f, -0.00228881835937500000f, + -0.00695800781250000000f, 0.00253295898437500040f, + -0.01144409179687500000f, 0.01330566406249999800f, + 0.00335693359375000000f, -0.00192260742187500000f, + -0.00082397460937500000f, -0.00415039062500000000f, + 0.00515747070312500000f, -0.00170898437500000000f, + -0.00024414062500000000f, -0.00521850585937500000f, + 0.00561523437500000000f, -0.00128173828125000000f, + 0.00451660156250000000f, 0.00207519531250000000f, + 0.00622558593750000000f, 0.00717163085937500000f, + 0.00335693359375000000f, -0.00698852539062499910f, + 0.00277709960937500000f, 0.00521850585937500000f, + -0.00131225585937500000f, -0.00009155273437500000f, + -0.00079345703125000011f, -0.00302124023437500040f, + -0.00338745117187500000f, 0.00216674804687500000f, + -0.00518798828125000000f, 0.00616455078125000000f, + -0.00204467773437500000f, 0.00552368164062500000f, + -0.00112915039062500000f, 0.00332641601562499960f, + -0.00366210937499999960f, 0.00009155273437500000f, + -0.00167846679687500000f, -0.00793457031250000000f, + -0.00048828125000000000f, 0.00463867187500000000f, + 0.00277709960937500000f, 0.00433349609375000000f, + 0.00128173828125000000f, 0.00134277343749999980f, + 0.00408935546875000000f, 0.00143432617187500000f, + 0.00051879882812500000f, -0.00106811523437500000f, + 0.00067138671874999989f, 0.00241088867187500000f, + -0.00515747070312500000f, 0.00125122070312500000f, + 0.00140380859375000000f, 0.00845336914062500000f, + -0.00283813476562499960f, -0.00149536132812500000f, + -0.00384521484375000000f, 0.00112915039062500000f, + -0.00314331054687500000f, -0.00103759765625000000f, + -0.00067138671874999989f, -0.00274658203125000000f, + -0.00408935546875000000f, -0.00625610351562500000f, + 0.00280761718750000000f, -0.00027465820312500000f, + 0.00003051757812500000f, -0.00595092773437500000f, + -0.00729370117187499910f, 0.00137329101562500000f, + 0.00164794921875000000f, 0.00054931640625000000f, + -0.00070190429687500000f, -0.00003051757812500000f, + -0.00244140625000000000f, -0.00299072265625000000f, + -0.00061035156250000000f, -0.00796508789062500000f, + 0.00933837890625000000f, 0.00219726562500000000f, + 0.00061035156250000000f, -0.00271606445312500000f, + -0.00662231445312500000f, 0.00033569335937499995f, + 0.00018310546875000000f, -0.00250244140625000000f, + 0.00271606445312500000f, 0.00039672851562500005f, + -0.00393676757812500000f, -0.00271606445312500000f, + 0.00253295898437500040f, -0.00216674804687500000f, + -0.00167846679687500000f, 0.00396728515625000000f, + -0.00299072265625000000f, -0.00445556640625000000f, + -0.00082397460937500000f, -0.00173950195312500000f, + 0.00161743164062500000f, 0.00839233398437500000f, + 0.00051879882812500000f, 0.00518798828125000000f, + -0.00015258789062500000f, -0.00164794921875000000f, + 0.00402832031250000000f, -0.00195312500000000000f, + 0.00219726562500000000f, 0.00488281250000000000f, + -0.00381469726562499960f, -0.00512695312500000000f, + 0.00219726562500000000f, 0.00122070312500000000f, + 0.00518798828125000000f, 0.00238037109375000000f, + 0.00756835937500000000f, 0.00354003906250000000f, + 0.00061035156250000000f, 0.00256347656250000000f, + 0.00094604492187500000f, -0.00103759765625000000f, + 0.00579833984375000000f, 0.00115966796875000000f, + 0.00039672851562500005f, -0.00323486328125000000f, + 0.00686645507812500000f, 0.00082397460937500000f, + -0.00512695312500000000f, 0.00073242187500000000f, + -0.00479125976562500000f, -0.00372314453125000000f, + 0.00503540039062499910f, 0.00033569335937499995f, + -0.00491333007812500000f, -0.00650024414062500000f, + -0.00036621093750000000f, -0.00155639648437500000f, + -0.00308227539062500000f, 0.00128173828125000000f, + 0.00308227539062500000f, 0.00082397460937500000f, + 0.00167846679687500000f, 0.00338745117187500000f, + 0.00228881835937500000f, 0.00216674804687500000f, + -0.00292968750000000000f, -0.00003051757812500000f, + 0.00198364257812500000f, -0.00845336914062500000f, + 0.01199340820312500000f, -0.00079345703125000011f, + -0.00134277343749999980f, -0.00207519531250000000f, + -0.00256347656250000000f, -0.00201416015625000000f, + -0.00289916992187500000f, 0.00717163085937500000f, + 0.00546264648437500000f, -0.00076293945312500000f, + -0.00125122070312500000f, 0.00082397460937500000f, + -0.00277709960937500000f, -0.00390625000000000000f, + -0.00677490234375000000f, 0.00445556640625000000f, + -0.00219726562500000000f, -0.00091552734374999989f, + -0.00073242187500000000f, 0.00167846679687500000f, + -0.00384521484375000000f, -0.00207519531250000000f, + -0.00177001953125000000f, -0.00387573242187500000f, + 0.00039672851562500005f, -0.00296020507812500000f, + -0.00323486328125000000f, 0.00531005859375000000f, + -0.00305175781250000000f, 0.00473022460937500000f, + 0.00308227539062500000f, -0.00445556640625000000f, + -0.00064086914062500000f, 0.00796508789062500000f, + 0.00067138671874999989f, 0.00115966796875000000f, + -0.00201416015625000000f, 0.00198364257812500000f, + 0.00012207031250000000f, 0.00213623046875000000f, + 0.00195312500000000000f, 0.00439453125000000000f, + 0.00180053710937500000f, 0.00650024414062500000f, + 0.00216674804687500000f, -0.01028442382812500000f, + 0.00924682617187500000f, -0.00158691406250000020f, + 0.00155639648437500000f, -0.00170898437500000000f, + 0.00003051757812500000f, 0.00030517578125000000f, + -0.00045776367187499995f, -0.00015258789062500000f, + 0.00103759765625000000f, 0.00158691406250000020f, + 0.00695800781250000000f, 0.00399780273437500000f, + 0.00491333007812500000f, -0.00387573242187500000f, + -0.00653076171875000000f, 0.00726318359375000000f, + 0.00375366210937500000f, 0.00195312500000000000f, + -0.00448608398437500000f, -0.00152587890625000000f, + -0.00103759765625000000f, -0.00387573242187500000f, + 0.00622558593750000000f, 0.00494384765625000000f, + 0.00259399414062500000f, 0.00125122070312500000f, + 0.00015258789062500000f, -0.00427246093750000000f, + 0.00222778320312500000f, -0.00457763671875000000f, + 0.00170898437500000000f, -0.00292968750000000000f, + -0.00201416015625000000f, -0.00061035156250000000f, + 0.00006103515625000000f, -0.00717163085937500000f, + 0.00180053710937500000f, -0.00067138671874999989f, + -0.00326538085937500000f, 0.00457763671875000000f, + -0.00048828125000000000f, -0.00143432617187500000f, + -0.00012207031250000000f, 0.00247192382812500000f, + -0.00204467773437500000f, 0.00509643554687500000f, + 0.00454711914062500000f, 0.00454711914062500000f, + -0.00479125976562500000f, 0.00878906250000000000f, + -0.00476074218750000000f, -0.00082397460937500000f, + -0.00024414062500000000f, 0.00054931640625000000f, + 0.00253295898437500040f, -0.00073242187500000000f, + -0.00125122070312500000f, -0.00509643554687500000f, + 0.00482177734375000000f, -0.00305175781250000000f, + 0.00283813476562499960f, 0.00161743164062500000f, + 0.00613403320312500000f, 0.00045776367187499995f, + 0.00128173828125000000f, 0.00811767578125000000f, + 0.00848388671875000000f, -0.00036621093750000000f, + -0.00018310546875000000f, -0.00112915039062500000f, + 0.00259399414062500000f, 0.00018310546875000000f, + 0.00061035156250000000f, -0.00573730468750000000f, + -0.00827026367187500000f, 0.00326538085937500000f, + -0.00039672851562500005f, -0.00244140625000000000f, + 0.00155639648437500000f, 0.00616455078125000000f, + 0.00527954101562500000f, -0.00210571289062500000f, + 0.00238037109375000000f, -0.00573730468750000000f, + 0.00140380859375000000f, 0.00012207031250000000f, + 0.00466918945312500000f, 0.00036621093750000000f, + -0.00421142578125000000f, 0.00515747070312500000f, + 0.00015258789062500000f, -0.00177001953125000000f, + -0.00375366210937500000f, -0.00329589843750000000f, + -0.00741577148437500000f, 0.00457763671875000000f, + 0.00030517578125000000f, -0.00582885742187500000f, + 0.00750732421875000000f, -0.00045776367187499995f, + 0.00115966796875000000f, 0.00076293945312500000f, + -0.00030517578125000000f, 0.00042724609375000000f, + 0.00186157226562500000f, 0.00152587890625000000f, + -0.00628662109375000000f, -0.00656127929687500000f, + -0.00671386718750000000f, 0.00274658203125000000f, + 0.00015258789062500000f, -0.00454711914062500000f, + -0.00668334960937500090f, 0.00170898437500000000f, + 0.00433349609375000000f, 0.00073242187500000000f, + -0.01147460937500000000f, 0.00234985351562500000f, + -0.00244140625000000000f, 0.00228881835937500000f, + 0.00018310546875000000f, 0.00128173828125000000f, + -0.00308227539062500000f, 0.00048828125000000000f, + 0.00170898437500000000f, 0.00042724609375000000f, + -0.00173950195312500000f, 0.00009155273437500000f, + -0.00051879882812500000f, 0.00244140625000000000f, + 0.00173950195312500000f, -0.00109863281250000000f, + 0.00268554687499999960f, -0.00180053710937500000f, + -0.00296020507812500000f, -0.00057983398437500000f, + -0.00451660156250000000f, 0.00140380859375000000f, + -0.00668334960937500090f, 0.00689697265625000000f, + 0.00347900390625000000f, -0.00012207031250000000f, + -0.00219726562500000000f, -0.00045776367187499995f, + 0.00112915039062500000f, -0.00149536132812500000f, + -0.00085449218750000000f, 0.00753784179687500000f, + 0.00134277343749999980f, 0.00375366210937500000f, + 0.00143432617187500000f, -0.00372314453125000000f, + -0.00115966796875000000f, 0.00051879882812500000f, + 0.00012207031250000000f, -0.00344848632812500000f, + -0.00097656250000000000f, -0.00683593750000000000f, + 0.00469970703125000000f, -0.00408935546875000000f, + 0.00598144531250000000f, 0.00216674804687500000f, + -0.00814819335937500000f, -0.00259399414062500000f, + 0.00085449218750000000f, -0.00213623046875000000f, + 0.00271606445312500000f, -0.00366210937499999960f, + 0.00302124023437500040f, -0.00006103515625000000f, + 0.00195312500000000000f, 0.00231933593750000000f, + -0.00506591796875000090f, -0.00146484375000000000f, + 0.00576782226562500000f, -0.00106811523437500000f, + -0.00280761718750000000f, -0.00515747070312500000f, + -0.00375366210937500000f, 0.01034545898437500000f, + 0.00115966796875000000f, -0.00076293945312500000f, + 0.00115966796875000000f, -0.00106811523437500000f, + 0.00686645507812500000f, -0.00424194335937500000f, + -0.00152587890625000000f, -0.00192260742187500000f, + 0.00750732421875000000f, 0.00183105468749999980f, + -0.00564575195312500000f, -0.00332641601562499960f, + -0.00149536132812500000f, -0.00161743164062500000f, + -0.00509643554687500000f, 0.00155639648437500000f, + 0.00454711914062500000f, 0.00183105468749999980f, + -0.00308227539062500000f, -0.00100708007812500000f, + 0.00076293945312500000f, -0.00231933593750000000f, + 0.00366210937499999960f, 0.00097656250000000000f, + -0.00091552734374999989f, -0.00253295898437500040f, + 0.00311279296875000000f, 0.00277709960937500000f, + -0.00567626953124999910f, -0.00796508789062500000f, + 0.00399780273437500000f, -0.00601196289062499910f +}; + +const SKP_Silk_NLSF_CBS_FLP SKP_Silk_NLSF_CB0_16_Stage_info_FLP[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + { 128, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 128 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 128 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 144 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 144 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 152 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 152 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 160 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 160 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 168 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 168 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 176 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 176 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 184 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 184 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 192 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 192 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16[ 16 * 200 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates[ 200 ] } +}; + +const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB0_16_FLP = +{ + NLSF_MSVQ_CB0_16_STAGES, + SKP_Silk_NLSF_CB0_16_Stage_info_FLP, + SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.c new file mode 100755 index 0000000..ea2dc02 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.c @@ -0,0 +1,578 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.19 + 1.61 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB1_10.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ NLSF_MSVQ_CB1_10_VECTORS + NLSF_MSVQ_CB1_10_STAGES ] = +{ + 0, + 17096, + 24130, + 28997, + 33179, + 36696, + 40213, + 42493, + 44252, + 45973, + 47551, + 49095, + 50542, + 51898, + 53196, + 54495, + 55685, + 56851, + 57749, + 58628, + 59435, + 60207, + 60741, + 61220, + 61700, + 62179, + 62659, + 63138, + 63617, + 64097, + 64576, + 65056, + 65535, + 0, + 20378, + 33032, + 40395, + 46721, + 51707, + 56585, + 61157, + 65535, + 0, + 15055, + 25472, + 35447, + 42501, + 48969, + 54773, + 60212, + 65535, + 0, + 12069, + 22440, + 32812, + 40145, + 46870, + 53595, + 59630, + 65535, + 0, + 10839, + 19954, + 27957, + 35961, + 43965, + 51465, + 58805, + 65535, + 0, + 8933, + 17674, + 26415, + 34785, + 42977, + 50820, + 58496, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 33 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 42 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 51 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 60 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 69 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + 5, + 3, + 4, + 4, + 5, + 5 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 62, 103, + 120, 127, + 135, 135, + 155, 167, + 168, 172, + 173, 176, + 179, 181, + 181, 185, + 186, 198, + 199, 203, + 205, 222, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 54, 76, + 101, 108, + 119, 120, + 123, 125, + 68, 85, + 87, 103, + 107, 112, + 115, 116, + 78, 85, + 85, 101, + 105, 105, + 110, 111, + 83, 91, + 97, 97, + 97, 100, + 101, 105, + 92, 93, + 93, 95, + 96, 98, + 99, 103 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min_Q15[ 10 + 1 ] = +{ + 462, + 3, + 64, + 74, + 98, + 50, + 97, + 68, + 120, + 53, + 639 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 1877, 4646, + 7712, 10745, + 13964, 17028, + 20239, 23182, + 26471, 29287, + 1612, 3278, + 7086, 9975, + 13228, 16264, + 19596, 22690, + 26037, 28965, + 2169, 3830, + 6460, 8958, + 11960, 14750, + 18408, 21659, + 25018, 28043, + 3680, 6024, + 8986, 12256, + 15201, 18188, + 21741, 24460, + 27484, 30059, + 2584, 5187, + 7799, 10902, + 13179, 15765, + 19017, 22431, + 25891, 28698, + 3731, 5751, + 8650, 11742, + 15090, 17407, + 20391, 23421, + 26228, 29247, + 2107, 6323, + 8915, 12226, + 14775, 17791, + 20664, 23679, + 26829, 29353, + 1677, 2870, + 5386, 8077, + 11817, 15176, + 18657, 22006, + 25513, 28689, + 2111, 3625, + 7027, 10588, + 14059, 17193, + 21137, 24260, + 27577, 30036, + 2428, 4010, + 5765, 9376, + 13805, 15821, + 19444, 22389, + 25295, 29310, + 2256, 4628, + 8377, 12441, + 15283, 19462, + 22257, 25551, + 28432, 30304, + 2352, 3675, + 6129, 11868, + 14551, 16655, + 19624, 21883, + 26526, 28849, + 5243, 7248, + 10558, 13269, + 15651, 17919, + 21141, 23827, + 27102, 29519, + 4422, 6725, + 10449, 13273, + 16124, 19921, + 22826, 26061, + 28763, 30583, + 4508, 6291, + 9504, 11809, + 13827, 15950, + 19077, 22084, + 25740, 28658, + 2540, 4297, + 8579, 13578, + 16634, 19101, + 21547, 23887, + 26777, 29146, + 3377, 6358, + 10224, 14518, + 17905, 21056, + 23637, 25784, + 28161, 30109, + 4177, 5942, + 8159, 10108, + 12130, 15470, + 20191, 23326, + 26782, 29359, + 2492, 3801, + 6144, 9825, + 16000, 18671, + 20893, 23663, + 25899, 28974, + 3011, 4727, + 6834, 10505, + 12465, 14496, + 17065, 20052, + 25265, 28057, + 4149, 7197, + 12338, 15076, + 18002, 20190, + 22187, 24723, + 27083, 29125, + 2975, 4578, + 6448, 8378, + 9671, 13225, + 19502, 22277, + 26058, 28850, + 4102, 5760, + 7744, 9484, + 10744, 12308, + 14677, 19607, + 24841, 28381, + 4931, 9287, + 12477, 13395, + 13712, 14351, + 16048, 19867, + 24188, 28994, + 4141, 7867, + 13140, 17720, + 20064, 21108, + 21692, 22722, + 23736, 27449, + 4011, 8720, + 13234, 16206, + 17601, 18289, + 18524, 19689, + 23234, 27882, + 3420, 5995, + 11230, 15117, + 15907, 16783, + 17762, 23347, + 26898, 29946, + 3080, 6786, + 10465, 13676, + 18059, 23615, + 27058, 29082, + 29563, 29905, + 3038, 5620, + 9266, 12870, + 18803, 19610, + 20010, 20802, + 23882, 29306, + 3314, 6420, + 9046, 13262, + 15869, 23117, + 23667, 24215, + 24487, 25915, + 3469, 6963, + 10103, 15282, + 20531, 23240, + 25024, 26021, + 26736, 27255, + 3041, 6459, + 9777, 12896, + 16315, 19410, + 24070, 29353, + 31795, 32075, + -200, -134, + -113, -204, + -347, -440, + -352, -211, + -418, -172, + -313, 59, + 495, 772, + 721, 614, + 334, 444, + 225, 242, + 161, 16, + 274, 564, + -73, -188, + -395, -171, + 777, 508, + 1340, 1145, + 699, 196, + 223, 173, + 90, 25, + -26, 18, + 133, -105, + -360, -277, + 859, 634, + 41, -557, + -768, -926, + -601, -1021, + -1189, -365, + 225, 107, + 374, -50, + 433, 417, + 156, 39, + -597, -1397, + -1594, -592, + -485, -292, + 253, 87, + -0, -6, + -25, -345, + -240, 120, + 1261, 946, + 166, -277, + 241, 167, + 170, 429, + 518, 714, + 602, 254, + 134, 92, + -152, -324, + -394, 49, + -151, -304, + -724, -657, + -162, -369, + -35, 3, + -2, -312, + -200, -92, + -227, 242, + 628, 565, + -124, 1056, + 770, 101, + -84, -33, + 4, -192, + -272, 5, + -627, -977, + 419, 472, + 53, -103, + 145, 322, + -95, -31, + -100, -303, + -560, -1067, + -413, 714, + 283, 2, + -223, -367, + 523, 360, + -38, -115, + 378, -591, + -718, 448, + -481, -274, + 180, -88, + -581, -157, + -696, -1265, + 394, -479, + -23, 124, + -43, 19, + -113, -236, + -412, -659, + -200, 2, + -69, -342, + 199, 55, + 58, -36, + -51, -62, + 507, 507, + 427, 442, + 36, 601, + -141, 68, + 274, 274, + 68, -12, + -4, 71, + -193, -464, + -425, -383, + 408, 203, + -337, 236, + 410, -59, + -25, -341, + -449, 28, + -9, 90, + 332, -14, + -905, 96, + -540, -242, + 679, -59, + 192, -24, + 60, -217, + 5, -37, + 179, -20, + 311, 519, + 274, 72, + -326, -1030, + -262, 213, + 380, 82, + 328, 411, + -540, 574, + -283, 151, + 181, -402, + -278, -240, + -110, -227, + -264, -89, + -250, -259, + -27, 106, + -239, -98, + -390, 118, + 61, 104, + 294, 532, + 92, -13, + 60, -233, + 335, 541, + 307, -26, + -110, -91, + -231, -460, + 170, 201, + 96, -372, + 132, 435, + -302, 216, + -279, -41, + 74, 190, + 368, 273, + -186, -608, + -157, 159, + 12, 278, + 245, 307, + 25, -187, + -16, 55, + 30, -163, + 548, -307, + 106, -5, + 27, 330, + -416, 475, + 438, -235, + 104, 137, + 21, -5, + -300, -468, + 521, -347, + 170, -200, + -219, 308, + -122, -133, + 219, -16, + 359, 412, + -89, -111, + 48, 322, + 142, 177, + -286, -127, + -39, -63, + -42, -451, + 160, 308, + -57, 193, + -48, 74, + -346, 59, + -27, 27, + -469, -277, + -344, 282, + 262, 122, + 171, -249, + 27, 258, + 188, -3, + 67, -206, + -284, 291, + -117, -88, + -477, 375, + 50, 106, + 99, -182, + 438, -376, + -401, -49, + 119, -23, + -10, -48, + -116, -200, + -310, 121, + 73, 7, + 237, -226, + 139, -456, + 397, 35, + 3, -108, + 323, -75, + 332, 198, + -99, -21 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB1_10_Stage_info[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 64 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB1_10 = +{ + NLSF_MSVQ_CB1_10_STAGES, + SKP_Silk_NLSF_CB1_10_Stage_info, + SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.h new file mode 100755 index 0000000..789d0bf --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_NLSF_CB1_10_H +#define SKP_SILK_TABLES_NLSF_CB1_10_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB1_10_STAGES 6 +#define NLSF_MSVQ_CB1_10_VECTORS 72 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ NLSF_MSVQ_CB1_10_VECTORS + NLSF_MSVQ_CB1_10_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr[ NLSF_MSVQ_CB1_10_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx[ NLSF_MSVQ_CB1_10_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10_FLP.c new file mode 100755 index 0000000..11eaae2 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_10_FLP.c @@ -0,0 +1,475 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 3.21 kB */ +/**********************************************/ + +#include "SKP_Silk_tables_FLP.h" +#include "SKP_Silk_tables_NLSF_CB1_10.h" + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_10_rates[ NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 1.93750000000000000000f, 3.21875000000000000000f, + 3.75000000000000000000f, 3.96875000000000000000f, + 4.21875000000000000000f, 4.21875000000000000000f, + 4.84375000000000000000f, 5.21875000000000000000f, + 5.25000000000000000000f, 5.37500000000000000000f, + 5.40625000000000000000f, 5.50000000000000000000f, + 5.59375000000000000000f, 5.65625000000000000000f, + 5.65625000000000000000f, 5.78125000000000000000f, + 5.81250000000000000000f, 6.18750000000000000000f, + 6.21875000000000000000f, 6.34375000000000000000f, + 6.40625000000000000000f, 6.93750000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 1.68750000000000000000f, 2.37500000000000000000f, + 3.15625000000000000000f, 3.37500000000000000000f, + 3.71875000000000000000f, 3.75000000000000000000f, + 3.84375000000000000000f, 3.90625000000000000000f, + 2.12500000000000000000f, 2.65625000000000000000f, + 2.71875000000000000000f, 3.21875000000000000000f, + 3.34375000000000000000f, 3.50000000000000000000f, + 3.59375000000000000000f, 3.62500000000000000000f, + 2.43750000000000000000f, 2.65625000000000000000f, + 2.65625000000000000000f, 3.15625000000000000000f, + 3.28125000000000000000f, 3.28125000000000000000f, + 3.43750000000000000000f, 3.46875000000000000000f, + 2.59375000000000000000f, 2.84375000000000000000f, + 3.03125000000000000000f, 3.03125000000000000000f, + 3.03125000000000000000f, 3.12500000000000000000f, + 3.15625000000000000000f, 3.28125000000000000000f, + 2.87500000000000000000f, 2.90625000000000000000f, + 2.90625000000000000000f, 2.96875000000000000000f, + 3.00000000000000000000f, 3.06250000000000000000f, + 3.09375000000000000000f, 3.21875000000000000000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min[ 10 + 1 ] = +{ + 0.01409912109375000000f, + 0.00009155273437500000f, + 0.00195312500000000000f, + 0.00225830078125000000f, + 0.00299072265625000000f, + 0.00152587890625000000f, + 0.00296020507812500000f, + 0.00207519531250000000f, + 0.00366210937499999960f, + 0.00161743164062500000f, + 0.01950073242187500000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 0.05728149414062500000f, 0.14178466796875000000f, + 0.23535156250000003000f, 0.32791137695312500000f, + 0.42614746093750000000f, 0.51965332031250000000f, + 0.61764526367187500000f, 0.70745849609375000000f, + 0.80783081054687511000f, 0.89376831054687500000f, + 0.04919433593750000000f, 0.10003662109375001000f, + 0.21624755859374997000f, 0.30441284179687500000f, + 0.40368652343750000000f, 0.49633789062499994000f, + 0.59802246093750000000f, 0.69244384765625011000f, + 0.79458618164062500000f, 0.88394165039062500000f, + 0.06619262695312500000f, 0.11688232421875000000f, + 0.19714355468750000000f, 0.27337646484375000000f, + 0.36499023437500000000f, 0.45013427734375000000f, + 0.56176757812500000000f, 0.66098022460937500000f, + 0.76348876953125000000f, 0.85580444335937489000f, + 0.11230468750000001000f, 0.18383789062500000000f, + 0.27423095703125000000f, 0.37402343749999994000f, + 0.46389770507812494000f, 0.55505371093750000000f, + 0.66348266601562500000f, 0.74645996093750000000f, + 0.83874511718749989000f, 0.91732788085937500000f, + 0.07885742187500000000f, 0.15829467773437500000f, + 0.23800659179687500000f, 0.33270263671874994000f, + 0.40219116210937500000f, 0.48110961914062500000f, + 0.58035278320312500000f, 0.68453979492187500000f, + 0.79013061523437500000f, 0.87579345703125000000f, + 0.11386108398437500000f, 0.17550659179687500000f, + 0.26397705078125000000f, 0.35833740234375000000f, + 0.46051025390625000000f, 0.53121948242187500000f, + 0.62228393554687500000f, 0.71475219726562500000f, + 0.80041503906250000000f, 0.89254760742187511000f, + 0.06430053710937500000f, 0.19296264648437500000f, + 0.27206420898437500000f, 0.37310791015625000000f, + 0.45089721679687500000f, 0.54293823242187500000f, + 0.63061523437500000000f, 0.72262573242187500000f, + 0.81875610351562500000f, 0.89578247070312500000f, + 0.05117797851562500000f, 0.08758544921875000000f, + 0.16436767578125000000f, 0.24649047851562500000f, + 0.36062622070312500000f, 0.46313476562500000000f, + 0.56936645507812500000f, 0.67156982421875011000f, + 0.77859497070312500000f, 0.87551879882812500000f, + 0.06442260742187500000f, 0.11062622070312501000f, + 0.21444702148437500000f, 0.32312011718750000000f, + 0.42904663085937500000f, 0.52468872070312500000f, + 0.64505004882812489000f, 0.74035644531250000000f, + 0.84158325195312500000f, 0.91662597656250011000f, + 0.07409667968750000000f, 0.12237548828125000000f, + 0.17593383789062500000f, 0.28613281250000000000f, + 0.42129516601562500000f, 0.48281860351562500000f, + 0.59338378906250000000f, 0.68325805664062511000f, + 0.77194213867187500000f, 0.89447021484375000000f, + 0.06884765625000000000f, 0.14123535156250000000f, + 0.25564575195312500000f, 0.37966918945312500000f, + 0.46640014648437500000f, 0.59393310546875000000f, + 0.67922973632812500000f, 0.77975463867187489000f, + 0.86767578124999989000f, 0.92480468750000000000f, + 0.07177734375000000000f, 0.11215209960937499000f, + 0.18704223632812500000f, 0.36218261718750000000f, + 0.44406127929687494000f, 0.50827026367187500000f, + 0.59887695312500000000f, 0.66781616210937500000f, + 0.80950927734375000000f, 0.88040161132812500000f, + 0.16000366210937500000f, 0.22119140625000000000f, + 0.32220458984375000000f, 0.40493774414062500000f, + 0.47763061523437506000f, 0.54684448242187500000f, + 0.64517211914062500000f, 0.72714233398437500000f, + 0.82708740234375000000f, 0.90084838867187489000f, + 0.13494873046875000000f, 0.20523071289062500000f, + 0.31887817382812500000f, 0.40505981445312500000f, + 0.49206542968750000000f, 0.60794067382812500000f, + 0.69659423828124989000f, 0.79531860351562500000f, + 0.87777709960937500000f, 0.93331909179687500000f, + 0.13757324218750000000f, 0.19198608398437500000f, + 0.29003906250000000000f, 0.36038208007812506000f, + 0.42196655273437500000f, 0.48675537109375000000f, + 0.58218383789062500000f, 0.67395019531250000000f, + 0.78552246093750000000f, 0.87457275390625000000f, + 0.07751464843750000000f, 0.13113403320312500000f, + 0.26181030273437500000f, 0.41436767578125000000f, + 0.50762939453125000000f, 0.58291625976562500000f, + 0.65756225585937500000f, 0.72897338867187500000f, + 0.81716918945312489000f, 0.88946533203125000000f, + 0.10305786132812501000f, 0.19403076171875003000f, + 0.31201171875000000000f, 0.44305419921875000000f, + 0.54641723632812500000f, 0.64257812500000000000f, + 0.72134399414062500000f, 0.78686523437500011000f, + 0.85940551757812500000f, 0.91885375976562500000f, + 0.12747192382812500000f, 0.18133544921875000000f, + 0.24899291992187497000f, 0.30847167968750000000f, + 0.37017822265625000000f, 0.47210693359375000000f, + 0.61618041992187500000f, 0.71185302734375000000f, + 0.81732177734375000000f, 0.89596557617187500000f, + 0.07604980468750000000f, 0.11599731445312501000f, + 0.18750000000000000000f, 0.29983520507812500000f, + 0.48828124999999994000f, 0.56979370117187500000f, + 0.63760375976562489000f, 0.72213745117187500000f, + 0.79037475585937500000f, 0.88421630859374989000f, + 0.09188842773437500000f, 0.14425659179687500000f, + 0.20855712890625000000f, 0.32058715820312500000f, + 0.38040161132812500000f, 0.44238281250000000000f, + 0.52078247070312500000f, 0.61193847656250000000f, + 0.77102661132812500000f, 0.85623168945312500000f, + 0.12661743164062500000f, 0.21963500976562500000f, + 0.37652587890625000000f, 0.46008300781249994000f, + 0.54937744140625000000f, 0.61614990234375000000f, + 0.67709350585937500000f, 0.75448608398437500000f, + 0.82650756835937500000f, 0.88882446289062511000f, + 0.09078979492187500000f, 0.13970947265625000000f, + 0.19677734375000000000f, 0.25567626953125000000f, + 0.29513549804687500000f, 0.40359497070312500000f, + 0.59515380859375000000f, 0.67984008789062500000f, + 0.79522705078125000000f, 0.88043212890625000000f, + 0.12518310546875000000f, 0.17578125000000000000f, + 0.23632812500000000000f, 0.28942871093750000000f, + 0.32788085937500000000f, 0.37561035156250000000f, + 0.44790649414062500000f, 0.59835815429687500000f, + 0.75808715820312500000f, 0.86611938476562489000f, + 0.15048217773437500000f, 0.28341674804687500000f, + 0.38076782226562500000f, 0.40878295898437500000f, + 0.41845703125000000000f, 0.43795776367187506000f, + 0.48974609375000000000f, 0.60629272460937500000f, + 0.73815917968750000000f, 0.88482666015624989000f, + 0.12637329101562500000f, 0.24008178710937500000f, + 0.40100097656250000000f, 0.54077148437500000000f, + 0.61230468750000000000f, 0.64416503906250000000f, + 0.66198730468750000000f, 0.69342041015625000000f, + 0.72436523437500000000f, 0.83767700195312500000f, + 0.12240600585937499000f, 0.26611328125000000000f, + 0.40386962890625006000f, 0.49456787109375006000f, + 0.53713989257812500000f, 0.55813598632812500000f, + 0.56530761718750000000f, 0.60086059570312500000f, + 0.70904541015625000000f, 0.85089111328125000000f, + 0.10437011718750000000f, 0.18295288085937500000f, + 0.34271240234375006000f, 0.46133422851562500000f, + 0.48544311523437500000f, 0.51217651367187500000f, + 0.54205322265625000000f, 0.71249389648437500000f, + 0.82086181640625000000f, 0.91387939453125000000f, + 0.09399414062500001400f, 0.20709228515625000000f, + 0.31936645507812506000f, 0.41735839843750000000f, + 0.55111694335937500000f, 0.72067260742187489000f, + 0.82574462890624989000f, 0.88751220703124989000f, + 0.90219116210937500000f, 0.91262817382812500000f, + 0.09271240234375000000f, 0.17150878906250003000f, + 0.28277587890625000000f, 0.39276123046875000000f, + 0.57382202148437500000f, 0.59844970703125000000f, + 0.61065673828125000000f, 0.63482666015625000000f, + 0.72882080078125011000f, 0.89434814453125000000f, + 0.10113525390625000000f, 0.19592285156250000000f, + 0.27606201171875000000f, 0.40472412109375000000f, + 0.48428344726562500000f, 0.70547485351562500000f, + 0.72225952148437500000f, 0.73898315429687500000f, + 0.74728393554687500000f, 0.79086303710937500000f, + 0.10586547851562500000f, 0.21249389648437500000f, + 0.30831909179687500000f, 0.46636962890625006000f, + 0.62655639648437500000f, 0.70922851562500000000f, + 0.76367187500000000000f, 0.79409790039062500000f, + 0.81591796875000000000f, 0.83175659179687500000f, + 0.09280395507812500000f, 0.19711303710937500000f, + 0.29837036132812500000f, 0.39355468750000000000f, + 0.49789428710937500000f, 0.59234619140625000000f, + 0.73455810546875000000f, 0.89578247070312500000f, + 0.97030639648437500000f, 0.97885131835937500000f, + -0.00610351562500000000f, -0.00408935546875000000f, + -0.00344848632812500000f, -0.00622558593750000000f, + -0.01058959960937500000f, -0.01342773437500000000f, + -0.01074218749999999800f, -0.00643920898437500000f, + -0.01275634765625000200f, -0.00524902343750000000f, + -0.00955200195312500000f, 0.00180053710937500000f, + 0.01510620117187500000f, 0.02355957031250000000f, + 0.02200317382812500000f, 0.01873779296875000000f, + 0.01019287109375000000f, 0.01354980468750000000f, + 0.00686645507812500000f, 0.00738525390625000000f, + 0.00491333007812500000f, 0.00048828125000000000f, + 0.00836181640625000000f, 0.01721191406250000000f, + -0.00222778320312500000f, -0.00573730468750000000f, + -0.01205444335937500000f, -0.00521850585937500000f, + 0.02371215820312499700f, 0.01550292968750000000f, + 0.04089355468750000000f, 0.03494262695312500000f, + 0.02133178710937500000f, 0.00598144531250000000f, + 0.00680541992187500000f, 0.00527954101562500000f, + 0.00274658203125000000f, 0.00076293945312500000f, + -0.00079345703125000011f, 0.00054931640625000000f, + 0.00405883789062500000f, -0.00320434570312500000f, + -0.01098632812500000000f, -0.00845336914062500000f, + 0.02621459960937500000f, 0.01934814453125000000f, + 0.00125122070312500000f, -0.01699829101562500000f, + -0.02343750000000000000f, -0.02825927734375000000f, + -0.01834106445312500000f, -0.03115844726562500000f, + -0.03628540039062500000f, -0.01113891601562500000f, + 0.00686645507812500000f, 0.00326538085937500000f, + 0.01141357421875000200f, -0.00152587890625000000f, + 0.01321411132812500000f, 0.01272583007812500000f, + 0.00476074218750000000f, 0.00119018554687500000f, + -0.01821899414062500000f, -0.04263305664062499300f, + -0.04864501953125000000f, -0.01806640625000000000f, + -0.01480102539062500000f, -0.00891113281250000000f, + 0.00772094726562500000f, 0.00265502929687500000f, + -0.00000000000000000000f, -0.00018310546875000000f, + -0.00076293945312500000f, -0.01052856445312500000f, + -0.00732421874999999910f, 0.00366210937499999960f, + 0.03848266601562500000f, 0.02886962890625000000f, + 0.00506591796875000090f, -0.00845336914062500000f, + 0.00735473632812500090f, 0.00509643554687500000f, + 0.00518798828125000000f, 0.01309204101562500000f, + 0.01580810546875000000f, 0.02178955078125000000f, + 0.01837158203125000000f, 0.00775146484375000000f, + 0.00408935546875000000f, 0.00280761718750000000f, + -0.00463867187500000000f, -0.00988769531250000000f, + -0.01202392578124999800f, 0.00149536132812500000f, + -0.00460815429687500000f, -0.00927734375000000000f, + -0.02209472656250000000f, -0.02005004882812500000f, + -0.00494384765625000000f, -0.01126098632812500000f, + -0.00106811523437500000f, 0.00009155273437500000f, + -0.00006103515625000000f, -0.00952148437500000000f, + -0.00610351562500000000f, -0.00280761718750000000f, + -0.00692749023437500000f, 0.00738525390625000000f, + 0.01916503906250000000f, 0.01724243164062500000f, + -0.00378417968750000000f, 0.03222656250000000000f, + 0.02349853515625000300f, 0.00308227539062500000f, + -0.00256347656250000000f, -0.00100708007812500000f, + 0.00012207031250000000f, -0.00585937500000000000f, + -0.00830078125000000000f, 0.00015258789062500000f, + -0.01913452148437500000f, -0.02981567382812500000f, + 0.01278686523437500000f, 0.01440429687500000000f, + 0.00161743164062500000f, -0.00314331054687500000f, + 0.00442504882812500000f, 0.00982666015625000000f, + -0.00289916992187500000f, -0.00094604492187500000f, + -0.00305175781250000000f, -0.00924682617187500000f, + -0.01708984375000000000f, -0.03256225585937500000f, + -0.01260375976562500000f, 0.02178955078125000000f, + 0.00863647460937500000f, 0.00006103515625000000f, + -0.00680541992187500000f, -0.01119995117187500000f, + 0.01596069335937500000f, 0.01098632812500000000f, + -0.00115966796875000000f, -0.00350952148437500040f, + 0.01153564453125000000f, -0.01803588867187500000f, + -0.02191162109375000000f, 0.01367187500000000000f, + -0.01467895507812500000f, -0.00836181640625000000f, + 0.00549316406250000000f, -0.00268554687499999960f, + -0.01773071289062500000f, -0.00479125976562500000f, + -0.02124023437500000000f, -0.03860473632812500000f, + 0.01202392578124999800f, -0.01461791992187500000f, + -0.00070190429687500000f, 0.00378417968750000000f, + -0.00131225585937500000f, 0.00057983398437500000f, + -0.00344848632812500000f, -0.00720214843750000000f, + -0.01257324218750000000f, -0.02011108398437500000f, + -0.00610351562500000000f, 0.00006103515625000000f, + -0.00210571289062500000f, -0.01043701171875000000f, + 0.00607299804687500000f, 0.00167846679687500000f, + 0.00177001953125000000f, -0.00109863281250000000f, + -0.00155639648437500000f, -0.00189208984375000000f, + 0.01547241210937500000f, 0.01547241210937500000f, + 0.01303100585937500200f, 0.01348876953125000000f, + 0.00109863281250000000f, 0.01834106445312500000f, + -0.00430297851562500000f, 0.00207519531250000000f, + 0.00836181640625000000f, 0.00836181640625000000f, + 0.00207519531250000000f, -0.00036621093750000000f, + -0.00012207031250000000f, 0.00216674804687500000f, + -0.00588989257812500000f, -0.01416015625000000000f, + -0.01296997070312499800f, -0.01168823242187499800f, + 0.01245117187500000000f, 0.00619506835937500000f, + -0.01028442382812500000f, 0.00720214843750000000f, + 0.01251220703125000000f, -0.00180053710937500000f, + -0.00076293945312500000f, -0.01040649414062499800f, + -0.01370239257812500200f, 0.00085449218750000000f, + -0.00027465820312500000f, 0.00274658203125000000f, + 0.01013183593750000200f, -0.00042724609375000000f, + -0.02761840820312499700f, 0.00292968750000000000f, + -0.01647949218750000000f, -0.00738525390625000000f, + 0.02072143554687500000f, -0.00180053710937500000f, + 0.00585937500000000000f, -0.00073242187500000000f, + 0.00183105468749999980f, -0.00662231445312500000f, + 0.00015258789062500000f, -0.00112915039062500000f, + 0.00546264648437500000f, -0.00061035156250000000f, + 0.00949096679687500000f, 0.01583862304687500000f, + 0.00836181640625000000f, 0.00219726562500000000f, + -0.00994873046875000000f, -0.03143310546875000000f, + -0.00799560546875000000f, 0.00650024414062500000f, + 0.01159667968750000000f, 0.00250244140625000000f, + 0.01000976562500000000f, 0.01254272460937500000f, + -0.01647949218750000000f, 0.01751708984375000000f, + -0.00863647460937500000f, 0.00460815429687500000f, + 0.00552368164062500000f, -0.01226806640625000000f, + -0.00848388671875000000f, -0.00732421874999999910f, + -0.00335693359375000000f, -0.00692749023437500000f, + -0.00805664062500000000f, -0.00271606445312500000f, + -0.00762939453124999910f, -0.00790405273437500000f, + -0.00082397460937500000f, 0.00323486328125000000f, + -0.00729370117187499910f, -0.00299072265625000000f, + -0.01190185546875000000f, 0.00360107421875000000f, + 0.00186157226562500000f, 0.00317382812500000040f, + 0.00897216796875000000f, 0.01623535156250000000f, + 0.00280761718750000000f, -0.00039672851562500005f, + 0.00183105468749999980f, -0.00711059570312500000f, + 0.01022338867187500000f, 0.01651000976562500000f, + 0.00936889648437500000f, -0.00079345703125000011f, + -0.00335693359375000000f, -0.00277709960937500000f, + -0.00704956054687500000f, -0.01403808593750000200f, + 0.00518798828125000000f, 0.00613403320312500000f, + 0.00292968750000000000f, -0.01135253906249999800f, + 0.00402832031250000000f, 0.01327514648437500000f, + -0.00921630859375000000f, 0.00659179687500000000f, + -0.00851440429687500000f, -0.00125122070312500000f, + 0.00225830078125000000f, 0.00579833984375000000f, + 0.01123046875000000000f, 0.00833129882812500000f, + -0.00567626953124999910f, -0.01855468750000000000f, + -0.00479125976562500000f, 0.00485229492187500000f, + 0.00036621093750000000f, 0.00848388671875000000f, + 0.00747680664062500000f, 0.00936889648437500000f, + 0.00076293945312500000f, -0.00570678710937500090f, + -0.00048828125000000000f, 0.00167846679687500000f, + 0.00091552734374999989f, -0.00497436523437500000f, + 0.01672363281250000000f, -0.00936889648437500000f, + 0.00323486328125000000f, -0.00015258789062500000f, + 0.00082397460937500000f, 0.01007080078124999800f, + -0.01269531250000000200f, 0.01449584960937500000f, + 0.01336669921875000200f, -0.00717163085937500000f, + 0.00317382812500000040f, 0.00418090820312500000f, + 0.00064086914062500000f, -0.00015258789062500000f, + -0.00915527343750000000f, -0.01428222656250000000f, + 0.01589965820312500000f, -0.01058959960937500000f, + 0.00518798828125000000f, -0.00610351562500000000f, + -0.00668334960937500090f, 0.00939941406250000000f, + -0.00372314453125000000f, -0.00405883789062500000f, + 0.00668334960937500090f, -0.00048828125000000000f, + 0.01095581054687500000f, 0.01257324218750000000f, + -0.00271606445312500000f, -0.00338745117187500000f, + 0.00146484375000000000f, 0.00982666015625000000f, + 0.00433349609375000000f, 0.00540161132812500090f, + -0.00872802734375000000f, -0.00387573242187500000f, + -0.00119018554687500000f, -0.00192260742187500000f, + -0.00128173828125000000f, -0.01376342773437500000f, + 0.00488281250000000000f, 0.00939941406250000000f, + -0.00173950195312500000f, 0.00588989257812500000f, + -0.00146484375000000000f, 0.00225830078125000000f, + -0.01055908203125000000f, 0.00180053710937500000f, + -0.00082397460937500000f, 0.00082397460937500000f, + -0.01431274414062499800f, -0.00845336914062500000f, + -0.01049804687500000000f, 0.00860595703125000000f, + 0.00799560546875000000f, 0.00372314453125000000f, + 0.00521850585937500000f, -0.00759887695312500000f, + 0.00082397460937500000f, 0.00787353515625000000f, + 0.00573730468750000000f, -0.00009155273437500000f, + 0.00204467773437500000f, -0.00628662109375000000f, + -0.00866699218750000000f, 0.00888061523437500000f, + -0.00357055664062500000f, -0.00268554687499999960f, + -0.01455688476562500000f, 0.01144409179687500000f, + 0.00152587890625000000f, 0.00323486328125000000f, + 0.00302124023437500040f, -0.00555419921875000000f, + 0.01336669921875000200f, -0.01147460937500000000f, + -0.01223754882812500000f, -0.00149536132812500000f, + 0.00363159179687500000f, -0.00070190429687500000f, + -0.00030517578125000000f, -0.00146484375000000000f, + -0.00354003906250000000f, -0.00610351562500000000f, + -0.00946044921875000000f, 0.00369262695312500000f, + 0.00222778320312500000f, 0.00021362304687500000f, + 0.00723266601562500000f, -0.00689697265625000000f, + 0.00424194335937500000f, -0.01391601562500000000f, + 0.01211547851562500000f, 0.00106811523437500000f, + 0.00009155273437500000f, -0.00329589843750000000f, + 0.00985717773437500000f, -0.00228881835937500000f, + 0.01013183593750000200f, 0.00604248046875000090f, + -0.00302124023437500040f, -0.00064086914062500000f +}; + +const SKP_Silk_NLSF_CBS_FLP SKP_Silk_NLSF_CB1_10_Stage_info_FLP[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates[ 64 ] } +}; + +const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB1_10_FLP = +{ + NLSF_MSVQ_CB1_10_STAGES, + SKP_Silk_NLSF_CB1_10_Stage_info_FLP, + SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.c new file mode 100755 index 0000000..b02f34d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.c @@ -0,0 +1,704 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.29 + 3.57 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB1_16.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ NLSF_MSVQ_CB1_16_VECTORS + NLSF_MSVQ_CB1_16_STAGES ] = +{ + 0, + 19099, + 26957, + 30639, + 34242, + 37546, + 40447, + 43287, + 46005, + 48445, + 49865, + 51284, + 52673, + 53975, + 55221, + 56441, + 57267, + 58025, + 58648, + 59232, + 59768, + 60248, + 60729, + 61210, + 61690, + 62171, + 62651, + 63132, + 63613, + 64093, + 64574, + 65054, + 65535, + 0, + 28808, + 38775, + 46801, + 51785, + 55886, + 59410, + 62572, + 65535, + 0, + 27376, + 38639, + 45052, + 51465, + 55448, + 59021, + 62594, + 65535, + 0, + 33403, + 39569, + 45102, + 49961, + 54047, + 57959, + 61788, + 65535, + 0, + 25851, + 43356, + 47828, + 52204, + 55964, + 59413, + 62507, + 65535, + 0, + 34277, + 40337, + 45432, + 50311, + 54326, + 58171, + 61853, + 65535, + 0, + 33538, + 39865, + 45302, + 50076, + 54549, + 58478, + 62159, + 65535, + 0, + 27445, + 35258, + 40665, + 46072, + 51362, + 56540, + 61086, + 65535, + 0, + 22080, + 30779, + 37065, + 43085, + 48849, + 54613, + 60133, + 65535, + 0, + 13417, + 21748, + 30078, + 38231, + 46383, + 53091, + 59515, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 33 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 42 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 51 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 60 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 69 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 78 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 87 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 96 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 105 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + 5, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 4 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 57, 98, + 133, 134, + 138, 144, + 145, 147, + 152, 177, + 177, 178, + 181, 183, + 184, 202, + 206, 215, + 218, 222, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 38, 87, + 97, 119, + 128, 135, + 140, 143, + 40, 81, + 107, 107, + 129, 134, + 134, 143, + 31, 109, + 114, 120, + 128, 130, + 131, 132, + 43, 61, + 124, 125, + 132, 136, + 141, 142, + 30, 110, + 118, 120, + 129, 131, + 133, 133, + 31, 108, + 115, 121, + 124, 130, + 133, 137, + 40, 98, + 115, 115, + 116, 117, + 123, 124, + 50, 93, + 108, 110, + 112, 112, + 114, 115, + 73, 95, + 95, 96, + 96, 105, + 107, 110 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min_Q15[ 16 + 1 ] = +{ + 148, + 3, + 60, + 68, + 117, + 86, + 121, + 124, + 152, + 153, + 207, + 151, + 225, + 239, + 126, + 183, + 792 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 1309, 3060, 5071, 6996, + 9028, 10938, 12934, 14891, + 16933, 18854, 20792, 22764, + 24753, 26659, 28626, 30501, + 1264, 2745, 4610, 6408, + 8286, 10043, 12084, 14108, + 16118, 18163, 20095, 22164, + 24264, 26316, 28329, 30251, + 1044, 2080, 3672, 5179, + 7140, 9100, 11070, 13065, + 15423, 17790, 19931, 22101, + 24290, 26361, 28499, 30418, + 1131, 2476, 4478, 6149, + 7902, 9875, 11938, 13809, + 15869, 17730, 19948, 21707, + 23761, 25535, 27426, 28917, + 1040, 2004, 4026, 6100, + 8432, 10494, 12610, 14694, + 16797, 18775, 20799, 22782, + 24772, 26682, 28631, 30516, + 2310, 3812, 5913, 7933, + 10033, 11881, 13885, 15798, + 17751, 19576, 21482, 23276, + 25157, 27010, 28833, 30623, + 1254, 2847, 5013, 6781, + 8626, 10370, 12726, 14633, + 16281, 17852, 19870, 21472, + 23002, 24629, 26710, 27960, + 1468, 3059, 4987, 7026, + 8741, 10412, 12281, 14020, + 15970, 17723, 19640, 21522, + 23472, 25661, 27986, 30225, + 2171, 3566, 5605, 7384, + 9404, 11220, 13030, 14758, + 16687, 18417, 20346, 22091, + 24055, 26212, 28356, 30397, + 2409, 4676, 7543, 9786, + 11419, 12935, 14368, 15653, + 17366, 18943, 20762, 22477, + 24440, 26327, 28284, 30242, + 2354, 4222, 6820, 9107, + 11596, 13934, 15973, 17682, + 19158, 20517, 21991, 23420, + 25178, 26936, 28794, 30527, + 1323, 2414, 4184, 6039, + 7534, 9398, 11099, 13097, + 14799, 16451, 18434, 20887, + 23490, 25838, 28046, 30225, + 1361, 3243, 6048, 8511, + 11001, 13145, 15073, 16608, + 18126, 19381, 20912, 22607, + 24660, 26668, 28663, 30566, + 1216, 2648, 5901, 8422, + 10037, 11425, 12973, 14603, + 16686, 18600, 20555, 22415, + 24450, 26280, 28206, 30077, + 2417, 4048, 6316, 8433, + 10510, 12757, 15072, 17295, + 19573, 21503, 23329, 24782, + 26235, 27689, 29214, 30819, + 1012, 2345, 4991, 7377, + 9465, 11916, 14296, 16566, + 18672, 20544, 22292, 23838, + 25415, 27050, 28848, 30551, + 1937, 3693, 6267, 8019, + 10372, 12194, 14287, 15657, + 17431, 18864, 20769, 22206, + 24037, 25463, 27383, 28602, + 1969, 3305, 5017, 6726, + 8375, 9993, 11634, 13280, + 15078, 16751, 18464, 20119, + 21959, 23858, 26224, 29298, + 1198, 2647, 5428, 7423, + 9775, 12155, 14665, 16344, + 18121, 19790, 21557, 22847, + 24484, 25742, 27639, 28711, + 1636, 3353, 5447, 7597, + 9837, 11647, 13964, 16019, + 17862, 20116, 22319, 24037, + 25966, 28086, 29914, 31294, + 2676, 4105, 6378, 8223, + 10058, 11549, 13072, 14453, + 15956, 17355, 18931, 20402, + 22183, 23884, 25717, 27723, + 1373, 2593, 4449, 5633, + 7300, 8425, 9474, 10818, + 12769, 15722, 19002, 21429, + 23682, 25924, 28135, 30333, + 1596, 3183, 5378, 7164, + 8670, 10105, 11470, 12834, + 13991, 15042, 16642, 17903, + 20759, 25283, 27770, 30240, + 2037, 3987, 6237, 8117, + 9954, 12245, 14217, 15892, + 17775, 20114, 22314, 25942, + 26305, 26483, 26796, 28561, + 2181, 3858, 5760, 7924, + 10041, 11577, 13769, 15700, + 17429, 19879, 23583, 24538, + 25212, 25693, 28688, 30507, + 1992, 3882, 6474, 7883, + 9381, 12672, 14340, 15701, + 16658, 17832, 20850, 22885, + 24677, 26457, 28491, 30460, + 2391, 3988, 5448, 7432, + 11014, 12579, 13140, 14146, + 15898, 18592, 21104, 22993, + 24673, 27186, 28142, 29612, + 1713, 5102, 6989, 7798, + 8670, 10110, 12746, 14881, + 16709, 18407, 20126, 22107, + 24181, 26198, 28237, 30137, + 1612, 3617, 6148, 8359, + 9576, 11528, 14936, 17809, + 18287, 18729, 19001, 21111, + 24631, 26596, 28740, 30643, + 2266, 4168, 7862, 9546, + 9618, 9703, 10134, 13897, + 16265, 18432, 20587, 22605, + 24754, 26994, 29125, 30840, + 1840, 3917, 6272, 7809, + 9714, 11438, 13767, 15799, + 19244, 21972, 22980, 23180, + 23723, 25650, 29117, 31085, + 1458, 3612, 6008, 7488, + 9827, 11893, 14086, 15734, + 17440, 19535, 22424, 24767, + 29246, 29928, 30516, 30947, + -102, -121, -31, -6, + 5, -2, 8, -18, + -4, 6, 14, -2, + -12, -16, -12, -60, + -126, -353, -574, -677, + -657, -617, -498, -393, + -348, -277, -225, -164, + -102, -70, -31, 33, + 4, 379, 387, 551, + 605, 620, 532, 482, + 442, 454, 385, 347, + 322, 299, 266, 200, + 1168, 951, 672, 246, + 60, -161, -259, -234, + -253, -282, -203, -187, + -155, -176, -198, -178, + 10, 170, 393, 609, + 555, 208, -330, -571, + -769, -633, -319, -43, + 95, 105, 106, 116, + -152, -140, -125, 5, + 173, 274, 264, 331, + -37, -293, -609, -786, + -959, -814, -645, -238, + -91, 36, -11, -101, + -279, -227, -40, 90, + 530, 677, 890, 1104, + 999, 835, 564, 295, + -280, -364, -340, -331, + -284, 288, 761, 880, + 988, 627, 146, -226, + -203, -181, -142, 39, + 24, -26, -107, -92, + -161, -135, -131, -88, + -160, -156, -75, -43, + -36, -6, -33, 33, + -324, -415, -108, 124, + 157, 191, 203, 197, + 144, 109, 152, 176, + 190, 122, 101, 159, + 663, 668, 480, 400, + 379, 444, 446, 458, + 343, 351, 310, 228, + 133, 44, 75, 63, + -84, 39, -29, 35, + -94, -233, -261, -354, + 77, 262, -24, -145, + -333, -409, -404, -597, + -488, -300, 910, 592, + 412, 120, 130, -51, + -37, -77, -172, -181, + -159, -148, -72, -62, + 510, 516, 113, -585, + -1075, -957, -417, -195, + 9, 7, -88, -173, + -91, 54, 98, 95, + -28, 197, -527, -621, + 157, 122, -168, 147, + 309, 300, 336, 315, + 396, 408, 376, 106, + -162, -170, -315, 98, + 821, 908, 570, -33, + -312, -568, -572, -378, + -107, 23, 156, 93, + -129, -87, 20, -72, + -37, 40, 21, 27, + 48, 75, 77, 65, + 46, 71, 66, 47, + 136, 344, 236, 322, + 170, 283, 269, 291, + 162, -43, -204, -259, + -240, -305, -350, -312, + 447, 348, 345, 257, + 71, -131, -77, -190, + -202, -40, 35, 133, + 261, 365, 438, 303, + -8, 22, 140, 137, + -300, -641, -764, -268, + -23, -25, 73, -162, + -150, -212, -72, 6, + 39, 78, 104, -93, + -308, -136, 117, -71, + -513, -820, -700, -450, + -161, -23, 29, 78, + 337, 106, -406, -782, + -112, 233, 383, 62, + -126, 6, -77, -29, + -146, -123, -51, -27, + -27, -381, -641, 402, + 539, 8, -207, -366, + -36, -27, -204, -227, + -237, -189, -64, 51, + -92, -137, -281, 62, + 233, 92, 148, 294, + 363, 416, 564, 625, + 370, -36, -469, -462, + 102, 168, 32, 117, + -21, 97, 139, 89, + 104, 35, 4, 82, + 66, 58, 73, 93, + -76, -320, -236, -189, + -203, -142, -27, -73, + 9, -9, -25, 12, + -15, 4, 4, -50, + 314, 180, 162, -49, + 199, -108, -227, -66, + -447, -67, -264, -394, + 5, 55, -133, -176, + -116, -241, 272, 109, + 282, 262, 192, -64, + -392, -514, 156, 203, + 154, 72, -34, -160, + -73, 3, -33, -431, + 321, 18, -567, -590, + -108, 88, 66, 51, + -31, -193, -46, 65, + -29, -23, 215, -31, + 101, -113, 32, 304, + 88, 320, 448, 5, + -439, -562, -508, -135, + -13, -171, -8, 182, + -99, -181, -149, 376, + 476, 64, -396, -652, + -150, 176, 222, 65, + -590, 719, 271, 399, + 245, 72, -156, -152, + -176, 59, 94, 125, + -9, -7, 9, 1, + -61, -116, -82, 1, + 79, 22, -44, -15, + -48, -65, -62, -101, + -102, -54, -70, -78, + -80, -25, 398, 71, + 139, 38, 90, 194, + 222, 249, 165, 94, + 221, 262, 163, 91, + -206, 573, 200, -287, + -147, 5, -18, -85, + -74, -125, -87, 85, + 141, 4, -4, 28, + 234, 48, -150, -111, + -506, 237, -209, 345, + 94, -124, 77, 121, + 143, 12, -80, -48, + 191, 144, -93, -65, + -151, -643, 435, 106, + 87, 7, 65, 102, + 94, 68, 5, 99, + 222, 93, 94, 355, + -13, -89, -228, -503, + 287, 109, 108, 449, + 253, -29, -109, -116, + 15, -73, -20, 131, + -147, 72, 59, -150, + -594, 273, 316, 132, + 199, 106, 198, 212, + 220, 82, 45, -13, + 223, 137, 270, 38, + 252, 135, -177, -207, + -360, -102, 403, 406, + -14, 83, 64, 51, + -7, -99, -97, -88, + -124, -65, 42, 32, + 28, 29, 12, 20, + 119, -26, -212, -201, + 373, 251, 141, 103, + 36, -52, 66, 18, + -6, -95, -196, 5, + 98, -85, -108, 218, + -164, 20, 356, 172, + 37, 266, 23, 112, + -24, -99, -92, -178, + 29, -278, 388, -60, + -220, 300, -13, 154, + 191, 15, -37, -110, + -153, -150, -114, -7, + -94, -31, -62, -177, + 4, -70, 35, 453, + 147, -247, -328, 101, + 20, -114, 147, 108, + -119, -109, -102, -238, + 55, -102, 173, -89, + 129, 138, -330, -160, + 485, 154, -59, -170, + -20, -34, -261, -40, + -129, 77, -84, 69, + 83, 160, 169, 63, + -516, 30, 336, 52, + -0, -52, -124, 158, + 19, 197, -10, -375, + 405, 285, 114, -395, + -47, 196, 62, 87, + -106, -65, -75, -69, + -13, 34, 99, 59, + 83, 98, 44, 0, + 24, 18, 17, 70, + -22, 194, 208, 144, + -79, -15, 32, -104, + -28, -105, -186, -212, + -228, -79, -76, 51, + -71, 72, 118, -34, + -3, -171, 5, 2, + -108, -125, 62, -58, + 58, -121, 73, -466, + 92, 63, -94, -78, + -76, 212, 36, -225, + -71, -354, 152, 143, + -79, -246, -51, -31, + -6, -270, 240, 210, + 30, -157, -231, 74, + -146, 88, -273, 156, + 92, 56, 71, 2, + 318, 164, 32, -110, + -35, -41, -95, -106, + 11, 132, -68, 55, + 123, -83, -149, 212, + 132, 0, -194, 55, + 206, -108, -353, 289, + -195, 1, 233, -22, + -60, 20, 26, 68, + 166, 27, -58, 130, + 112, 107, 27, -165, + 115, -93, -37, 38, + 83, 483, 65, -229, + -13, 157, 85, 50, + 136, 10, 32, 83, + 82, 55, 5, -9, + -52, -78, -81, -51, + 40, 18, -127, -224, + -41, 53, -210, -113, + 24, -17, -187, -89, + 8, 121, 83, 77, + 91, -74, -35, -112, + -161, -173, 102, 132, + -125, -61, 103, -260, + 52, 166, -32, -156, + -87, -56, 60, -70, + -124, 242, 114, -251, + -166, 201, 127, 28, + -11, 23, -80, -115, + -20, -51, -348, 340, + -34, 133, 13, 92, + -124, -136, -120, -26, + -6, 17, 28, 21, + 120, -168, 160, -35, + 115, 28, 9, 7, + -56, 39, 156, 256, + -18, 1, 277, 82, + -70, -144, -88, -13, + -59, -157, 8, -134, + 21, -40, 58, -21, + 194, -276, 97, 279, + -56, -140, 125, 57, + -184, -204, -70, -2, + 128, -202, -78, 230, + -23, 161, -102, 1, + 1, 180, -31, -86, + -167, -57, -60, 27, + -13, 99, 108, 111, + 76, 69, 34, -21, + 53, 38, 34, 78, + 73, 219, 51, 15, + -72, -103, -207, 30, + 213, -14, 31, -94, + -40, -144, 67, 4, + 105, 59, -240, 25, + 244, 69, 58, 23, + -24, -5, -15, -133, + -71, -67, 181, 29, + -45, 121, 96, 51, + -72, -53, 56, -153, + -27, 85, 183, 211, + 105, -34, -46, 43, + -72, -93, 36, -128, + 29, 111, -95, -156, + -179, -235, 21, -39, + -71, -33, -61, -252, + 230, -131, 157, -21, + -85, -28, -123, 80, + -160, 63, 47, -6, + -49, -96, -19, 17, + -58, 17, -0, -13, + -170, 25, -35, 59, + 10, -31, -413, 81, + 62, 18, -164, 245, + 92, -165, 42, 26, + 126, -248, 193, -55, + 16, 39, 14, 50 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB1_16_Stage_info[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 72 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 72 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 80 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 88 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 96 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 96 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB1_16 = +{ + NLSF_MSVQ_CB1_16_STAGES, + SKP_Silk_NLSF_CB1_16_Stage_info, + SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.h new file mode 100755 index 0000000..657f6a9 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TABLES_NLSF_CB1_16_H +#define SKP_SILK_TABLES_NLSF_CB1_16_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB1_16_STAGES 10 +#define NLSF_MSVQ_CB1_16_VECTORS 104 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ NLSF_MSVQ_CB1_16_VECTORS + NLSF_MSVQ_CB1_16_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr[ NLSF_MSVQ_CB1_16_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx[ NLSF_MSVQ_CB1_16_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16_FLP.c new file mode 100755 index 0000000..f9a820f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_NLSF_CB1_16_FLP.c @@ -0,0 +1,973 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 7.14 kB */ +/**********************************************/ + +#include "SKP_Silk_tables_FLP.h" +#include "SKP_Silk_tables_NLSF_CB1_16.h" + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_16_rates[ NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 1.78125000000000000000f, 3.06250000000000000000f, + 4.15625000000000000000f, 4.18750000000000000000f, + 4.31250000000000000000f, 4.50000000000000000000f, + 4.53125000000000000000f, 4.59375000000000000000f, + 4.75000000000000000000f, 5.53125000000000000000f, + 5.53125000000000000000f, 5.56250000000000000000f, + 5.65625000000000000000f, 5.71875000000000000000f, + 5.75000000000000000000f, 6.31250000000000000000f, + 6.43750000000000000000f, 6.71875000000000000000f, + 6.81250000000000000000f, 6.93750000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 7.09375000000000000000f, 7.09375000000000000000f, + 1.18750000000000000000f, 2.71875000000000000000f, + 3.03125000000000000000f, 3.71875000000000000000f, + 4.00000000000000000000f, 4.21875000000000000000f, + 4.37500000000000000000f, 4.46875000000000000000f, + 1.25000000000000000000f, 2.53125000000000000000f, + 3.34375000000000000000f, 3.34375000000000000000f, + 4.03125000000000000000f, 4.18750000000000000000f, + 4.18750000000000000000f, 4.46875000000000000000f, + 0.96875000000000000000f, 3.40625000000000000000f, + 3.56250000000000000000f, 3.75000000000000000000f, + 4.00000000000000000000f, 4.06250000000000000000f, + 4.09375000000000000000f, 4.12500000000000000000f, + 1.34375000000000000000f, 1.90625000000000000000f, + 3.87500000000000000000f, 3.90625000000000000000f, + 4.12500000000000000000f, 4.25000000000000000000f, + 4.40625000000000000000f, 4.43750000000000000000f, + 0.93750000000000000000f, 3.43750000000000000000f, + 3.68750000000000000000f, 3.75000000000000000000f, + 4.03125000000000000000f, 4.09375000000000000000f, + 4.15625000000000000000f, 4.15625000000000000000f, + 0.96875000000000000000f, 3.37500000000000000000f, + 3.59375000000000000000f, 3.78125000000000000000f, + 3.87500000000000000000f, 4.06250000000000000000f, + 4.15625000000000000000f, 4.28125000000000000000f, + 1.25000000000000000000f, 3.06250000000000000000f, + 3.59375000000000000000f, 3.59375000000000000000f, + 3.62500000000000000000f, 3.65625000000000000000f, + 3.84375000000000000000f, 3.87500000000000000000f, + 1.56250000000000000000f, 2.90625000000000000000f, + 3.37500000000000000000f, 3.43750000000000000000f, + 3.50000000000000000000f, 3.50000000000000000000f, + 3.56250000000000000000f, 3.59375000000000000000f, + 2.28125000000000000000f, 2.96875000000000000000f, + 2.96875000000000000000f, 3.00000000000000000000f, + 3.00000000000000000000f, 3.28125000000000000000f, + 3.34375000000000000000f, 3.43750000000000000000f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min[ 16 + 1 ] = +{ + 0.00451660156250000000f, + 0.00009155273437500000f, + 0.00183105468749999980f, + 0.00207519531250000000f, + 0.00357055664062500000f, + 0.00262451171875000000f, + 0.00369262695312500000f, + 0.00378417968750000000f, + 0.00463867187500000000f, + 0.00466918945312500000f, + 0.00631713867187499910f, + 0.00460815429687500000f, + 0.00686645507812500000f, + 0.00729370117187499910f, + 0.00384521484375000000f, + 0.00558471679687500000f, + 0.02416992187500000300f +}; + +const SKP_float SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 0.03994750976562499300f, 0.09338378906250000000f, + 0.15475463867187500000f, 0.21350097656250000000f, + 0.27551269531250000000f, 0.33380126953125000000f, + 0.39471435546875000000f, 0.45443725585937500000f, + 0.51675415039062500000f, 0.57537841796875000000f, + 0.63452148437500000000f, 0.69470214843750000000f, + 0.75540161132812500000f, 0.81356811523437500000f, + 0.87359619140625000000f, 0.93081665039062500000f, + 0.03857421875000000000f, 0.08377075195312498600f, + 0.14068603515625000000f, 0.19555664062500000000f, + 0.25286865234375000000f, 0.30648803710937500000f, + 0.36877441406250000000f, 0.43054199218750000000f, + 0.49188232421875006000f, 0.55429077148437500000f, + 0.61325073242187500000f, 0.67639160156250000000f, + 0.74047851562500000000f, 0.80310058593750000000f, + 0.86453247070312500000f, 0.92318725585937500000f, + 0.03186035156250000000f, 0.06347656250000000000f, + 0.11206054687500000000f, 0.15805053710937500000f, + 0.21789550781250003000f, 0.27770996093750000000f, + 0.33782958984375000000f, 0.39871215820312494000f, + 0.47067260742187500000f, 0.54290771484375000000f, + 0.60824584960937500000f, 0.67446899414062500000f, + 0.74127197265625000000f, 0.80447387695312500000f, + 0.86972045898437500000f, 0.92828369140625000000f, + 0.03451538085937500000f, 0.07556152343750000000f, + 0.13665771484375000000f, 0.18765258789062500000f, + 0.24114990234375000000f, 0.30136108398437500000f, + 0.36431884765624994000f, 0.42141723632812500000f, + 0.48428344726562500000f, 0.54107666015625000000f, + 0.60876464843750000000f, 0.66244506835937500000f, + 0.72512817382812500000f, 0.77926635742187500000f, + 0.83697509765625000000f, 0.88247680664062500000f, + 0.03173828125000000000f, 0.06115722656250000000f, + 0.12286376953125000000f, 0.18615722656250000000f, + 0.25732421875000000000f, 0.32025146484375000000f, + 0.38482666015625000000f, 0.44842529296875000000f, + 0.51260375976562500000f, 0.57296752929687500000f, + 0.63473510742187500000f, 0.69525146484375000000f, + 0.75598144531250000000f, 0.81427001953125000000f, + 0.87374877929687511000f, 0.93127441406250000000f, + 0.07049560546875000000f, 0.11633300781250001000f, + 0.18045043945312497000f, 0.24209594726562500000f, + 0.30618286132812500000f, 0.36257934570312500000f, + 0.42373657226562500000f, 0.48211669921875000000f, + 0.54171752929687500000f, 0.59741210937500000000f, + 0.65557861328125000000f, 0.71032714843750000000f, + 0.76773071289062500000f, 0.82427978515624989000f, + 0.87991333007812500000f, 0.93453979492187500000f, + 0.03826904296875000000f, 0.08688354492187500000f, + 0.15298461914062500000f, 0.20693969726562500000f, + 0.26324462890625000000f, 0.31646728515625000000f, + 0.38836669921875000000f, 0.44656372070312500000f, + 0.49685668945312494000f, 0.54479980468750000000f, + 0.60638427734375000000f, 0.65527343749999989000f, + 0.70196533203124989000f, 0.75161743164062500000f, + 0.81512451171875000000f, 0.85327148437500000000f, + 0.04479980468750000000f, 0.09335327148437500000f, + 0.15219116210937500000f, 0.21441650390625000000f, + 0.26675415039062500000f, 0.31774902343750000000f, + 0.37478637695312500000f, 0.42785644531250000000f, + 0.48736572265625000000f, 0.54086303710937500000f, + 0.59936523437500000000f, 0.65679931640625000000f, + 0.71630859375000000000f, 0.78311157226562500000f, + 0.85406494140625000000f, 0.92239379882812500000f, + 0.06625366210937500000f, 0.10882568359375000000f, + 0.17105102539062497000f, 0.22534179687500000000f, + 0.28698730468750000000f, 0.34240722656249994000f, + 0.39764404296875000000f, 0.45037841796875000000f, + 0.50924682617187500000f, 0.56204223632812500000f, + 0.62091064453125000000f, 0.67416381835937511000f, + 0.73410034179687489000f, 0.79992675781250000000f, + 0.86535644531250000000f, 0.92764282226562500000f, + 0.07351684570312500000f, 0.14270019531250000000f, + 0.23019409179687497000f, 0.29864501953125000000f, + 0.34848022460937500000f, 0.39474487304687500000f, + 0.43847656250000006000f, 0.47769165039062500000f, + 0.52996826171875000000f, 0.57809448242187500000f, + 0.63360595703125000000f, 0.68594360351562511000f, + 0.74584960937500000000f, 0.80343627929687500000f, + 0.86315917968750000000f, 0.92291259765625000000f, + 0.07183837890625000000f, 0.12884521484375000000f, + 0.20812988281250003000f, 0.27792358398437500000f, + 0.35388183593749994000f, 0.42523193359375000000f, + 0.48745727539062494000f, 0.53961181640625000000f, + 0.58465576171875000000f, 0.62612915039062500000f, + 0.67111206054687500000f, 0.71472167968750000000f, + 0.76837158203125000000f, 0.82202148437499989000f, + 0.87872314453125000000f, 0.93161010742187511000f, + 0.04037475585937500000f, 0.07366943359375000000f, + 0.12768554687500000000f, 0.18429565429687500000f, + 0.22991943359375000000f, 0.28680419921875000000f, + 0.33871459960937500000f, 0.39968872070312500000f, + 0.45162963867187500000f, 0.50204467773437500000f, + 0.56256103515625000000f, 0.63742065429687500000f, + 0.71685791015624989000f, 0.78851318359375011000f, + 0.85589599609374989000f, 0.92239379882812500000f, + 0.04153442382812500700f, 0.09896850585937500000f, + 0.18457031250000000000f, 0.25973510742187500000f, + 0.33572387695312500000f, 0.40115356445312500000f, + 0.45999145507812500000f, 0.50683593750000000000f, + 0.55316162109375000000f, 0.59146118164062500000f, + 0.63818359375000000000f, 0.68991088867187500000f, + 0.75256347656250011000f, 0.81384277343750000000f, + 0.87472534179687500000f, 0.93280029296875000000f, + 0.03710937500000000000f, 0.08081054687500000000f, + 0.18008422851562503000f, 0.25701904296875000000f, + 0.30630493164062500000f, 0.34866333007812500000f, + 0.39590454101562500000f, 0.44564819335937500000f, + 0.50921630859375000000f, 0.56762695312500000000f, + 0.62728881835937500000f, 0.68405151367187500000f, + 0.74615478515625000000f, 0.80200195312500000000f, + 0.86077880859375000000f, 0.91787719726562500000f, + 0.07376098632812500000f, 0.12353515625000000000f, + 0.19274902343750000000f, 0.25735473632812500000f, + 0.32073974609375000000f, 0.38931274414062494000f, + 0.45996093750000006000f, 0.52780151367187500000f, + 0.59732055664062500000f, 0.65621948242187489000f, + 0.71194458007812500000f, 0.75628662109375011000f, + 0.80062866210937489000f, 0.84500122070312500000f, + 0.89154052734375000000f, 0.94052124023437500000f, + 0.03088378906250000000f, 0.07156372070312500000f, + 0.15231323242187500000f, 0.22512817382812503000f, + 0.28884887695312500000f, 0.36364746093750000000f, + 0.43627929687500000000f, 0.50555419921875000000f, + 0.56982421875000000000f, 0.62695312500000000000f, + 0.68029785156250000000f, 0.72747802734375000000f, + 0.77560424804687511000f, 0.82550048828125011000f, + 0.88037109375000000000f, 0.93234252929687500000f, + 0.05911254882812500000f, 0.11270141601562500000f, + 0.19125366210937500000f, 0.24472045898437500000f, + 0.31652832031250000000f, 0.37213134765625000000f, + 0.43600463867187494000f, 0.47781372070312500000f, + 0.53195190429687500000f, 0.57568359375000000000f, + 0.63381958007812500000f, 0.67767333984375000000f, + 0.73355102539062500000f, 0.77706909179687489000f, + 0.83566284179687500000f, 0.87286376953125000000f, + 0.06008911132812500000f, 0.10086059570312500000f, + 0.15310668945312500000f, 0.20526123046875000000f, + 0.25558471679687500000f, 0.30496215820312500000f, + 0.35504150390625000000f, 0.40527343750000000000f, + 0.46014404296875000000f, 0.51119995117187500000f, + 0.56347656250000000000f, 0.61398315429687500000f, + 0.67013549804687500000f, 0.72808837890625000000f, + 0.80029296875000011000f, 0.89410400390625011000f, + 0.03656005859375000000f, 0.08078002929687500000f, + 0.16564941406250000000f, 0.22653198242187500000f, + 0.29830932617187500000f, 0.37094116210937500000f, + 0.44754028320312500000f, 0.49877929687500000000f, + 0.55300903320312500000f, 0.60394287109375000000f, + 0.65786743164062489000f, 0.69723510742187500000f, + 0.74719238281250011000f, 0.78558349609375000000f, + 0.84347534179687500000f, 0.87619018554687500000f, + 0.04992675781250000000f, 0.10232543945312500000f, + 0.16622924804687500000f, 0.23184204101562503000f, + 0.30020141601562500000f, 0.35543823242187500000f, + 0.42614746093750000000f, 0.48886108398437500000f, + 0.54510498046875000000f, 0.61389160156250000000f, + 0.68112182617187500000f, 0.73355102539062500000f, + 0.79241943359375000000f, 0.85711669921875011000f, + 0.91290283203125011000f, 0.95501708984375000000f, + 0.08166503906250000000f, 0.12527465820312500000f, + 0.19464111328125000000f, 0.25094604492187500000f, + 0.30694580078125000000f, 0.35244750976562500000f, + 0.39892578124999994000f, 0.44107055664062494000f, + 0.48693847656249994000f, 0.52963256835937500000f, + 0.57772827148437500000f, 0.62261962890625000000f, + 0.67697143554687500000f, 0.72888183593750000000f, + 0.78482055664062500000f, 0.84603881835937500000f, + 0.04190063476562500000f, 0.07913208007812500000f, + 0.13577270507812500000f, 0.17190551757812500000f, + 0.22277832031250000000f, 0.25711059570312500000f, + 0.28912353515625000000f, 0.33013916015625000000f, + 0.38967895507812500000f, 0.47979736328125006000f, + 0.57989501953125000000f, 0.65396118164062500000f, + 0.72271728515625000000f, 0.79113769531250000000f, + 0.85861206054687500000f, 0.92568969726562500000f, + 0.04870605468750000000f, 0.09713745117187500000f, + 0.16412353515625003000f, 0.21862792968750000000f, + 0.26458740234375000000f, 0.30838012695312500000f, + 0.35003662109375000000f, 0.39166259765625000000f, + 0.42697143554687500000f, 0.45904541015624994000f, + 0.50787353515625000000f, 0.54635620117187500000f, + 0.63351440429687500000f, 0.77157592773437500000f, + 0.84747314453125000000f, 0.92285156249999989000f, + 0.06216430664062500000f, 0.12167358398437500000f, + 0.19033813476562500000f, 0.24771118164062500000f, + 0.30377197265625000000f, 0.37368774414062500000f, + 0.43386840820312500000f, 0.48498535156250000000f, + 0.54244995117187500000f, 0.61383056640625000000f, + 0.68096923828125000000f, 0.79168701171875000000f, + 0.80276489257812500000f, 0.80819702148437500000f, + 0.81774902343750000000f, 0.87161254882812500000f, + 0.06655883789062500000f, 0.11773681640625000000f, + 0.17578125000000000000f, 0.24182128906250000000f, + 0.30642700195312500000f, 0.35330200195312500000f, + 0.42019653320312494000f, 0.47912597656250000000f, + 0.53189086914062500000f, 0.60665893554687500000f, + 0.71969604492187500000f, 0.74884033203125000000f, + 0.76940917968750000000f, 0.78408813476562511000f, + 0.87548828125000000000f, 0.93099975585937489000f, + 0.06079101562500000000f, 0.11846923828125000000f, + 0.19757080078125000000f, 0.24057006835937503000f, + 0.28628540039062500000f, 0.38671875000000006000f, + 0.43762207031250000000f, 0.47915649414062500000f, + 0.50836181640625000000f, 0.54418945312500000000f, + 0.63629150390625000000f, 0.69839477539062500000f, + 0.75308227539062511000f, 0.80740356445312500000f, + 0.86947631835937500000f, 0.92956542968750000000f, + 0.07296752929687500000f, 0.12170410156250000000f, + 0.16625976562500000000f, 0.22680664062500000000f, + 0.33612060546875000000f, 0.38388061523437500000f, + 0.40100097656250000000f, 0.43170166015625000000f, + 0.48516845703125006000f, 0.56738281250000000000f, + 0.64404296875000000000f, 0.70169067382812500000f, + 0.75296020507812500000f, 0.82965087890624989000f, + 0.85882568359375000000f, 0.90368652343750000000f, + 0.05227661132812500000f, 0.15570068359375000000f, + 0.21328735351562500000f, 0.23797607421875000000f, + 0.26458740234375000000f, 0.30853271484375000000f, + 0.38897705078125000000f, 0.45413208007812500000f, + 0.50991821289062500000f, 0.56173706054687500000f, + 0.61419677734375000000f, 0.67465209960937500000f, + 0.73794555664062500000f, 0.79949951171874989000f, + 0.86172485351562500000f, 0.91970825195312500000f, + 0.04919433593750000000f, 0.11038208007812500000f, + 0.18762207031250000000f, 0.25509643554687500000f, + 0.29223632812500000000f, 0.35180664062500006000f, + 0.45581054687500000000f, 0.54348754882812500000f, + 0.55807495117187500000f, 0.57156372070312500000f, + 0.57986450195312500000f, 0.64425659179687500000f, + 0.75167846679687500000f, 0.81164550781250000000f, + 0.87707519531250000000f, 0.93515014648437500000f, + 0.06915283203125000000f, 0.12719726562500000000f, + 0.23992919921875000000f, 0.29132080078125000000f, + 0.29351806640625000000f, 0.29611206054687500000f, + 0.30926513671875000000f, 0.42410278320312500000f, + 0.49636840820312500000f, 0.56250000000000000000f, + 0.62826538085937500000f, 0.68984985351562500000f, + 0.75543212890625000000f, 0.82379150390625000000f, + 0.88882446289062511000f, 0.94116210937500000000f, + 0.05615234375000000700f, 0.11953735351562501000f, + 0.19140625000000000000f, 0.23831176757812500000f, + 0.29644775390625000000f, 0.34906005859375000000f, + 0.42013549804687500000f, 0.48214721679687500000f, + 0.58728027343750000000f, 0.67053222656250000000f, + 0.70129394531250000000f, 0.70739746093750000000f, + 0.72396850585937489000f, 0.78277587890625000000f, + 0.88858032226562500000f, 0.94863891601562500000f, + 0.04449462890625000000f, 0.11022949218750000000f, + 0.18334960937500000000f, 0.22851562500000000000f, + 0.29989624023437500000f, 0.36294555664062500000f, + 0.42987060546875000000f, 0.48016357421875000000f, + 0.53222656250000000000f, 0.59616088867187500000f, + 0.68432617187500000000f, 0.75582885742187500000f, + 0.89251708984375000000f, 0.91333007812499989000f, + 0.93127441406250000000f, 0.94442749023437489000f, + -0.00311279296875000000f, -0.00369262695312500000f, + -0.00094604492187500000f, -0.00018310546875000000f, + 0.00015258789062500000f, -0.00006103515625000000f, + 0.00024414062500000000f, -0.00054931640625000000f, + -0.00012207031250000000f, 0.00018310546875000000f, + 0.00042724609375000000f, -0.00006103515625000000f, + -0.00036621093750000000f, -0.00048828125000000000f, + -0.00036621093750000000f, -0.00183105468749999980f, + -0.00384521484375000000f, -0.01077270507812500000f, + -0.01751708984375000000f, -0.02066040039062500000f, + -0.02005004882812500000f, -0.01882934570312500000f, + -0.01519775390625000000f, -0.01199340820312500000f, + -0.01062011718750000000f, -0.00845336914062500000f, + -0.00686645507812500000f, -0.00500488281250000000f, + -0.00311279296875000000f, -0.00213623046875000000f, + -0.00094604492187500000f, 0.00100708007812500000f, + 0.00012207031250000000f, 0.01156616210937500000f, + 0.01181030273437500000f, 0.01681518554687500000f, + 0.01846313476562500000f, 0.01892089843750000000f, + 0.01623535156250000000f, 0.01470947265625000200f, + 0.01348876953125000000f, 0.01385498046875000000f, + 0.01174926757812500200f, 0.01058959960937500000f, + 0.00982666015625000000f, 0.00912475585937500000f, + 0.00811767578125000000f, 0.00610351562500000000f, + 0.03564453125000000000f, 0.02902221679687500000f, + 0.02050781250000000000f, 0.00750732421875000000f, + 0.00183105468749999980f, -0.00491333007812500000f, + -0.00790405273437500000f, -0.00714111328125000000f, + -0.00772094726562500000f, -0.00860595703125000000f, + -0.00619506835937500000f, -0.00570678710937500090f, + -0.00473022460937500000f, -0.00537109374999999910f, + -0.00604248046875000090f, -0.00543212890625000000f, + 0.00030517578125000000f, 0.00518798828125000000f, + 0.01199340820312500000f, 0.01858520507812500000f, + 0.01693725585937500000f, 0.00634765625000000090f, + -0.01007080078124999800f, -0.01742553710937500000f, + -0.02346801757812500000f, -0.01931762695312500000f, + -0.00973510742187500000f, -0.00131225585937500000f, + 0.00289916992187500000f, 0.00320434570312500000f, + 0.00323486328125000000f, 0.00354003906250000000f, + -0.00463867187500000000f, -0.00427246093750000000f, + -0.00381469726562499960f, 0.00015258789062500000f, + 0.00527954101562500000f, 0.00836181640625000000f, + 0.00805664062500000000f, 0.01010131835937500000f, + -0.00112915039062500000f, -0.00894165039062500000f, + -0.01858520507812500000f, -0.02398681640625000000f, + -0.02926635742187500000f, -0.02484130859375000300f, + -0.01968383789062500000f, -0.00726318359375000000f, + -0.00277709960937500000f, 0.00109863281250000000f, + -0.00033569335937499995f, -0.00308227539062500000f, + -0.00851440429687500000f, -0.00692749023437500000f, + -0.00122070312500000000f, 0.00274658203125000000f, + 0.01617431640625000000f, 0.02066040039062500000f, + 0.02716064453125000000f, 0.03369140625000000000f, + 0.03048706054687500000f, 0.02548217773437500000f, + 0.01721191406250000000f, 0.00900268554687500000f, + -0.00854492187500000000f, -0.01110839843750000000f, + -0.01037597656250000000f, -0.01010131835937500000f, + -0.00866699218750000000f, 0.00878906250000000000f, + 0.02322387695312500000f, 0.02685546875000000000f, + 0.03015136718750000000f, 0.01913452148437500000f, + 0.00445556640625000000f, -0.00689697265625000000f, + -0.00619506835937500000f, -0.00552368164062500000f, + -0.00433349609375000000f, 0.00119018554687500000f, + 0.00073242187500000000f, -0.00079345703125000011f, + -0.00326538085937500000f, -0.00280761718750000000f, + -0.00491333007812500000f, -0.00411987304687500000f, + -0.00399780273437500000f, -0.00268554687499999960f, + -0.00488281250000000000f, -0.00476074218750000000f, + -0.00228881835937500000f, -0.00131225585937500000f, + -0.00109863281250000000f, -0.00018310546875000000f, + -0.00100708007812500000f, 0.00100708007812500000f, + -0.00988769531250000000f, -0.01266479492187500000f, + -0.00329589843750000000f, 0.00378417968750000000f, + 0.00479125976562500000f, 0.00582885742187500000f, + 0.00619506835937500000f, 0.00601196289062499910f, + 0.00439453125000000000f, 0.00332641601562499960f, + 0.00463867187500000000f, 0.00537109374999999910f, + 0.00579833984375000000f, 0.00372314453125000000f, + 0.00308227539062500000f, 0.00485229492187500000f, + 0.02023315429687500000f, 0.02038574218750000000f, + 0.01464843749999999800f, 0.01220703125000000000f, + 0.01156616210937500000f, 0.01354980468750000000f, + 0.01361083984375000000f, 0.01397705078124999800f, + 0.01046752929687500200f, 0.01071166992187500000f, + 0.00946044921875000000f, 0.00695800781250000000f, + 0.00405883789062500000f, 0.00134277343749999980f, + 0.00228881835937500000f, 0.00192260742187500000f, + -0.00256347656250000000f, 0.00119018554687500000f, + -0.00088500976562500000f, 0.00106811523437500000f, + -0.00286865234375000000f, -0.00711059570312500000f, + -0.00796508789062500000f, -0.01080322265625000200f, + 0.00234985351562500000f, 0.00799560546875000000f, + -0.00073242187500000000f, -0.00442504882812500000f, + -0.01016235351562500000f, -0.01248168945312500000f, + -0.01232910156250000000f, -0.01821899414062500000f, + -0.01489257812500000000f, -0.00915527343750000000f, + 0.02777099609375000000f, 0.01806640625000000000f, + 0.01257324218750000000f, 0.00366210937499999960f, + 0.00396728515625000000f, -0.00155639648437500000f, + -0.00112915039062500000f, -0.00234985351562500000f, + -0.00524902343750000000f, -0.00552368164062500000f, + -0.00485229492187500000f, -0.00451660156250000000f, + -0.00219726562500000000f, -0.00189208984375000000f, + 0.01556396484375000000f, 0.01574707031250000000f, + 0.00344848632812500000f, -0.01785278320312500000f, + -0.03280639648437500000f, -0.02920532226562500000f, + -0.01272583007812500000f, -0.00595092773437500000f, + 0.00027465820312500000f, 0.00021362304687500000f, + -0.00268554687499999960f, -0.00527954101562500000f, + -0.00277709960937500000f, 0.00164794921875000000f, + 0.00299072265625000000f, 0.00289916992187500000f, + -0.00085449218750000000f, 0.00601196289062499910f, + -0.01608276367187500000f, -0.01895141601562500000f, + 0.00479125976562500000f, 0.00372314453125000000f, + -0.00512695312500000000f, 0.00448608398437500000f, + 0.00942993164062500000f, 0.00915527343750000000f, + 0.01025390625000000000f, 0.00961303710937500000f, + 0.01208496093750000200f, 0.01245117187500000000f, + 0.01147460937500000000f, 0.00323486328125000000f, + -0.00494384765625000000f, -0.00518798828125000000f, + -0.00961303710937500000f, 0.00299072265625000000f, + 0.02505493164062499700f, 0.02770996093750000000f, + 0.01739501953125000000f, -0.00100708007812500000f, + -0.00952148437500000000f, -0.01733398437500000000f, + -0.01745605468750000000f, -0.01153564453125000000f, + -0.00326538085937500000f, 0.00070190429687500000f, + 0.00476074218750000000f, 0.00283813476562499960f, + -0.00393676757812500000f, -0.00265502929687500000f, + 0.00061035156250000000f, -0.00219726562500000000f, + -0.00112915039062500000f, 0.00122070312500000000f, + 0.00064086914062500000f, 0.00082397460937500000f, + 0.00146484375000000000f, 0.00228881835937500000f, + 0.00234985351562500000f, 0.00198364257812500000f, + 0.00140380859375000000f, 0.00216674804687500000f, + 0.00201416015625000000f, 0.00143432617187500000f, + 0.00415039062500000000f, 0.01049804687500000000f, + 0.00720214843750000000f, 0.00982666015625000000f, + 0.00518798828125000000f, 0.00863647460937500000f, + 0.00820922851562500000f, 0.00888061523437500000f, + 0.00494384765625000000f, -0.00131225585937500000f, + -0.00622558593750000000f, -0.00790405273437500000f, + -0.00732421874999999910f, -0.00930786132812500000f, + -0.01068115234374999800f, -0.00952148437500000000f, + 0.01364135742187499800f, 0.01062011718750000000f, + 0.01052856445312500000f, 0.00784301757812500000f, + 0.00216674804687500000f, -0.00399780273437500000f, + -0.00234985351562500000f, -0.00579833984375000000f, + -0.00616455078125000000f, -0.00122070312500000000f, + 0.00106811523437500000f, 0.00405883789062500000f, + 0.00796508789062500000f, 0.01113891601562500000f, + 0.01336669921875000200f, 0.00924682617187500000f, + -0.00024414062500000000f, 0.00067138671874999989f, + 0.00427246093750000000f, 0.00418090820312500000f, + -0.00915527343750000000f, -0.01956176757812500000f, + -0.02331542968750000000f, -0.00817871093750000000f, + -0.00070190429687500000f, -0.00076293945312500000f, + 0.00222778320312500000f, -0.00494384765625000000f, + -0.00457763671875000000f, -0.00646972656250000000f, + -0.00219726562500000000f, 0.00018310546875000000f, + 0.00119018554687500000f, 0.00238037109375000000f, + 0.00317382812500000040f, -0.00283813476562499960f, + -0.00939941406250000000f, -0.00415039062500000000f, + 0.00357055664062500000f, -0.00216674804687500000f, + -0.01565551757812500000f, -0.02502441406250000000f, + -0.02136230468749999700f, -0.01373291015625000000f, + -0.00491333007812500000f, -0.00070190429687500000f, + 0.00088500976562500000f, 0.00238037109375000000f, + 0.01028442382812500000f, 0.00323486328125000000f, + -0.01239013671875000000f, -0.02386474609375000000f, + -0.00341796875000000000f, 0.00711059570312500000f, + 0.01168823242187499800f, 0.00189208984375000000f, + -0.00384521484375000000f, 0.00018310546875000000f, + -0.00234985351562500000f, -0.00088500976562500000f, + -0.00445556640625000000f, -0.00375366210937500000f, + -0.00155639648437500000f, -0.00082397460937500000f, + -0.00082397460937500000f, -0.01162719726562500000f, + -0.01956176757812500000f, 0.01226806640625000000f, + 0.01644897460937500000f, 0.00024414062500000000f, + -0.00631713867187499910f, -0.01116943359375000000f, + -0.00109863281250000000f, -0.00082397460937500000f, + -0.00622558593750000000f, -0.00692749023437500000f, + -0.00723266601562500000f, -0.00576782226562500000f, + -0.00195312500000000000f, 0.00155639648437500000f, + -0.00280761718750000000f, -0.00418090820312500000f, + -0.00857543945312500000f, 0.00189208984375000000f, + 0.00711059570312500000f, 0.00280761718750000000f, + 0.00451660156250000000f, 0.00897216796875000000f, + 0.01107788085937500200f, 0.01269531250000000200f, + 0.01721191406250000000f, 0.01907348632812500000f, + 0.01129150390625000000f, -0.00109863281250000000f, + -0.01431274414062499800f, -0.01409912109375000000f, + 0.00311279296875000000f, 0.00512695312500000000f, + 0.00097656250000000000f, 0.00357055664062500000f, + -0.00064086914062500000f, 0.00296020507812500000f, + 0.00424194335937500000f, 0.00271606445312500000f, + 0.00317382812500000040f, 0.00106811523437500000f, + 0.00012207031250000000f, 0.00250244140625000000f, + 0.00201416015625000000f, 0.00177001953125000000f, + 0.00222778320312500000f, 0.00283813476562499960f, + -0.00231933593750000000f, -0.00976562500000000000f, + -0.00720214843750000000f, -0.00576782226562500000f, + -0.00619506835937500000f, -0.00433349609375000000f, + -0.00082397460937500000f, -0.00222778320312500000f, + 0.00027465820312500000f, -0.00027465820312500000f, + -0.00076293945312500000f, 0.00036621093750000000f, + -0.00045776367187499995f, 0.00012207031250000000f, + 0.00012207031250000000f, -0.00152587890625000000f, + 0.00958251953125000000f, 0.00549316406250000000f, + 0.00494384765625000000f, -0.00149536132812500000f, + 0.00607299804687500000f, -0.00329589843750000000f, + -0.00692749023437500000f, -0.00201416015625000000f, + -0.01364135742187499800f, -0.00204467773437500000f, + -0.00805664062500000000f, -0.01202392578124999800f, + 0.00015258789062500000f, 0.00167846679687500000f, + -0.00405883789062500000f, -0.00537109374999999910f, + -0.00354003906250000000f, -0.00735473632812500090f, + 0.00830078125000000000f, 0.00332641601562499960f, + 0.00860595703125000000f, 0.00799560546875000000f, + 0.00585937500000000000f, -0.00195312500000000000f, + -0.01196289062500000000f, -0.01568603515625000000f, + 0.00476074218750000000f, 0.00619506835937500000f, + 0.00469970703125000000f, 0.00219726562500000000f, + -0.00103759765625000000f, -0.00488281250000000000f, + -0.00222778320312500000f, 0.00009155273437500000f, + -0.00100708007812500000f, -0.01315307617187500000f, + 0.00979614257812500000f, 0.00054931640625000000f, + -0.01730346679687500000f, -0.01800537109375000000f, + -0.00329589843750000000f, 0.00268554687499999960f, + 0.00201416015625000000f, 0.00155639648437500000f, + -0.00094604492187500000f, -0.00588989257812500000f, + -0.00140380859375000000f, 0.00198364257812500000f, + -0.00088500976562500000f, -0.00070190429687500000f, + 0.00656127929687500000f, -0.00094604492187500000f, + 0.00308227539062500000f, -0.00344848632812500000f, + 0.00097656250000000000f, 0.00927734375000000000f, + 0.00268554687499999960f, 0.00976562500000000000f, + 0.01367187500000000000f, 0.00015258789062500000f, + -0.01339721679687500000f, -0.01715087890625000000f, + -0.01550292968750000000f, -0.00411987304687500000f, + -0.00039672851562500005f, -0.00521850585937500000f, + -0.00024414062500000000f, 0.00555419921875000000f, + -0.00302124023437500040f, -0.00552368164062500000f, + -0.00454711914062500000f, 0.01147460937500000000f, + 0.01452636718750000000f, 0.00195312500000000000f, + -0.01208496093750000200f, -0.01989746093750000000f, + -0.00457763671875000000f, 0.00537109374999999910f, + 0.00677490234375000000f, 0.00198364257812500000f, + -0.01800537109375000000f, 0.02194213867187500300f, + 0.00827026367187500000f, 0.01217651367187500000f, + 0.00747680664062500000f, 0.00219726562500000000f, + -0.00476074218750000000f, -0.00463867187500000000f, + -0.00537109374999999910f, 0.00180053710937500000f, + 0.00286865234375000000f, 0.00381469726562499960f, + -0.00027465820312500000f, -0.00021362304687500000f, + 0.00027465820312500000f, 0.00003051757812500000f, + -0.00186157226562500000f, -0.00354003906250000000f, + -0.00250244140625000000f, 0.00003051757812500000f, + 0.00241088867187500000f, 0.00067138671874999989f, + -0.00134277343749999980f, -0.00045776367187499995f, + -0.00146484375000000000f, -0.00198364257812500000f, + -0.00189208984375000000f, -0.00308227539062500000f, + -0.00311279296875000000f, -0.00164794921875000000f, + -0.00213623046875000000f, -0.00238037109375000000f, + -0.00244140625000000000f, -0.00076293945312500000f, + 0.01214599609375000000f, 0.00216674804687500000f, + 0.00424194335937500000f, 0.00115966796875000000f, + 0.00274658203125000000f, 0.00592041015625000000f, + 0.00677490234375000000f, 0.00759887695312500000f, + 0.00503540039062499910f, 0.00286865234375000000f, + 0.00674438476562500000f, 0.00799560546875000000f, + 0.00497436523437500000f, 0.00277709960937500000f, + -0.00628662109375000000f, 0.01748657226562500000f, + 0.00610351562500000000f, -0.00875854492187500000f, + -0.00448608398437500000f, 0.00015258789062500000f, + -0.00054931640625000000f, -0.00259399414062500000f, + -0.00225830078125000000f, -0.00381469726562499960f, + -0.00265502929687500000f, 0.00259399414062500000f, + 0.00430297851562500000f, 0.00012207031250000000f, + -0.00012207031250000000f, 0.00085449218750000000f, + 0.00714111328125000000f, 0.00146484375000000000f, + -0.00457763671875000000f, -0.00338745117187500000f, + -0.01544189453125000000f, 0.00723266601562500000f, + -0.00637817382812500090f, 0.01052856445312500000f, + 0.00286865234375000000f, -0.00378417968750000000f, + 0.00234985351562500000f, 0.00369262695312500000f, + 0.00436401367187500000f, 0.00036621093750000000f, + -0.00244140625000000000f, -0.00146484375000000000f, + 0.00582885742187500000f, 0.00439453125000000000f, + -0.00283813476562499960f, -0.00198364257812500000f, + -0.00460815429687500000f, -0.01962280273437500000f, + 0.01327514648437500000f, 0.00323486328125000000f, + 0.00265502929687500000f, 0.00021362304687500000f, + 0.00198364257812500000f, 0.00311279296875000000f, + 0.00286865234375000000f, 0.00207519531250000000f, + 0.00015258789062500000f, 0.00302124023437500040f, + 0.00677490234375000000f, 0.00283813476562499960f, + 0.00286865234375000000f, 0.01083374023437500000f, + -0.00039672851562500005f, -0.00271606445312500000f, + -0.00695800781250000000f, -0.01535034179687500000f, + 0.00875854492187500000f, 0.00332641601562499960f, + 0.00329589843750000000f, 0.01370239257812500200f, + 0.00772094726562500000f, -0.00088500976562500000f, + -0.00332641601562499960f, -0.00354003906250000000f, + 0.00045776367187499995f, -0.00222778320312500000f, + -0.00061035156250000000f, 0.00399780273437500000f, + -0.00448608398437500000f, 0.00219726562500000000f, + 0.00180053710937500000f, -0.00457763671875000000f, + -0.01812744140625000000f, 0.00833129882812500000f, + 0.00964355468750000000f, 0.00402832031250000000f, + 0.00607299804687500000f, 0.00323486328125000000f, + 0.00604248046875000090f, 0.00646972656250000000f, + 0.00671386718750000000f, 0.00250244140625000000f, + 0.00137329101562500000f, -0.00039672851562500005f, + 0.00680541992187500000f, 0.00418090820312500000f, + 0.00823974609375000000f, 0.00115966796875000000f, + 0.00769042968750000000f, 0.00411987304687500000f, + -0.00540161132812500090f, -0.00631713867187499910f, + -0.01098632812500000000f, -0.00311279296875000000f, + 0.01229858398437500000f, 0.01239013671875000000f, + -0.00042724609375000000f, 0.00253295898437500040f, + 0.00195312500000000000f, 0.00155639648437500000f, + -0.00021362304687500000f, -0.00302124023437500040f, + -0.00296020507812500000f, -0.00268554687499999960f, + -0.00378417968750000000f, -0.00198364257812500000f, + 0.00128173828125000000f, 0.00097656250000000000f, + 0.00085449218750000000f, 0.00088500976562500000f, + 0.00036621093750000000f, 0.00061035156250000000f, + 0.00363159179687500000f, -0.00079345703125000011f, + -0.00646972656250000000f, -0.00613403320312500000f, + 0.01138305664062500000f, 0.00765991210937500090f, + 0.00430297851562500000f, 0.00314331054687500000f, + 0.00109863281250000000f, -0.00158691406250000020f, + 0.00201416015625000000f, 0.00054931640625000000f, + -0.00018310546875000000f, -0.00289916992187500000f, + -0.00598144531250000000f, 0.00015258789062500000f, + 0.00299072265625000000f, -0.00259399414062500000f, + -0.00329589843750000000f, 0.00665283203124999910f, + -0.00500488281250000000f, 0.00061035156250000000f, + 0.01086425781250000000f, 0.00524902343750000000f, + 0.00112915039062500000f, 0.00811767578125000000f, + 0.00070190429687500000f, 0.00341796875000000000f, + -0.00073242187500000000f, -0.00302124023437500040f, + -0.00280761718750000000f, -0.00543212890625000000f, + 0.00088500976562500000f, -0.00848388671875000000f, + 0.01184082031250000000f, -0.00183105468749999980f, + -0.00671386718750000000f, 0.00915527343750000000f, + -0.00039672851562500005f, 0.00469970703125000000f, + 0.00582885742187500000f, 0.00045776367187499995f, + -0.00112915039062500000f, -0.00335693359375000000f, + -0.00466918945312500000f, -0.00457763671875000000f, + -0.00347900390625000000f, -0.00021362304687500000f, + -0.00286865234375000000f, -0.00094604492187500000f, + -0.00189208984375000000f, -0.00540161132812500090f, + 0.00012207031250000000f, -0.00213623046875000000f, + 0.00106811523437500000f, 0.01382446289062500000f, + 0.00448608398437500000f, -0.00753784179687500000f, + -0.01000976562500000000f, 0.00308227539062500000f, + 0.00061035156250000000f, -0.00347900390625000000f, + 0.00448608398437500000f, 0.00329589843750000000f, + -0.00363159179687500000f, -0.00332641601562499960f, + -0.00311279296875000000f, -0.00726318359375000000f, + 0.00167846679687500000f, -0.00311279296875000000f, + 0.00527954101562500000f, -0.00271606445312500000f, + 0.00393676757812500000f, 0.00421142578125000000f, + -0.01007080078124999800f, -0.00488281250000000000f, + 0.01480102539062500000f, 0.00469970703125000000f, + -0.00180053710937500000f, -0.00518798828125000000f, + -0.00061035156250000000f, -0.00103759765625000000f, + -0.00796508789062500000f, -0.00122070312500000000f, + -0.00393676757812500000f, 0.00234985351562500000f, + -0.00256347656250000000f, 0.00210571289062500000f, + 0.00253295898437500040f, 0.00488281250000000000f, + 0.00515747070312500000f, 0.00192260742187500000f, + -0.01574707031250000000f, 0.00091552734374999989f, + 0.01025390625000000000f, 0.00158691406250000020f, + -0.00000000000000000000f, -0.00158691406250000020f, + -0.00378417968750000000f, 0.00482177734375000000f, + 0.00057983398437500000f, 0.00601196289062499910f, + -0.00030517578125000000f, -0.01144409179687500000f, + 0.01235961914062499800f, 0.00869750976562500000f, + 0.00347900390625000000f, -0.01205444335937500000f, + -0.00143432617187500000f, 0.00598144531250000000f, + 0.00189208984375000000f, 0.00265502929687500000f, + -0.00323486328125000000f, -0.00198364257812500000f, + -0.00228881835937500000f, -0.00210571289062500000f, + -0.00039672851562500005f, 0.00103759765625000000f, + 0.00302124023437500040f, 0.00180053710937500000f, + 0.00253295898437500040f, 0.00299072265625000000f, + 0.00134277343749999980f, 0.00000000000000000000f, + 0.00073242187500000000f, 0.00054931640625000000f, + 0.00051879882812500000f, 0.00213623046875000000f, + -0.00067138671874999989f, 0.00592041015625000000f, + 0.00634765625000000090f, 0.00439453125000000000f, + -0.00241088867187500000f, -0.00045776367187499995f, + 0.00097656250000000000f, -0.00317382812500000040f, + -0.00085449218750000000f, -0.00320434570312500000f, + -0.00567626953124999910f, -0.00646972656250000000f, + -0.00695800781250000000f, -0.00241088867187500000f, + -0.00231933593750000000f, 0.00155639648437500000f, + -0.00216674804687500000f, 0.00219726562500000000f, + 0.00360107421875000000f, -0.00103759765625000000f, + -0.00009155273437500000f, -0.00521850585937500000f, + 0.00015258789062500000f, 0.00006103515625000000f, + -0.00329589843750000000f, -0.00381469726562499960f, + 0.00189208984375000000f, -0.00177001953125000000f, + 0.00177001953125000000f, -0.00369262695312500000f, + 0.00222778320312500000f, -0.01422119140625000000f, + 0.00280761718750000000f, 0.00192260742187500000f, + -0.00286865234375000000f, -0.00238037109375000000f, + -0.00231933593750000000f, 0.00646972656250000000f, + 0.00109863281250000000f, -0.00686645507812500000f, + -0.00216674804687500000f, -0.01080322265625000200f, + 0.00463867187500000000f, 0.00436401367187500000f, + -0.00241088867187500000f, -0.00750732421875000000f, + -0.00155639648437500000f, -0.00094604492187500000f, + -0.00018310546875000000f, -0.00823974609375000000f, + 0.00732421874999999910f, 0.00640869140625000000f, + 0.00091552734374999989f, -0.00479125976562500000f, + -0.00704956054687500000f, 0.00225830078125000000f, + -0.00445556640625000000f, 0.00268554687499999960f, + -0.00833129882812500000f, 0.00476074218750000000f, + 0.00280761718750000000f, 0.00170898437500000000f, + 0.00216674804687500000f, 0.00006103515625000000f, + 0.00970458984375000000f, 0.00500488281250000000f, + 0.00097656250000000000f, -0.00335693359375000000f, + -0.00106811523437500000f, -0.00125122070312500000f, + -0.00289916992187500000f, -0.00323486328125000000f, + 0.00033569335937499995f, 0.00402832031250000000f, + -0.00207519531250000000f, 0.00167846679687500000f, + 0.00375366210937500000f, -0.00253295898437500040f, + -0.00454711914062500000f, 0.00646972656250000000f, + 0.00402832031250000000f, 0.00000000000000000000f, + -0.00592041015625000000f, 0.00167846679687500000f, + 0.00628662109375000000f, -0.00329589843750000000f, + -0.01077270507812500000f, 0.00881958007812500000f, + -0.00595092773437500000f, 0.00003051757812500000f, + 0.00711059570312500000f, -0.00067138671874999989f, + -0.00183105468749999980f, 0.00061035156250000000f, + 0.00079345703125000011f, 0.00207519531250000000f, + 0.00506591796875000090f, 0.00082397460937500000f, + -0.00177001953125000000f, 0.00396728515625000000f, + 0.00341796875000000000f, 0.00326538085937500000f, + 0.00082397460937500000f, -0.00503540039062499910f, + 0.00350952148437500040f, -0.00283813476562499960f, + -0.00112915039062500000f, 0.00115966796875000000f, + 0.00253295898437500040f, 0.01473999023437500000f, + 0.00198364257812500000f, -0.00698852539062499910f, + -0.00039672851562500005f, 0.00479125976562500000f, + 0.00259399414062500000f, 0.00152587890625000000f, + 0.00415039062500000000f, 0.00030517578125000000f, + 0.00097656250000000000f, 0.00253295898437500040f, + 0.00250244140625000000f, 0.00167846679687500000f, + 0.00015258789062500000f, -0.00027465820312500000f, + -0.00158691406250000020f, -0.00238037109375000000f, + -0.00247192382812500000f, -0.00155639648437500000f, + 0.00122070312500000000f, 0.00054931640625000000f, + -0.00387573242187500000f, -0.00683593750000000000f, + -0.00125122070312500000f, 0.00161743164062500000f, + -0.00640869140625000000f, -0.00344848632812500000f, + 0.00073242187500000000f, -0.00051879882812500000f, + -0.00570678710937500090f, -0.00271606445312500000f, + 0.00024414062500000000f, 0.00369262695312500000f, + 0.00253295898437500040f, 0.00234985351562500000f, + 0.00277709960937500000f, -0.00225830078125000000f, + -0.00106811523437500000f, -0.00341796875000000000f, + -0.00491333007812500000f, -0.00527954101562500000f, + 0.00311279296875000000f, 0.00402832031250000000f, + -0.00381469726562499960f, -0.00186157226562500000f, + 0.00314331054687500000f, -0.00793457031250000000f, + 0.00158691406250000020f, 0.00506591796875000090f, + -0.00097656250000000000f, -0.00476074218750000000f, + -0.00265502929687500000f, -0.00170898437500000000f, + 0.00183105468749999980f, -0.00213623046875000000f, + -0.00378417968750000000f, 0.00738525390625000000f, + 0.00347900390625000000f, -0.00765991210937500090f, + -0.00506591796875000090f, 0.00613403320312500000f, + 0.00387573242187500000f, 0.00085449218750000000f, + -0.00033569335937499995f, 0.00070190429687500000f, + -0.00244140625000000000f, -0.00350952148437500040f, + -0.00061035156250000000f, -0.00155639648437500000f, + -0.01062011718750000000f, 0.01037597656250000000f, + -0.00103759765625000000f, 0.00405883789062500000f, + 0.00039672851562500005f, 0.00280761718750000000f, + -0.00378417968750000000f, -0.00415039062500000000f, + -0.00366210937499999960f, -0.00079345703125000011f, + -0.00018310546875000000f, 0.00051879882812500000f, + 0.00085449218750000000f, 0.00064086914062500000f, + 0.00366210937499999960f, -0.00512695312500000000f, + 0.00488281250000000000f, -0.00106811523437500000f, + 0.00350952148437500040f, 0.00085449218750000000f, + 0.00027465820312500000f, 0.00021362304687500000f, + -0.00170898437500000000f, 0.00119018554687500000f, + 0.00476074218750000000f, 0.00781250000000000000f, + -0.00054931640625000000f, 0.00003051757812500000f, + 0.00845336914062500000f, 0.00250244140625000000f, + -0.00213623046875000000f, -0.00439453125000000000f, + -0.00268554687499999960f, -0.00039672851562500005f, + -0.00180053710937500000f, -0.00479125976562500000f, + 0.00024414062500000000f, -0.00408935546875000000f, + 0.00064086914062500000f, -0.00122070312500000000f, + 0.00177001953125000000f, -0.00064086914062500000f, + 0.00592041015625000000f, -0.00842285156250000000f, + 0.00296020507812500000f, 0.00851440429687500000f, + -0.00170898437500000000f, -0.00427246093750000000f, + 0.00381469726562499960f, 0.00173950195312500000f, + -0.00561523437500000000f, -0.00622558593750000000f, + -0.00213623046875000000f, -0.00006103515625000000f, + 0.00390625000000000000f, -0.00616455078125000000f, + -0.00238037109375000000f, 0.00701904296875000090f, + -0.00070190429687500000f, 0.00491333007812500000f, + -0.00311279296875000000f, 0.00003051757812500000f, + 0.00003051757812500000f, 0.00549316406250000000f, + -0.00094604492187500000f, -0.00262451171875000000f, + -0.00509643554687500000f, -0.00173950195312500000f, + -0.00183105468749999980f, 0.00082397460937500000f, + -0.00039672851562500005f, 0.00302124023437500040f, + 0.00329589843750000000f, 0.00338745117187500000f, + 0.00231933593750000000f, 0.00210571289062500000f, + 0.00103759765625000000f, -0.00064086914062500000f, + 0.00161743164062500000f, 0.00115966796875000000f, + 0.00103759765625000000f, 0.00238037109375000000f, + 0.00222778320312500000f, 0.00668334960937500090f, + 0.00155639648437500000f, 0.00045776367187499995f, + -0.00219726562500000000f, -0.00314331054687500000f, + -0.00631713867187499910f, 0.00091552734374999989f, + 0.00650024414062500000f, -0.00042724609375000000f, + 0.00094604492187500000f, -0.00286865234375000000f, + -0.00122070312500000000f, -0.00439453125000000000f, + 0.00204467773437500000f, 0.00012207031250000000f, + 0.00320434570312500000f, 0.00180053710937500000f, + -0.00732421874999999910f, 0.00076293945312500000f, + 0.00744628906250000000f, 0.00210571289062500000f, + 0.00177001953125000000f, 0.00070190429687500000f, + -0.00073242187500000000f, -0.00015258789062500000f, + -0.00045776367187499995f, -0.00405883789062500000f, + -0.00216674804687500000f, -0.00204467773437500000f, + 0.00552368164062500000f, 0.00088500976562500000f, + -0.00137329101562500000f, 0.00369262695312500000f, + 0.00292968750000000000f, 0.00155639648437500000f, + -0.00219726562500000000f, -0.00161743164062500000f, + 0.00170898437500000000f, -0.00466918945312500000f, + -0.00082397460937500000f, 0.00259399414062500000f, + 0.00558471679687500000f, 0.00643920898437500000f, + 0.00320434570312500000f, -0.00103759765625000000f, + -0.00140380859375000000f, 0.00131225585937500000f, + -0.00219726562500000000f, -0.00283813476562499960f, + 0.00109863281250000000f, -0.00390625000000000000f, + 0.00088500976562500000f, 0.00338745117187500000f, + -0.00289916992187500000f, -0.00476074218750000000f, + -0.00546264648437500000f, -0.00717163085937500000f, + 0.00064086914062500000f, -0.00119018554687500000f, + -0.00216674804687500000f, -0.00100708007812500000f, + -0.00186157226562500000f, -0.00769042968750000000f, + 0.00701904296875000090f, -0.00399780273437500000f, + 0.00479125976562500000f, -0.00064086914062500000f, + -0.00259399414062500000f, -0.00085449218750000000f, + -0.00375366210937500000f, 0.00244140625000000000f, + -0.00488281250000000000f, 0.00192260742187500000f, + 0.00143432617187500000f, -0.00018310546875000000f, + -0.00149536132812500000f, -0.00292968750000000000f, + -0.00057983398437500000f, 0.00051879882812500000f, + -0.00177001953125000000f, 0.00051879882812500000f, + -0.00000000000000000000f, -0.00039672851562500005f, + -0.00518798828125000000f, 0.00076293945312500000f, + -0.00106811523437500000f, 0.00180053710937500000f, + 0.00030517578125000000f, -0.00094604492187500000f, + -0.01260375976562500000f, 0.00247192382812500000f, + 0.00189208984375000000f, 0.00054931640625000000f, + -0.00500488281250000000f, 0.00747680664062500000f, + 0.00280761718750000000f, -0.00503540039062499910f, + 0.00128173828125000000f, 0.00079345703125000011f, + 0.00384521484375000000f, -0.00756835937500000000f, + 0.00588989257812500000f, -0.00167846679687500000f, + 0.00048828125000000000f, 0.00119018554687500000f, + 0.00042724609375000000f, 0.00152587890625000000f +}; + +const SKP_Silk_NLSF_CBS_FLP SKP_Silk_NLSF_CB1_16_Stage_info_FLP[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 72 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 72 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 80 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 88 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16[ 16 * 96 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates[ 96 ] } +}; + +const SKP_Silk_NLSF_CB_FLP SKP_Silk_NLSF_CB1_16_FLP = +{ + NLSF_MSVQ_CB1_16_STAGES, + SKP_Silk_NLSF_CB1_16_Stage_info_FLP, + SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_gain.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_gain.c new file mode 100755 index 0000000..36cf647 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_gain.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const SKP_uint16 SKP_Silk_gain_CDF[ 2 ][ 65 ] = +{ +{ + 0, 18, 45, 94, 181, 320, 519, 777, + 1093, 1468, 1909, 2417, 2997, 3657, 4404, 5245, + 6185, 7228, 8384, 9664, 11069, 12596, 14244, 16022, + 17937, 19979, 22121, 24345, 26646, 29021, 31454, 33927, + 36438, 38982, 41538, 44068, 46532, 48904, 51160, 53265, + 55184, 56904, 58422, 59739, 60858, 61793, 62568, 63210, + 63738, 64165, 64504, 64769, 64976, 65133, 65249, 65330, + 65386, 65424, 65451, 65471, 65487, 65501, 65513, 65524, + 65535 +}, +{ + 0, 214, 581, 1261, 2376, 3920, 5742, 7632, + 9449, 11157, 12780, 14352, 15897, 17427, 18949, 20462, + 21957, 23430, 24889, 26342, 27780, 29191, 30575, 31952, + 33345, 34763, 36200, 37642, 39083, 40519, 41930, 43291, + 44602, 45885, 47154, 48402, 49619, 50805, 51959, 53069, + 54127, 55140, 56128, 57101, 58056, 58979, 59859, 60692, + 61468, 62177, 62812, 63368, 63845, 64242, 64563, 64818, + 65023, 65184, 65306, 65391, 65447, 65482, 65505, 65521, + 65535 +} +}; + +const SKP_int SKP_Silk_gain_CDF_offset = 32; + + +const SKP_uint16 SKP_Silk_delta_gain_CDF[ 46 ] = { + 0, 2358, 3856, 7023, 15376, 53058, 59135, 61555, + 62784, 63498, 63949, 64265, 64478, 64647, 64783, 64894, + 64986, 65052, 65113, 65169, 65213, 65252, 65284, 65314, + 65338, 65359, 65377, 65392, 65403, 65415, 65424, 65432, + 65440, 65448, 65455, 65462, 65470, 65477, 65484, 65491, + 65499, 65506, 65513, 65521, 65528, 65535 +}; + +const SKP_int SKP_Silk_delta_gain_CDF_offset = 5; + +#ifdef __cplusplus +} +#endif diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other.c new file mode 100755 index 0000000..0afbc72 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other.c @@ -0,0 +1,148 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_define.h" +#include "SKP_Silk_tables.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +const SKP_int32 TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = { + 0, 8000, 9000, 11000, 13000, 16000, 22000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = { + 0, 10000, 12000, 14000, 17000, 21000, 28000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = { + 0, 11000, 14000, 17000, 21000, 26000, 36000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_SWB[ TARGET_RATE_TAB_SZ ] = { + 0, 13000, 16000, 19000, 25000, 32000, 46000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = { + 19, 31, 35, 39, 43, 47, 54, 64 +}; + +const SKP_int32 SNR_table_one_bit_per_sample_Q7[ 4 ] = { + 1984, 2240, 2408, 2708 +}; + +/* Filter coeficicnts for HP filter: 4. Order filter implementad as two biquad filters */ +const SKP_int16 SKP_Silk_SWB_detect_B_HP_Q13[ NB_SOS ][ 3 ] = { + //{400, -550, 400}, {400, 130, 400}, {400, 390, 400} + {575, -948, 575}, {575, -221, 575}, {575, 104, 575} +}; +const SKP_int16 SKP_Silk_SWB_detect_A_HP_Q13[ NB_SOS ][ 2 ] = { + {14613, 6868}, {12883, 7337}, {11586, 7911} + //{14880, 6900}, {14400, 7300}, {13700, 7800} +}; + +/* Decoder high-pass filter coefficients for 24 kHz sampling, -6 dB @ 44 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_24[ DEC_HP_ORDER ] = {-16220, 8030}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_24[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 16 kHz sampling, - 6 dB @ 46 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_16[ DEC_HP_ORDER ] = {-16127, 7940}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_16[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 12 kHz sampling, -6 dB @ 44 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_12[ DEC_HP_ORDER ] = {-16043, 7859}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_12[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 8 kHz sampling, -6 dB @ 43 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_8[ DEC_HP_ORDER ] = {-15885, 7710}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_8[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* table for LSB coding */ +const SKP_uint16 SKP_Silk_lsb_CDF[ 3 ] = {0, 40000, 65535}; + +/* tables for LTPScale */ +const SKP_uint16 SKP_Silk_LTPscale_CDF[ 4 ] = {0, 32000, 48000, 65535}; +const SKP_int SKP_Silk_LTPscale_offset = 2; + +/* tables for VAD flag */ +const SKP_uint16 SKP_Silk_vadflag_CDF[ 3 ] = {0, 22000, 65535}; // 66% for speech, 33% for no speech +const SKP_int SKP_Silk_vadflag_offset = 1; + +/* tables for sampling rate */ +const SKP_int SKP_Silk_SamplingRates_table[ 4 ] = {8, 12, 16, 24}; +const SKP_uint16 SKP_Silk_SamplingRates_CDF[ 5 ] = {0, 16000, 32000, 48000, 65535}; +const SKP_int SKP_Silk_SamplingRates_offset = 2; + +/* tables for NLSF interpolation factor */ +const SKP_uint16 SKP_Silk_NLSF_interpolation_factor_CDF[ 6 ] = {0, 3706, 8703, 19226, 30926, 65535}; +const SKP_int SKP_Silk_NLSF_interpolation_factor_offset = 4; + +/* Table for frame termination indication */ +const SKP_uint16 SKP_Silk_FrameTermination_CDF[ 5 ] = {0, 20000, 45000, 56000, 65535}; +const SKP_int SKP_Silk_FrameTermination_offset = 2; + +/* Table for random seed */ +const SKP_uint16 SKP_Silk_Seed_CDF[ 5 ] = {0, 16384, 32768, 49152, 65535}; +const SKP_int SKP_Silk_Seed_offset = 2; + +/* Quantization offsets */ +const SKP_int16 SKP_Silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_VL_Q10, OFFSET_VH_Q10 }, { OFFSET_UVL_Q10, OFFSET_UVH_Q10 } +}; + +/* Table for LTPScale */ +const SKP_int16 SKP_Silk_LTPScales_table_Q14[ 3 ] = { 15565, 11469, 8192 }; + +#if SWITCH_TRANSITION_FILTERING +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const SKP_int32 SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const SKP_int32 SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other_FLP.c new file mode 100755 index 0000000..16eea19 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_other_FLP.c @@ -0,0 +1,35 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_structs_FLP.h" +#include "SKP_Silk_tables_FLP.h" + +const SKP_float SKP_Silk_HarmShapeFIR_FLP[ HARM_SHAPE_FIR_TAPS ] = { 16384.0f / 65536.0f, 32767.0f / 65536.0f, 16384.0f / 65536.0f }; + +const SKP_float SKP_Silk_Quantization_Offsets[ 2 ][ 2 ] = { + { OFFSET_VL_Q10 / 1024.0f, OFFSET_VH_Q10 / 1024.0f }, { OFFSET_UVL_Q10 / 1024.0f, OFFSET_UVH_Q10 / 1024.0f } +}; diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pitch_lag.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pitch_lag.c new file mode 100755 index 0000000..f86d2f2 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pitch_lag.c @@ -0,0 +1,199 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_pitch_lag_NB_CDF[ 8 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 194, 395, 608, 841, 1099, 1391, 1724, + 2105, 2544, 3047, 3624, 4282, 5027, 5865, 6799, + 7833, 8965, 10193, 11510, 12910, 14379, 15905, 17473, + 19065, 20664, 22252, 23814, 25335, 26802, 28206, 29541, + 30803, 31992, 33110, 34163, 35156, 36098, 36997, 37861, + 38698, 39515, 40319, 41115, 41906, 42696, 43485, 44273, + 45061, 45847, 46630, 47406, 48175, 48933, 49679, 50411, + 51126, 51824, 52502, 53161, 53799, 54416, 55011, 55584, + 56136, 56666, 57174, 57661, 58126, 58570, 58993, 59394, + 59775, 60134, 60472, 60790, 61087, 61363, 61620, 61856, + 62075, 62275, 62458, 62625, 62778, 62918, 63045, 63162, + 63269, 63368, 63459, 63544, 63623, 63698, 63769, 63836, + 63901, 63963, 64023, 64081, 64138, 64194, 64248, 64301, + 64354, 64406, 64457, 64508, 64558, 64608, 64657, 64706, + 64754, 64803, 64851, 64899, 64946, 64994, 65041, 65088, + 65135, 65181, 65227, 65272, 65317, 65361, 65405, 65449, + 65492, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_NB_CDF_offset = 43; + +const SKP_uint16 SKP_Silk_pitch_contour_NB_CDF[ 12 ] = { + 0, 14445, 18587, 25628, 30013, 34859, 40597, 48426, + 54460, 59033, 62990, 65535 +}; + +const SKP_int SKP_Silk_pitch_contour_NB_CDF_offset = 5; + +const SKP_uint16 SKP_Silk_pitch_lag_MB_CDF[ 12 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 132, 266, 402, 542, 686, 838, 997, + 1167, 1349, 1546, 1760, 1993, 2248, 2528, 2835, + 3173, 3544, 3951, 4397, 4882, 5411, 5984, 6604, + 7270, 7984, 8745, 9552, 10405, 11300, 12235, 13206, + 14209, 15239, 16289, 17355, 18430, 19507, 20579, 21642, + 22688, 23712, 24710, 25677, 26610, 27507, 28366, 29188, + 29971, 30717, 31427, 32104, 32751, 33370, 33964, 34537, + 35091, 35630, 36157, 36675, 37186, 37692, 38195, 38697, + 39199, 39701, 40206, 40713, 41222, 41733, 42247, 42761, + 43277, 43793, 44309, 44824, 45336, 45845, 46351, 46851, + 47347, 47836, 48319, 48795, 49264, 49724, 50177, 50621, + 51057, 51484, 51902, 52312, 52714, 53106, 53490, 53866, + 54233, 54592, 54942, 55284, 55618, 55944, 56261, 56571, + 56873, 57167, 57453, 57731, 58001, 58263, 58516, 58762, + 58998, 59226, 59446, 59656, 59857, 60050, 60233, 60408, + 60574, 60732, 60882, 61024, 61159, 61288, 61410, 61526, + 61636, 61742, 61843, 61940, 62033, 62123, 62210, 62293, + 62374, 62452, 62528, 62602, 62674, 62744, 62812, 62879, + 62945, 63009, 63072, 63135, 63196, 63256, 63316, 63375, + 63434, 63491, 63549, 63605, 63661, 63717, 63772, 63827, + 63881, 63935, 63988, 64041, 64094, 64147, 64199, 64252, + 64304, 64356, 64409, 64461, 64513, 64565, 64617, 64669, + 64721, 64773, 64824, 64875, 64925, 64975, 65024, 65072, + 65121, 65168, 65215, 65262, 65308, 65354, 65399, 65445, + 65490, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_MB_CDF_offset = 64; + +const SKP_uint16 SKP_Silk_pitch_lag_WB_CDF[ 16 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 106, 213, 321, 429, 539, 651, 766, + 884, 1005, 1132, 1264, 1403, 1549, 1705, 1870, + 2047, 2236, 2439, 2658, 2893, 3147, 3420, 3714, + 4030, 4370, 4736, 5127, 5546, 5993, 6470, 6978, + 7516, 8086, 8687, 9320, 9985, 10680, 11405, 12158, + 12938, 13744, 14572, 15420, 16286, 17166, 18057, 18955, + 19857, 20759, 21657, 22547, 23427, 24293, 25141, 25969, + 26774, 27555, 28310, 29037, 29736, 30406, 31048, 31662, + 32248, 32808, 33343, 33855, 34345, 34815, 35268, 35704, + 36127, 36537, 36938, 37330, 37715, 38095, 38471, 38844, + 39216, 39588, 39959, 40332, 40707, 41084, 41463, 41844, + 42229, 42615, 43005, 43397, 43791, 44186, 44583, 44982, + 45381, 45780, 46179, 46578, 46975, 47371, 47765, 48156, + 48545, 48930, 49312, 49690, 50064, 50433, 50798, 51158, + 51513, 51862, 52206, 52544, 52877, 53204, 53526, 53842, + 54152, 54457, 54756, 55050, 55338, 55621, 55898, 56170, + 56436, 56697, 56953, 57204, 57449, 57689, 57924, 58154, + 58378, 58598, 58812, 59022, 59226, 59426, 59620, 59810, + 59994, 60173, 60348, 60517, 60681, 60840, 60993, 61141, + 61284, 61421, 61553, 61679, 61800, 61916, 62026, 62131, + 62231, 62326, 62417, 62503, 62585, 62663, 62737, 62807, + 62874, 62938, 62999, 63057, 63113, 63166, 63217, 63266, + 63314, 63359, 63404, 63446, 63488, 63528, 63567, 63605, + 63642, 63678, 63713, 63748, 63781, 63815, 63847, 63879, + 63911, 63942, 63973, 64003, 64033, 64063, 64092, 64121, + 64150, 64179, 64207, 64235, 64263, 64291, 64319, 64347, + 64374, 64401, 64428, 64455, 64481, 64508, 64534, 64560, + 64585, 64610, 64635, 64660, 64685, 64710, 64734, 64758, + 64782, 64807, 64831, 64855, 64878, 64902, 64926, 64950, + 64974, 64998, 65022, 65045, 65069, 65093, 65116, 65139, + 65163, 65186, 65209, 65231, 65254, 65276, 65299, 65321, + 65343, 65364, 65386, 65408, 65429, 65450, 65471, 65493, + 65514, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_WB_CDF_offset = 86; + + +const SKP_uint16 SKP_Silk_pitch_lag_SWB_CDF[ 24 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 253, 505, 757, 1008, 1258, 1507, 1755, + 2003, 2249, 2494, 2738, 2982, 3225, 3469, 3713, + 3957, 4202, 4449, 4698, 4949, 5203, 5460, 5720, + 5983, 6251, 6522, 6798, 7077, 7361, 7650, 7942, + 8238, 8539, 8843, 9150, 9461, 9775, 10092, 10411, + 10733, 11057, 11383, 11710, 12039, 12370, 12701, 13034, + 13368, 13703, 14040, 14377, 14716, 15056, 15398, 15742, + 16087, 16435, 16785, 17137, 17492, 17850, 18212, 18577, + 18946, 19318, 19695, 20075, 20460, 20849, 21243, 21640, + 22041, 22447, 22856, 23269, 23684, 24103, 24524, 24947, + 25372, 25798, 26225, 26652, 27079, 27504, 27929, 28352, + 28773, 29191, 29606, 30018, 30427, 30831, 31231, 31627, + 32018, 32404, 32786, 33163, 33535, 33902, 34264, 34621, + 34973, 35320, 35663, 36000, 36333, 36662, 36985, 37304, + 37619, 37929, 38234, 38535, 38831, 39122, 39409, 39692, + 39970, 40244, 40513, 40778, 41039, 41295, 41548, 41796, + 42041, 42282, 42520, 42754, 42985, 43213, 43438, 43660, + 43880, 44097, 44312, 44525, 44736, 44945, 45153, 45359, + 45565, 45769, 45972, 46175, 46377, 46578, 46780, 46981, + 47182, 47383, 47585, 47787, 47989, 48192, 48395, 48599, + 48804, 49009, 49215, 49422, 49630, 49839, 50049, 50259, + 50470, 50682, 50894, 51107, 51320, 51533, 51747, 51961, + 52175, 52388, 52601, 52813, 53025, 53236, 53446, 53655, + 53863, 54069, 54274, 54477, 54679, 54879, 55078, 55274, + 55469, 55662, 55853, 56042, 56230, 56415, 56598, 56779, + 56959, 57136, 57311, 57484, 57654, 57823, 57989, 58152, + 58314, 58473, 58629, 58783, 58935, 59084, 59230, 59373, + 59514, 59652, 59787, 59919, 60048, 60174, 60297, 60417, + 60533, 60647, 60757, 60865, 60969, 61070, 61167, 61262, + 61353, 61442, 61527, 61609, 61689, 61765, 61839, 61910, + 61979, 62045, 62109, 62170, 62230, 62287, 62343, 62396, + 62448, 62498, 62547, 62594, 62640, 62685, 62728, 62770, + 62811, 62852, 62891, 62929, 62967, 63004, 63040, 63075, + 63110, 63145, 63178, 63212, 63244, 63277, 63308, 63340, + 63371, 63402, 63432, 63462, 63491, 63521, 63550, 63578, + 63607, 63635, 63663, 63690, 63718, 63744, 63771, 63798, + 63824, 63850, 63875, 63900, 63925, 63950, 63975, 63999, + 64023, 64046, 64069, 64092, 64115, 64138, 64160, 64182, + 64204, 64225, 64247, 64268, 64289, 64310, 64330, 64351, + 64371, 64391, 64411, 64431, 64450, 64470, 64489, 64508, + 64527, 64545, 64564, 64582, 64600, 64617, 64635, 64652, + 64669, 64686, 64702, 64719, 64735, 64750, 64766, 64782, + 64797, 64812, 64827, 64842, 64857, 64872, 64886, 64901, + 64915, 64930, 64944, 64959, 64974, 64988, 65003, 65018, + 65033, 65048, 65063, 65078, 65094, 65109, 65125, 65141, + 65157, 65172, 65188, 65204, 65220, 65236, 65252, 65268, + 65283, 65299, 65314, 65330, 65345, 65360, 65375, 65390, + 65405, 65419, 65434, 65449, 65463, 65477, 65492, 65506, + 65521, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_SWB_CDF_offset = 128; + + +const SKP_uint16 SKP_Silk_pitch_contour_CDF[ 35 ] = { + 0, 372, 843, 1315, 1836, 2644, 3576, 4719, + 6088, 7621, 9396, 11509, 14245, 17618, 20777, 24294, + 27992, 33116, 40100, 44329, 47558, 50679, 53130, 55557, + 57510, 59022, 60285, 61345, 62316, 63140, 63762, 64321, + 64729, 65099, 65535 +}; + +const SKP_int SKP_Silk_pitch_contour_CDF_offset = 17; + +const SKP_uint16 SKP_Silk_pitch_delta_CDF[23] = { + 0, 343, 740, 1249, 1889, 2733, 3861, 5396, + 7552, 10890, 16053, 24152, 30220, 34680, 37973, 40405, + 42243, 43708, 44823, 45773, 46462, 47055, 65535 +}; + +const SKP_int SKP_Silk_pitch_delta_CDF_offset = 11; diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pulses_per_block.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pulses_per_block.c new file mode 100755 index 0000000..cce996a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_pulses_per_block.c @@ -0,0 +1,235 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_int SKP_Silk_max_pulses_table[ 4 ] = { + 6, 8, 12, 18 +}; + +const SKP_uint16 SKP_Silk_pulses_per_block_CDF[ 10 ][ 21 ] = +{ +{ + 0, 47113, 61501, 64590, 65125, 65277, 65352, 65407, + 65450, 65474, 65488, 65501, 65508, 65514, 65516, 65520, + 65521, 65523, 65524, 65526, 65535 +}, +{ + 0, 26368, 47760, 58803, 63085, 64567, 65113, 65333, + 65424, 65474, 65498, 65511, 65517, 65520, 65523, 65525, + 65526, 65528, 65529, 65530, 65535 +}, +{ + 0, 9601, 28014, 45877, 57210, 62560, 64611, 65260, + 65447, 65500, 65511, 65519, 65521, 65525, 65526, 65529, + 65530, 65531, 65532, 65534, 65535 +}, +{ + 0, 3351, 12462, 25972, 39782, 50686, 57644, 61525, + 63521, 64506, 65009, 65255, 65375, 65441, 65471, 65488, + 65497, 65505, 65509, 65512, 65535 +}, +{ + 0, 488, 2944, 9295, 19712, 32160, 43976, 53121, + 59144, 62518, 64213, 65016, 65346, 65470, 65511, 65515, + 65525, 65529, 65531, 65534, 65535 +}, +{ + 0, 17013, 30405, 40812, 48142, 53466, 57166, 59845, + 61650, 62873, 63684, 64223, 64575, 64811, 64959, 65051, + 65111, 65143, 65165, 65183, 65535 +}, +{ + 0, 2994, 8323, 15845, 24196, 32300, 39340, 45140, + 49813, 53474, 56349, 58518, 60167, 61397, 62313, 62969, + 63410, 63715, 63906, 64056, 65535 +}, +{ + 0, 88, 721, 2795, 7542, 14888, 24420, 34593, + 43912, 51484, 56962, 60558, 62760, 64037, 64716, 65069, + 65262, 65358, 65398, 65420, 65535 +}, +{ + 0, 287, 789, 2064, 4398, 8174, 13534, 20151, + 27347, 34533, 41295, 47242, 52070, 55772, 58458, 60381, + 61679, 62533, 63109, 63519, 65535 +}, +{ + 0, 1, 3, 91, 4521, 14708, 28329, 41955, + 52116, 58375, 61729, 63534, 64459, 64924, 65092, 65164, + 65182, 65198, 65203, 65211, 65535 +} +}; + +const SKP_int SKP_Silk_pulses_per_block_CDF_offset = 6; + + +const SKP_int16 SKP_Silk_pulses_per_block_BITS_Q6[ 9 ][ 20 ] = +{ +{ + 30, 140, 282, 444, 560, 625, 654, 677, + 731, 780, 787, 844, 859, 960, 896, 1024, + 960, 1024, 960, 821 +}, +{ + 84, 103, 164, 252, 350, 442, 526, 607, + 663, 731, 787, 859, 923, 923, 960, 1024, + 960, 1024, 1024, 875 +}, +{ + 177, 117, 120, 162, 231, 320, 426, 541, + 657, 803, 832, 960, 896, 1024, 923, 1024, + 1024, 1024, 960, 1024 +}, +{ + 275, 182, 146, 144, 166, 207, 261, 322, + 388, 450, 516, 582, 637, 710, 762, 821, + 832, 896, 923, 734 +}, +{ + 452, 303, 216, 170, 153, 158, 182, 220, + 274, 337, 406, 489, 579, 681, 896, 811, + 896, 960, 923, 1024 +}, +{ + 125, 147, 170, 202, 232, 265, 295, 332, + 368, 406, 443, 483, 520, 563, 606, 646, + 704, 739, 757, 483 +}, +{ + 285, 232, 200, 190, 193, 206, 224, 244, + 266, 289, 315, 340, 367, 394, 425, 462, + 496, 539, 561, 350 +}, +{ + 611, 428, 319, 242, 202, 178, 172, 180, + 199, 229, 268, 313, 364, 422, 482, 538, + 603, 683, 739, 586 +}, +{ + 501, 450, 364, 308, 264, 231, 212, 204, + 204, 210, 222, 241, 265, 295, 326, 362, + 401, 437, 469, 321 +} +}; + +const SKP_uint16 SKP_Silk_rate_levels_CDF[ 2 ][ 10 ] = +{ +{ + 0, 2005, 12717, 20281, 31328, 36234, 45816, 57753, + 63104, 65535 +}, +{ + 0, 8553, 23489, 36031, 46295, 53519, 56519, 59151, + 64185, 65535 +} +}; + +const SKP_int SKP_Silk_rate_levels_CDF_offset = 4; + + +const SKP_int16 SKP_Silk_rate_levels_BITS_Q6[ 2 ][ 9 ] = +{ +{ + 322, 167, 199, 164, 239, 178, 157, 231, + 304 +}, +{ + 188, 137, 153, 171, 204, 285, 297, 237, + 358 +} +}; + +const SKP_uint16 SKP_Silk_shell_code_table0[ 33 ] = { + 0, 32748, 65535, 0, 9505, 56230, 65535, 0, + 4093, 32204, 61720, 65535, 0, 2285, 16207, 48750, + 63424, 65535, 0, 1709, 9446, 32026, 55752, 63876, + 65535, 0, 1623, 6986, 21845, 45381, 59147, 64186, + 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table1[ 52 ] = { + 0, 32691, 65535, 0, 12782, 52752, 65535, 0, + 4847, 32665, 60899, 65535, 0, 2500, 17305, 47989, + 63369, 65535, 0, 1843, 10329, 32419, 55433, 64277, + 65535, 0, 1485, 7062, 21465, 43414, 59079, 64623, + 65535, 0, 0, 4841, 14797, 31799, 49667, 61309, + 65535, 65535, 0, 0, 0, 8032, 21695, 41078, + 56317, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table2[ 102 ] = { + 0, 32615, 65535, 0, 14447, 50912, 65535, 0, + 6301, 32587, 59361, 65535, 0, 3038, 18640, 46809, + 62852, 65535, 0, 1746, 10524, 32509, 55273, 64278, + 65535, 0, 1234, 6360, 21259, 43712, 59651, 64805, + 65535, 0, 1020, 4461, 14030, 32286, 51249, 61904, + 65100, 65535, 0, 851, 3435, 10006, 23241, 40797, + 55444, 63009, 65252, 65535, 0, 0, 2075, 7137, + 17119, 31499, 46982, 58723, 63976, 65535, 65535, 0, + 0, 0, 3820, 11572, 23038, 37789, 51969, 61243, + 65535, 65535, 65535, 0, 0, 0, 0, 6882, + 16828, 30444, 44844, 57365, 65535, 65535, 65535, 65535, + 0, 0, 0, 0, 0, 10093, 22963, 38779, + 54426, 65535, 65535, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table3[ 207 ] = { + 0, 32324, 65535, 0, 15328, 49505, 65535, 0, + 7474, 32344, 57955, 65535, 0, 3944, 19450, 45364, + 61873, 65535, 0, 2338, 11698, 32435, 53915, 63734, + 65535, 0, 1506, 7074, 21778, 42972, 58861, 64590, + 65535, 0, 1027, 4490, 14383, 32264, 50980, 61712, + 65043, 65535, 0, 760, 3022, 9696, 23264, 41465, + 56181, 63253, 65251, 65535, 0, 579, 2256, 6873, + 16661, 31951, 48250, 59403, 64198, 65360, 65535, 0, + 464, 1783, 5181, 12269, 24247, 39877, 53490, 61502, + 64591, 65410, 65535, 0, 366, 1332, 3880, 9273, + 18585, 32014, 45928, 56659, 62616, 64899, 65483, 65535, + 0, 286, 1065, 3089, 6969, 14148, 24859, 38274, + 50715, 59078, 63448, 65091, 65481, 65535, 0, 0, + 482, 2010, 5302, 10408, 18988, 30698, 43634, 54233, + 60828, 64119, 65288, 65535, 65535, 0, 0, 0, + 1006, 3531, 7857, 14832, 24543, 36272, 47547, 56883, + 62327, 64746, 65535, 65535, 65535, 0, 0, 0, + 0, 1863, 4950, 10730, 19284, 29397, 41382, 52335, + 59755, 63834, 65535, 65535, 65535, 65535, 0, 0, + 0, 0, 0, 2513, 7290, 14487, 24275, 35312, + 46240, 55841, 62007, 65535, 65535, 65535, 65535, 65535, + 0, 0, 0, 0, 0, 0, 3606, 9573, + 18764, 28667, 40220, 51290, 59924, 65535, 65535, 65535, + 65535, 65535, 65535, 0, 0, 0, 0, 0, + 0, 0, 4879, 13091, 23376, 36061, 49395, 59315, + 65535, 65535, 65535, 65535, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table_offsets[ 19 ] = { + 0, 0, 3, 7, 12, 18, 25, 33, + 42, 52, 63, 75, 88, 102, 117, 133, + 150, 168, 187 +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_sign.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_sign.c new file mode 100755 index 0000000..c44978b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_sign.c @@ -0,0 +1,42 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_sign_CDF[ 36 ] = +{ + 37840, 36944, 36251, 35304, + 34715, 35503, 34529, 34296, + 34016, 47659, 44945, 42503, + 40235, 38569, 40254, 37851, + 37243, 36595, 43410, 44121, + 43127, 40978, 38845, 40433, + 38252, 37795, 36637, 59159, + 55630, 51806, 48073, 45036, + 48416, 43857, 42678, 41146, +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_type_offset.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_type_offset.c new file mode 100755 index 0000000..96d8926 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tables_type_offset.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_type_offset_CDF[ 5 ] = { + 0, 37522, 41030, 44212, 65535 +}; + +const SKP_int SKP_Silk_type_offset_CDF_offset = 2; + + +const SKP_uint16 SKP_Silk_type_offset_joint_CDF[ 4 ][ 5 ] = +{ +{ + 0, 57686, 61230, 62358, 65535 +}, +{ + 0, 18346, 40067, 43659, 65535 +}, +{ + 0, 22694, 24279, 35507, 65535 +}, +{ + 0, 6067, 7215, 13010, 65535 +} +}; + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tuning_parameters.h b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tuning_parameters.h new file mode 100755 index 0000000..3f8a696 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_tuning_parameters.h @@ -0,0 +1,183 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SKP_SILK_TUNING_PARAMETERS_H +#define SKP_SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWITH_EXPANSION 0.99f + +/* Threshold used by pitch estimator for early escape */ +#define FIND_PITCH_CORRELATION_THRESHOLD_HC_MODE 0.7f +#define FIND_PITCH_CORRELATION_THRESHOLD_MC_MODE 0.75f +#define FIND_PITCH_CORRELATION_THRESHOLD_LC_MODE 0.8f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis defines: regularization and bandwidth expansion */ +#define FIND_LPC_COND_FAC 2.5e-5f +#define FIND_LPC_CHIRP 0.99995f + +/* LTP analysis defines */ +#define FIND_LTP_COND_FAC 1e-5f +#define LTP_DAMPING 0.01f +#define LTP_SMOOTHING 0.1f + +/* LTP quantization settings */ +#define MU_LTP_QUANT_NB 0.03f +#define MU_LTP_QUANT_MB 0.025f +#define MU_LTP_QUANT_WB 0.02f +#define MU_LTP_QUANT_SWB 0.016f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f + +/* Min and max values for low end of pitch frequency range estimation */ +#define VARIABLE_HP_MIN_FREQ 80.0f +#define VARIABLE_HP_MAX_FREQ 150.0f + +/* Max absolute difference between log2 of pitch frequency and smoother state, to enter the smoother */ +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/***********/ +/* Various */ +/***********/ + +/* Required speech activity for counting frame as active */ +#define WB_DETECT_ACTIVE_SPEECH_LEVEL_THRES 0.7f + +#define SPEECH_ACTIVITY_DTX_THRES 0.1f + +/* Speech Activity LBRR enable threshold (needs tuning) */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.5f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 4.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 1e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.95f + +/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */ +#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f + +/* gain reduction for fricatives */ +#define DE_ESSER_COEF_SWB_dB 2.0f +#define DE_ESSER_COEF_WB_dB 1.0f + +/* extra harmonic boosting (signal shaping) at low bitrates */ +#define LOW_RATE_HARMONIC_BOOST 0.1f + +/* extra harmonic boosting (signal shaping) for noisy input signals */ +#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.3f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 3.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* noise floor to put a lower limit on the quantization step size */ +#define NOISE_FLOOR_dB 4.0f + +/* noise floor relative to active speech gain level */ +#define RELATIVE_MIN_GAIN_dB -50.0f + +/* subframe smoothing coefficient for determining active speech gain level (lower -> more smoothing) */ +#define GAIN_SMOOTHING_COEF 1e-3f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.3f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.2f +#define LAMBDA_CODING_QUALITY -0.1f +#define LAMBDA_QUANT_OFFSET 1.5f + +#ifdef __cplusplus +} +#endif + +#endif // SKP_SILK_TUNING_PARAMETERS_H diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_warped_autocorrelation_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_warped_autocorrelation_FLP.c new file mode 100755 index 0000000..16956f4 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_warped_autocorrelation_FLP.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FLP( + SKP_float *corr, /* O Result [order + 1] */ + const SKP_float *input, /* I Input data to correlate */ + const SKP_float warping, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +) +{ + SKP_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in SKP_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( SKP_float )C[ i ]; + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_wrappers_FLP.c b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_wrappers_FLP.c new file mode 100755 index 0000000..a7f1efa --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/SKP_Silk_wrappers_FLP.c @@ -0,0 +1,256 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void SKP_Silk_A2NLSF_FLP( + SKP_float *pNLSF, /* O NLSF vector [ LPC_order ] */ + const SKP_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int i; + SKP_int NLSF_fix[ MAX_LPC_ORDER ]; + SKP_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = SKP_float2int( pAR[ i ] * 65536.0f ); + } + SKP_Silk_A2NLSF( NLSF_fix, a_fix_Q16, LPC_order ); + + for( i = 0; i < LPC_order; i++ ) { + pNLSF[ i ] = ( SKP_float )NLSF_fix[ i ] * ( 1.0f / 32768.0f ); + } +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable_FLP( + SKP_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const SKP_float *pNLSF, /* I NLSF vector [ LPC_order ] */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int i; + SKP_int NLSF_fix[ MAX_LPC_ORDER ]; + SKP_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + NLSF_fix[ i ] = ( SKP_int )SKP_CHECK_FIT16( SKP_float2int( pNLSF[ i ] * 32768.0f ) ); + } + + SKP_Silk_NLSF2A_stable( a_fix_Q12, NLSF_fix, LPC_order ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( SKP_float )a_fix_Q12[ i ] / 4096.0f; + } +} + + +/* LSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize_FLP( + SKP_float *pNLSF, /* I/O (Un)stable NLSF vector [ LPC_order ] */ + const SKP_float *pNDelta_min, /* I Normalized delta min vector[LPC_order+1]*/ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int i; + SKP_int NLSF_Q15[ MAX_LPC_ORDER ], ndelta_min_Q15[ MAX_LPC_ORDER + 1 ]; + + for( i = 0; i < LPC_order; i++ ) { + NLSF_Q15[ i ] = ( SKP_int )SKP_float2int( pNLSF[ i ] * 32768.0f ); + ndelta_min_Q15[ i ] = ( SKP_int )SKP_float2int( pNDelta_min[ i ] * 32768.0f ); + } + ndelta_min_Q15[ LPC_order ] = ( SKP_int )SKP_float2int( pNDelta_min[ LPC_order ] * 32768.0f ); + + /* NLSF stabilizer, for a single input data vector */ + SKP_Silk_NLSF_stabilize( NLSF_Q15, ndelta_min_Q15, LPC_order ); + + for( i = 0; i < LPC_order; i++ ) { + pNLSF[ i ] = ( SKP_float )NLSF_Q15[ i ] * ( 1.0f / 32768.0f ); + } +} + +/* Interpolation function with fixed point rounding */ +void SKP_Silk_interpolate_wrapper_FLP( + SKP_float xi[], /* O Interpolated vector */ + const SKP_float x0[], /* I First vector */ + const SKP_float x1[], /* I Second vector */ + const SKP_float ifact, /* I Interp. factor, weight on second vector */ + const SKP_int d /* I Number of parameters */ +) +{ + SKP_int x0_int[ MAX_LPC_ORDER ], x1_int[ MAX_LPC_ORDER ], xi_int[ MAX_LPC_ORDER ]; + SKP_int ifact_Q2 = ( SKP_int )( ifact * 4.0f ); + SKP_int i; + + /* Convert input from flp to fix */ + for( i = 0; i < d; i++ ) { + x0_int[ i ] = SKP_float2int( x0[ i ] * 32768.0f ); + x1_int[ i ] = SKP_float2int( x1[ i ] * 32768.0f ); + } + + /* Interpolate two vectors */ + SKP_Silk_interpolate( xi_int, x0_int, x1_int, ifact_Q2, d ); + + /* Convert output from fix to flp */ + for( i = 0; i < d; i++ ) { + xi[ i ] = ( SKP_float )xi_int[ i ] * ( 1.0f / 32768.0f ); + } +} + +/****************************************/ +/* Floating-point Silk VAD wrapper */ +/****************************************/ +SKP_int SKP_Silk_VAD_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_int16 *pIn /* I Input signal */ +) +{ + SKP_int i, ret, SA_Q8, SNR_dB_Q7, Tilt_Q15; + SKP_int Quality_Bands_Q15[ VAD_N_BANDS ]; + + ret = SKP_Silk_VAD_GetSA_Q8( &psEnc->sCmn.sVAD, &SA_Q8, &SNR_dB_Q7, Quality_Bands_Q15, &Tilt_Q15, + pIn, psEnc->sCmn.frame_length ); + + psEnc->speech_activity = ( SKP_float )SA_Q8 / 256.0f; + for( i = 0; i < VAD_N_BANDS; i++ ) { + psEncCtrl->input_quality_bands[ i ] = ( SKP_float )Quality_Bands_Q15[ i ] / 32768.0f; + } + psEncCtrl->input_tilt = ( SKP_float )Tilt_Q15 / 32768.0f; + + return ret; +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void SKP_Silk_NSQ_wrapper_FLP( + SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const SKP_float x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int useLBRR /* I LBRR flag */ +) +{ + SKP_int i, j; + SKP_float tmp_float; + SKP_int16 x_16[ MAX_FRAME_LENGTH ]; + /* Prediction and coding parameters */ + SKP_int32 Gains_Q16[ NB_SUBFR ]; + SKP_DWORD_ALIGN SKP_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ]; + SKP_int LTP_scale_Q14; + + /* Noise shaping parameters */ + /* Testing */ + SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_int32 LF_shp_Q14[ NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + SKP_int Lambda_Q10; + SKP_int Tilt_Q14[ NB_SUBFR ]; + SKP_int HarmShapeGain_Q14[ NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < NB_SUBFR; i++ ) { + /* Convert only the data in use */ + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = SKP_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + /* Clear the rest only to get rid of analysis tool warnings */ + for( ; j < MAX_SHAPE_LPC_ORDER; j++ ) { + AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = 0; + } + } + + for( i = 0; i < NB_SUBFR; i++ ) { + LF_shp_Q14[ i ] = SKP_LSHIFT32( SKP_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (SKP_uint16)SKP_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (SKP_int)SKP_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (SKP_int)SKP_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( SKP_int )SKP_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < NB_SUBFR * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = ( SKP_int16 )SKP_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < NB_SUBFR >> 1; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = ( SKP_int16 )SKP_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + /* Clear the rest only to get rid of analysis tool warnings */ + for( ; i < MAX_LPC_ORDER; i++ ) { + PredCoef_Q12[ j ][ i ] = 0; + } + } + + for( i = 0; i < NB_SUBFR; i++ ) { + tmp_float = SKP_LIMIT( ( psEncCtrl->Gains[ i ] * 65536.0f ), 2147483000.0f, -2147483000.0f ); + Gains_Q16[ i ] = SKP_float2int( tmp_float ); + if( psEncCtrl->Gains[ i ] > 0.0f ) { + SKP_assert( tmp_float >= 0.0f ); + SKP_assert( Gains_Q16[ i ] >= 0 ); + } + } + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ psEncCtrl->sCmn.LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + SKP_float2short_array( x_16, x, psEnc->sCmn.frame_length ); + + /* Call NSQ */ + if( useLBRR ) { + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, + x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, + x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); + } + } else { + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ, + x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ, + x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); + } + } +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcproj b/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcproj new file mode 100755 index 0000000..645fb5a --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcproj @@ -0,0 +1,744 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcxproj b/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcxproj new file mode 100755 index 0000000..a4a933e --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/src/Silk_FLP.vcxproj @@ -0,0 +1,331 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {56B91D01-9150-4BBF-AFA1-5B68AB991B76} + Silk + Win32Proj + + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + + + StaticLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)\src\ + $(SolutionDir)\src\ + $(Configuration)\ + $(Configuration)\ + $(SolutionDir)\src\ + $(SolutionDir)\src\ + $(Configuration)\ + $(Configuration)\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + SKP_$(ProjectName)_$(Platform)_debug + SKP_$(ProjectName)_$(Platform)_debug + SKP_$(ProjectName)_$(Platform)_mt + SKP_$(ProjectName)_$(Platform)_mt + + + + Disabled + Neither + ../interface;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Fast + + + Level3 + EditAndContinue + + + SKP_Silk_FLP_Win32_debug.lib + + + + + + + + + Disabled + Neither + ../interface;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Fast + + + Level3 + ProgramDatabase + + + SKP_Silk_FLP_x64_debug.lib + + + + + + + + + MaxSpeed + Default + Neither + ../interface;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + false + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + SKP_Silk_FLP_Win32_mt.lib + + + + + + + + + MaxSpeed + Default + Neither + ../interface;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + false + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + SKP_Silk_FLP_x64_mt.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcproj new file mode 100755 index 0000000..131586b --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcproj @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcxproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcxproj new file mode 100755 index 0000000..ed959bc --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Dec_SDK.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {82685D7F-0589-42BD-877C-31A952D53A8E} + Test + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir) + $(SolutionDir) + $(Configuration)_Dec\ + $(Configuration)_Dec\ + true + true + $(SolutionDir) + $(SolutionDir) + $(Configuration)_Dec\ + $(Configuration)_Dec\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + Decoder_debug + Decoder_debug + Decoder + Decoder + + + + Disabled + ../interface;../src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;COMPILE_SDK;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)Decoder_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + Disabled + ../interface;../src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;COMPILE_SDK;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(OutDir)Decoder_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + + + + + ../interface;../src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;COMPILE_SDK;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(OutDir)Decoder.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + MachineX86 + + + + + ../interface;../src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;COMPILE_SDK;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(OutDir)Decoder.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + + + + + + + + + + + + + + {56b91d01-9150-4bbf-afa1-5b68ab991b76} + false + + + + + + \ No newline at end of file diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Decoder.c b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Decoder.c new file mode 100755 index 0000000..d1f298f --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Decoder.c @@ -0,0 +1,472 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +/*****************************/ +/* Silk decoder test program */ +/*****************************/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include "SKP_Silk_SDK_API.h" +#include "SKP_Silk_SigProc_FIX.h" + +/* Define codec specific settings should be moved to h file */ +#define MAX_BYTES_PER_FRAME 1024 +#define MAX_INPUT_FRAMES 5 +#define MAX_FRAME_LENGTH 480 +#define FRAME_LENGTH_MS 20 +#define MAX_API_FS_KHZ 48 +#define MAX_LBRR_DELAY 2 + +#ifdef _SYSTEM_IS_BIG_ENDIAN +/* Function to convert a little endian int16 to a */ +/* big endian int16 or vica verca */ +void swap_endian( + SKP_int16 vec[], + SKP_int len +) +{ + SKP_int i; + SKP_int16 tmp; + SKP_uint8 *p1, *p2; + + for( i = 0; i < len; i++ ){ + tmp = vec[ i ]; + p1 = (SKP_uint8 *)&vec[ i ]; p2 = (SKP_uint8 *)&tmp; + p1[ 0 ] = p2[ 1 ]; p1[ 1 ] = p2[ 0 ]; + } +} +#endif + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else // Linux or Mac +#include +#endif + +#ifdef _WIN32 + +unsigned long GetHighResolutionTime() /* O: time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else // Linux or Mac +unsigned long GetHighResolutionTime() /* O: time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif // _WIN32 + +/* Seed for the random number generator, which is used for simulating packet loss */ +static SKP_int32 rand_seed = 1; + +static void print_usage(char* argv[]) { + printf( "\nusage: %s in.bit out.pcm [settings]\n", argv[ 0 ] ); + printf( "\nin.bit : Bitstream input to decoder" ); + printf( "\nout.pcm : Speech output from decoder" ); + printf( "\n settings:" ); + printf( "\n-Fs_API : Sampling rate of output signal in Hz; default: 24000" ); + printf( "\n-loss : Simulated packet loss percentage (0-100); default: 0" ); + printf( "\n-quiet : Print out just some basic values" ); + printf( "\n" ); +} + +int main( int argc, char* argv[] ) +{ + unsigned long tottime, starttime; + double filetime; + size_t counter; + SKP_int32 args, totPackets, i, k; + SKP_int16 ret, len, tot_len; + SKP_int16 nBytes; + SKP_uint8 payload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES * ( MAX_LBRR_DELAY + 1 ) ]; + SKP_uint8 *payloadEnd = NULL, *payloadToDec = NULL; + SKP_uint8 FECpayload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES ], *payloadPtr; + SKP_int16 nBytesFEC; + SKP_int16 nBytesPerPacket[ MAX_LBRR_DELAY + 1 ], totBytes; + SKP_int16 out[ ( ( FRAME_LENGTH_MS * MAX_API_FS_KHZ ) << 1 ) * MAX_INPUT_FRAMES ], *outPtr; + char speechOutFileName[ 150 ], bitInFileName[ 150 ]; + FILE *bitInFile, *speechOutFile; + SKP_int32 packetSize_ms=0, API_Fs_Hz = 0; + SKP_int32 decSizeBytes; + void *psDec; + SKP_float loss_prob; + SKP_int32 frames, lost, quiet; + SKP_SILK_SDK_DecControlStruct DecControl; + + if( argc < 3 ) { + print_usage( argv ); + exit( 0 ); + } + + /* default settings */ + quiet = 0; + loss_prob = 0.0f; + + /* get arguments */ + args = 1; + strcpy( bitInFileName, argv[ args ] ); + args++; + strcpy( speechOutFileName, argv[ args ] ); + args++; + while( args < argc ) { + if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) { + sscanf( argv[ args + 1 ], "%f", &loss_prob ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_API" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &API_Fs_Hz ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-quiet" ) == 0 ) { + quiet = 1; + args++; + } else { + printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); + print_usage( argv ); + exit( 0 ); + } + } + + if( !quiet ) { + printf("********** Silk Decoder (Fixed Point) v %s ********************\n", SKP_Silk_SDK_get_version()); + printf("********** Compiled for %d bit cpu *******************************\n", (int)sizeof(void*) * 8 ); + printf( "Input: %s\n", bitInFileName ); + printf( "Output: %s\n", speechOutFileName ); + } + + /* Open files */ + bitInFile = fopen( bitInFileName, "rb" ); + if( bitInFile == NULL ) { + printf( "Error: could not open input file %s\n", bitInFileName ); + exit( 0 ); + } + + /* Check Silk header */ + { + char header_buf[ 50 ]; + counter = fread( header_buf, sizeof( char ), strlen( "#!SILK_V3" ), bitInFile ); + header_buf[ strlen( "#!SILK_V3" ) ] = '\0'; /* Terminate with a null character */ + if( strcmp( header_buf, "#!SILK_V3" ) != 0 ) { + /* Non-equal strings */ + printf( "Error: Wrong Header %s\n", header_buf ); + exit( 0 ); + } + } + + speechOutFile = fopen( speechOutFileName, "wb" ); + if( speechOutFile == NULL ) { + printf( "Error: could not open output file %s\n", speechOutFileName ); + exit( 0 ); + } + + /* Set the samplingrate that is requested for the output */ + if( API_Fs_Hz == 0 ) { + DecControl.API_sampleRate = 24000; + } else { + DecControl.API_sampleRate = API_Fs_Hz; + } + + /* Initialize to one frame per packet, for proper concealment before first packet arrives */ + DecControl.framesPerPacket = 1; + + /* Create decoder */ + ret = SKP_Silk_SDK_Get_Decoder_Size( &decSizeBytes ); + if( ret ) { + printf( "\nSKP_Silk_SDK_Get_Decoder_Size returned %d", ret ); + } + psDec = malloc( decSizeBytes ); + + /* Reset decoder */ + ret = SKP_Silk_SDK_InitDecoder( psDec ); + if( ret ) { + printf( "\nSKP_Silk_InitDecoder returned %d", ret ); + } + + totPackets = 0; + tottime = 0; + payloadEnd = payload; + + /* Simulate the jitter buffer holding MAX_FEC_DELAY packets */ + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + /* Read payload size */ + counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); +#ifdef _SYSTEM_IS_BIG_ENDIAN + swap_endian( &nBytes, 1 ); +#endif + /* Read payload */ + counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); + + if( ( SKP_int16 )counter < nBytes ) { + break; + } + nBytesPerPacket[ i ] = nBytes; + payloadEnd += nBytes; + totPackets++; + } + + while( 1 ) { + /* Read payload size */ + counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); +#ifdef _SYSTEM_IS_BIG_ENDIAN + swap_endian( &nBytes, 1 ); +#endif + if( nBytes < 0 || counter < 1 ) { + break; + } + + /* Read payload */ + counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); + if( ( SKP_int16 )counter < nBytes ) { + break; + } + + /* Simulate losses */ + rand_seed = SKP_RAND( rand_seed ); + if( ( ( ( float )( ( rand_seed >> 16 ) + ( 1 << 15 ) ) ) / 65535.0f >= ( loss_prob / 100.0f ) ) && ( counter > 0 ) ) { + nBytesPerPacket[ MAX_LBRR_DELAY ] = nBytes; + payloadEnd += nBytes; + } else { + nBytesPerPacket[ MAX_LBRR_DELAY ] = 0; + } + + if( nBytesPerPacket[ 0 ] == 0 ) { + /* Indicate lost packet */ + lost = 1; + + /* Packet loss. Search after FEC in next packets. Should be done in the jitter buffer */ + payloadPtr = payload; + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + if( nBytesPerPacket[ i + 1 ] > 0 ) { + starttime = GetHighResolutionTime(); + SKP_Silk_SDK_search_for_LBRR( payloadPtr, nBytesPerPacket[ i + 1 ], ( i + 1 ), FECpayload, &nBytesFEC ); + tottime += GetHighResolutionTime() - starttime; + if( nBytesFEC > 0 ) { + payloadToDec = FECpayload; + nBytes = nBytesFEC; + lost = 0; + break; + } + } + payloadPtr += nBytesPerPacket[ i + 1 ]; + } + } else { + lost = 0; + nBytes = nBytesPerPacket[ 0 ]; + payloadToDec = payload; + } + + /* Silk decoder */ + outPtr = out; + tot_len = 0; + starttime = GetHighResolutionTime(); + + if( lost == 0 ) { + /* No Loss: Decode all frames in the packet */ + frames = 0; + do { + /* Decode 20 ms */ + ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 0, payloadToDec, nBytes, outPtr, &len ); + if( ret ) { + printf( "\nSKP_Silk_SDK_Decode returned %d", ret ); + } + + frames++; + outPtr += len; + tot_len += len; + if( frames > MAX_INPUT_FRAMES ) { + /* Hack for corrupt stream that could generate too many frames */ + outPtr = out; + tot_len = 0; + frames = 0; + } + /* Until last 20 ms frame of packet has been decoded */ + } while( DecControl.moreInternalDecoderFrames ); + } else { + /* Loss: Decode enough frames to cover one packet duration */ + for( i = 0; i < DecControl.framesPerPacket; i++ ) { + /* Generate 20 ms */ + ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 1, payloadToDec, nBytes, outPtr, &len ); + if( ret ) { + printf( "\nSKP_Silk_Decode returned %d", ret ); + } + outPtr += len; + tot_len += len; + } + } + + packetSize_ms = tot_len / ( DecControl.API_sampleRate / 1000 ); + tottime += GetHighResolutionTime() - starttime; + totPackets++; + + /* Write output to file */ +#ifdef _SYSTEM_IS_BIG_ENDIAN + swap_endian( out, tot_len ); +#endif + fwrite( out, sizeof( SKP_int16 ), tot_len, speechOutFile ); + + /* Update buffer */ + totBytes = 0; + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + totBytes += nBytesPerPacket[ i + 1 ]; + } + SKP_memmove( payload, &payload[ nBytesPerPacket[ 0 ] ], totBytes * sizeof( SKP_uint8 ) ); + payloadEnd -= nBytesPerPacket[ 0 ]; + SKP_memmove( nBytesPerPacket, &nBytesPerPacket[ 1 ], MAX_LBRR_DELAY * sizeof( SKP_int16 ) ); + + if( !quiet ) { + fprintf( stderr, "\rPackets decoded: %d", totPackets ); + } + } + + /* Empty the recieve buffer */ + for( k = 0; k < MAX_LBRR_DELAY; k++ ) { + if( nBytesPerPacket[ 0 ] == 0 ) { + /* Indicate lost packet */ + lost = 1; + + /* Packet loss. Search after FEC in next packets. Should be done in the jitter buffer */ + payloadPtr = payload; + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + if( nBytesPerPacket[ i + 1 ] > 0 ) { + starttime = GetHighResolutionTime(); + SKP_Silk_SDK_search_for_LBRR( payloadPtr, nBytesPerPacket[ i + 1 ], ( i + 1 ), FECpayload, &nBytesFEC ); + tottime += GetHighResolutionTime() - starttime; + if( nBytesFEC > 0 ) { + payloadToDec = FECpayload; + nBytes = nBytesFEC; + lost = 0; + break; + } + } + payloadPtr += nBytesPerPacket[ i + 1 ]; + } + } else { + lost = 0; + nBytes = nBytesPerPacket[ 0 ]; + payloadToDec = payload; + } + + /* Silk decoder */ + outPtr = out; + tot_len = 0; + starttime = GetHighResolutionTime(); + + if( lost == 0 ) { + /* No loss: Decode all frames in the packet */ + frames = 0; + do { + /* Decode 20 ms */ + ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 0, payloadToDec, nBytes, outPtr, &len ); + if( ret ) { + printf( "\nSKP_Silk_SDK_Decode returned %d", ret ); + } + + frames++; + outPtr += len; + tot_len += len; + if( frames > MAX_INPUT_FRAMES ) { + /* Hack for corrupt stream that could generate too many frames */ + outPtr = out; + tot_len = 0; + frames = 0; + } + /* Until last 20 ms frame of packet has been decoded */ + } while( DecControl.moreInternalDecoderFrames ); + } else { + /* Loss: Decode enough frames to cover one packet duration */ + + /* Generate 20 ms */ + for( i = 0; i < DecControl.framesPerPacket; i++ ) { + ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 1, payloadToDec, nBytes, outPtr, &len ); + if( ret ) { + printf( "\nSKP_Silk_Decode returned %d", ret ); + } + outPtr += len; + tot_len += len; + } + } + + packetSize_ms = tot_len / ( DecControl.API_sampleRate / 1000 ); + tottime += GetHighResolutionTime() - starttime; + totPackets++; + + /* Write output to file */ +#ifdef _SYSTEM_IS_BIG_ENDIAN + swap_endian( out, tot_len ); +#endif + fwrite( out, sizeof( SKP_int16 ), tot_len, speechOutFile ); + + /* Update Buffer */ + totBytes = 0; + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + totBytes += nBytesPerPacket[ i + 1 ]; + } + SKP_memmove( payload, &payload[ nBytesPerPacket[ 0 ] ], totBytes * sizeof( SKP_uint8 ) ); + payloadEnd -= nBytesPerPacket[ 0 ]; + SKP_memmove( nBytesPerPacket, &nBytesPerPacket[ 1 ], MAX_LBRR_DELAY * sizeof( SKP_int16 ) ); + + if( !quiet ) { + fprintf( stderr, "\rPackets decoded: %d", totPackets ); + } + } + + if( !quiet ) { + printf( "\nDecoding Finished \n" ); + } + + /* Free decoder */ + free( psDec ); + + /* Close files */ + fclose( speechOutFile ); + fclose( bitInFile ); + + filetime = totPackets * 1e-3 * packetSize_ms; + if( !quiet ) { + printf("\nFile length: %.3f s", filetime); + printf("\nTime for decoding: %.3f s (%.3f%% of realtime)", 1e-6 * tottime, 1e-4 * tottime / filetime); + printf("\n\n"); + } else { + /* print time and % of realtime */ + printf( "%.3f %.3f %d\n", 1e-6 * tottime, 1e-4 * tottime / filetime, totPackets ); + } + return 0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcproj new file mode 100755 index 0000000..4415931 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcproj @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcxproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcxproj new file mode 100755 index 0000000..038b559 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Enc_SDK.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6D97A8EF-5724-4D85-8BF4-C583714BBA78} + Enc + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir) + $(SolutionDir) + $(Configuration)\Enc\ + $(Configuration)\Enc\ + true + true + $(SolutionDir) + $(SolutionDir) + $(Configuration)_Enc\ + $(Configuration)_Enc\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + Encoder_debug + Encoder_debug + Encoder + Encoder + + + + Disabled + ../interface;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)Encoder_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + Disabled + ../interface;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(OutDir)Encoder_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + + + + + ../interface;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(OutDir)Encoder.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + MachineX86 + + + + + ../interface;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(OutDir)Encoder.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + + + + + + + + + + + + + + {56b91d01-9150-4bbf-afa1-5b68ab991b76} + false + + + + + + \ No newline at end of file diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/Encoder.c b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Encoder.c new file mode 100755 index 0000000..e03cbf8 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/Encoder.c @@ -0,0 +1,369 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +/*****************************/ +/* Silk encoder test program */ +/*****************************/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include "SKP_Silk_SDK_API.h" + +/* Define codec specific settings */ +#define MAX_BYTES_PER_FRAME 250 // Equals peak bitrate of 100 kbps +#define MAX_INPUT_FRAMES 5 +#define FRAME_LENGTH_MS 20 +#define MAX_API_FS_KHZ 48 + +#ifdef _SYSTEM_IS_BIG_ENDIAN +/* Function to convert a little endian int16 to a */ +/* big endian int16 or vica verca */ +void swap_endian( + SKP_int16 vec[], /* I/O array of */ + SKP_int len /* I length */ +) +{ + SKP_int i; + SKP_int16 tmp; + SKP_uint8 *p1, *p2; + + for( i = 0; i < len; i++ ){ + tmp = vec[ i ]; + p1 = (SKP_uint8 *)&vec[ i ]; p2 = (SKP_uint8 *)&tmp; + p1[ 0 ] = p2[ 1 ]; p1[ 1 ] = p2[ 0 ]; + } +} +#endif + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else // Linux or Mac +#include +#endif + +#ifdef _WIN32 + +unsigned long GetHighResolutionTime() /* O: time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else // Linux or Mac +unsigned long GetHighResolutionTime() /* O: time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif // _WIN32 + +static void print_usage( char* argv[] ) { + printf( "\nusage: %s in.pcm out.bit [settings]\n", argv[ 0 ] ); + printf( "\nin.pcm : Speech input to encoder" ); + printf( "\nout.bit : Bitstream output from encoder" ); + printf( "\n settings:" ); + printf( "\n-Fs_API : API sampling rate in Hz, default: 24000" ); + printf( "\n-Fs_maxInternal : Maximum internal sampling rate in Hz, default: 24000" ); + printf( "\n-packetlength : Packet interval in ms, default: 20" ); + printf( "\n-rate : Target bitrate; default: 25000" ); + printf( "\n-loss : Uplink loss estimate, in percent (0-100); default: 0" ); + printf( "\n-inbandFEC : Enable inband FEC usage (0/1); default: 0" ); + printf( "\n-complexity : Set complexity, 0: low, 1: medium, 2: high; default: 2" ); + printf( "\n-DTX : Enable DTX (0/1); default: 0" ); + printf( "\n-quiet : Print only some basic values" ); + printf( "\n"); +} + +int main( int argc, char* argv[] ) +{ + unsigned long tottime, starttime; + double filetime; + size_t counter; + SKP_int32 k, args, totPackets, totActPackets, ret; + SKP_int16 nBytes; + double sumBytes, sumActBytes, avg_rate, act_rate, nrg; + SKP_uint8 payload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES ]; + SKP_int16 in[ FRAME_LENGTH_MS * MAX_API_FS_KHZ * MAX_INPUT_FRAMES ]; + char speechInFileName[ 150 ], bitOutFileName[ 150 ]; + FILE *bitOutFile, *speechInFile; + SKP_int32 encSizeBytes; + void *psEnc; +#ifdef _SYSTEM_IS_BIG_ENDIAN + SKP_int16 nBytes_LE; +#endif + + /* default settings */ + SKP_int32 API_fs_Hz = 24000; + SKP_int32 max_internal_fs_Hz = 0; + SKP_int32 targetRate_bps = 25000; + SKP_int32 smplsSinceLastPacket, packetSize_ms = 20; + SKP_int32 frameSizeReadFromFile_ms = 20; + SKP_int32 packetLoss_perc = 0; +#if LOW_COMPLEXITY_ONLY + SKP_int32 complexity_mode = 0; +#else + SKP_int32 complexity_mode = 2; +#endif + SKP_int32 DTX_enabled = 0, INBandFEC_enabled = 0, quiet = 0; + SKP_SILK_SDK_EncControlStruct encControl; // Struct for input to encoder + SKP_SILK_SDK_EncControlStruct encStatus; // Struct for status of encoder + + if( argc < 3 ) { + print_usage( argv ); + exit( 0 ); + } + + /* get arguments */ + args = 1; + strcpy( speechInFileName, argv[ args ] ); + args++; + strcpy( bitOutFileName, argv[ args ] ); + args++; + while( args < argc ) { + if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_API" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &API_fs_Hz ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_maxInternal" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &max_internal_fs_Hz ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-packetlength" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &packetSize_ms ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-rate" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &targetRate_bps ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &packetLoss_perc ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &complexity_mode ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandFEC" ) == 0 ) { + sscanf( argv[ args + 1 ], "%d", &INBandFEC_enabled ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-DTX") == 0 ) { + sscanf( argv[ args + 1 ], "%d", &DTX_enabled ); + args += 2; + } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-quiet" ) == 0 ) { + quiet = 1; + args++; + } else { + printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); + print_usage( argv ); + exit( 0 ); + } + } + + /* If no max internal is specified, set to minimum of API fs and 24 kHz */ + if( max_internal_fs_Hz == 0 ) { + max_internal_fs_Hz = 24000; + if( API_fs_Hz < max_internal_fs_Hz ) { + max_internal_fs_Hz = API_fs_Hz; + } + } + + /* Print options */ + if( !quiet ) { + if( sizeof(SKP_float) == sizeof(float) ) { + printf("********** Silk Encoder (Single Precision) v %s ***************\n", SKP_Silk_SDK_get_version()); + } else { + printf("********** Silk Encoder (Double Precision) v %s ***************\n", SKP_Silk_SDK_get_version()); + } + printf("********** Compiled for %d bit cpu ******************************* \n", (int)sizeof(void*) * 8 ); + printf( "Input: %s\n", speechInFileName ); + printf( "Output: %s\n", bitOutFileName ); + printf( "API sampling rate: %d Hz\n", API_fs_Hz ); + printf( "Maximum internal sampling rate: %d Hz\n", max_internal_fs_Hz ); + printf( "Packet interval: %d ms\n", packetSize_ms ); + printf( "Inband FEC used: %d\n", INBandFEC_enabled ); + printf( "DTX used: %d\n", DTX_enabled ); + printf( "Complexity: %d\n", complexity_mode ); + printf( "Target bitrate: %d bps\n", targetRate_bps ); + } + + /* Open files */ + speechInFile = fopen( speechInFileName, "rb" ); + if( speechInFile == NULL ) { + printf( "Error: could not open input file %s\n", speechInFileName ); + exit( 0 ); + } + bitOutFile = fopen( bitOutFileName, "wb" ); + if( bitOutFile == NULL ) { + printf( "Error: could not open output file %s\n", bitOutFileName ); + exit( 0 ); + } + + /* Add Silk header to stream */ + { + static const char Silk_header[] = "#!SILK_V3"; + fwrite( Silk_header, sizeof( char ), strlen( Silk_header ), bitOutFile ); + } + + /* Create Encoder */ + ret = SKP_Silk_SDK_Get_Encoder_Size( &encSizeBytes ); + if( ret ) { + printf( "\nError: SKP_Silk_create_encoder returned %d\n", ret ); + exit( 0 ); + } + + psEnc = malloc( encSizeBytes ); + + /* Reset Encoder */ + ret = SKP_Silk_SDK_InitEncoder( psEnc, &encStatus ); + if( ret ) { + printf( "\nError: SKP_Silk_reset_encoder returned %d\n", ret ); + exit( 0 ); + } + + /* Set Encoder parameters */ + encControl.API_sampleRate = API_fs_Hz; + encControl.maxInternalSampleRate = max_internal_fs_Hz; + encControl.packetSize = ( packetSize_ms * API_fs_Hz ) / 1000; + encControl.packetLossPercentage = packetLoss_perc; + encControl.useInBandFEC = INBandFEC_enabled; + encControl.useDTX = DTX_enabled; + encControl.complexity = complexity_mode; + encControl.bitRate = ( targetRate_bps > 0 ? targetRate_bps : 0 ); + + if( API_fs_Hz > MAX_API_FS_KHZ * 1000 || API_fs_Hz < 0 ) { + printf( "\nError: API sampling rate = %d out of range, valid range 8000 - 48000 \n \n", API_fs_Hz ); + exit( 0 ); + } + + tottime = 0; + totPackets = 0; + totActPackets = 0; + smplsSinceLastPacket = 0; + sumBytes = 0.0; + sumActBytes = 0.0; + smplsSinceLastPacket = 0; + + while( 1 ) { + /* Read input from file */ + counter = fread( in, sizeof( SKP_int16 ), ( frameSizeReadFromFile_ms * API_fs_Hz ) / 1000, speechInFile ); +#ifdef _SYSTEM_IS_BIG_ENDIAN + swap_endian( in, counter ); +#endif + if( ( SKP_int )counter < ( ( frameSizeReadFromFile_ms * API_fs_Hz ) / 1000 ) ) { + break; + } + + /* max payload size */ + nBytes = MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES; + + starttime = GetHighResolutionTime(); + + /* Silk Encoder */ + ret = SKP_Silk_SDK_Encode( psEnc, &encControl, in, (SKP_int16)counter, payload, &nBytes ); + if( ret ) { + printf( "\nSKP_Silk_Encode returned %d", ret ); + } + + tottime += GetHighResolutionTime() - starttime; + + /* Get packet size */ + packetSize_ms = ( SKP_int )( ( 1000 * ( SKP_int32 )encControl.packetSize ) / encControl.API_sampleRate ); + + smplsSinceLastPacket += ( SKP_int )counter; + + if( ( ( 1000 * smplsSinceLastPacket ) / API_fs_Hz ) == packetSize_ms ) { + /* Sends a dummy zero size packet in case of DTX period */ + /* to make it work with the decoder test program. */ + /* In practice should be handled by RTP sequence numbers */ + totPackets++; + sumBytes += nBytes; + nrg = 0.0; + for( k = 0; k < ( SKP_int )counter; k++ ) { + nrg += in[ k ] * (double)in[ k ]; + } + if( ( nrg / ( SKP_int )counter ) > 1e3 ) { + sumActBytes += nBytes; + totActPackets++; + } + + /* Write payload size */ +#ifdef _SYSTEM_IS_BIG_ENDIAN + nBytes_LE = nBytes; + swap_endian( &nBytes_LE, 1 ); + fwrite( &nBytes_LE, sizeof( SKP_int16 ), 1, bitOutFile ); +#else + fwrite( &nBytes, sizeof( SKP_int16 ), 1, bitOutFile ); +#endif + + /* Write payload */ + fwrite( payload, sizeof( SKP_uint8 ), nBytes, bitOutFile ); + + smplsSinceLastPacket = 0; + + if( !quiet ) { + fprintf( stderr, "\rPackets encoded: %d", totPackets ); + } + } + } + + /* Write dummy because it can not end with 0 bytes */ + nBytes = -1; + + /* Write payload size */ + fwrite( &nBytes, sizeof( SKP_int16 ), 1, bitOutFile ); + + /* Free Encoder */ + free( psEnc ); + + fclose( speechInFile ); + fclose( bitOutFile ); + + filetime = totPackets * 1e-3 * packetSize_ms; + avg_rate = 8.0 / packetSize_ms * sumBytes / totPackets; + act_rate = 8.0 / packetSize_ms * sumActBytes / totActPackets; + if( !quiet ) { + printf( "\nFile length: %.3f s", filetime ); + printf( "\nTime for encoding: %.3f s (%.3f%% of realtime)", 1e-6 * tottime, 1e-4 * tottime / filetime ); + printf( "\nAverage bitrate: %.3f kbps", avg_rate ); + printf( "\nActive bitrate: %.3f kbps", act_rate ); + printf( "\n\n" ); + } else { + /* print time and % of realtime */ + printf("%.3f %.3f %d ", 1e-6 * tottime, 1e-4 * tottime / filetime, totPackets ); + /* print average and active bitrates */ + printf( "%.3f %.3f \n", avg_rate, act_rate ); + } + + return 0; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcproj new file mode 100755 index 0000000..1627697 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcxproj b/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcxproj new file mode 100755 index 0000000..f6dc3ba --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/SignalCompare.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7FE8F544-9175-40C3-A187-7F15CE9A75D8} + Test + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir) + $(SolutionDir) + $(Configuration)_SigCmp\ + $(Configuration)_SigCmp\ + true + true + $(SolutionDir) + $(SolutionDir) + $(Configuration)_SigCmp\ + $(Configuration)_SigCmp\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(ProjectName)_debug + $(ProjectName)_debug + + + + Disabled + ..\interface;..\src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(SolutionDir)SignalCompare_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX86 + + + + + Disabled + ..\interface;..\src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(SolutionDir)SignalCompare_debug.exe + %(AdditionalLibraryDirectories) + false + %(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + + + + + ..\interface;..\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(SolutionDir)SignalCompare.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + MachineX86 + + + + + ..\interface;..\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Fast + + + Level3 + ProgramDatabase + + + /fixed:no %(AdditionalOptions) + $(SolutionDir)SignalCompare.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + false + Console + true + true + + + + + + + + + \ No newline at end of file diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test/signalCompare.c b/external/SILK_SDK_SRC_FLP_v1.0.9/test/signalCompare.c new file mode 100755 index 0000000..3418288 --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test/signalCompare.c @@ -0,0 +1,375 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* +* Compare two audio signals and compute weighted SNR difference +*/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include + +#include "SKP_Silk_SigProc_FIX.h" + +#define FRAME_LENGTH_MS 10 +#define WIN_LENGTH_MS 20 +#define BW_EXPANSION 0.7f + +#define MAX_FS_KHZ 48 +#define LPC_ORDER 10 +#define SNR_THRESHOLD 15.0 + +#ifdef __cplusplus +extern "C" +{ +#endif +/* Internally used functions */ +void Autocorrelation( + SKP_float *results, /* o result (length correlationCount) */ + const SKP_float *inputData, /* i input data to correlate */ + SKP_int inputDataSize, /* i length of input */ + SKP_int correlationCount /* i number of correlation taps to compute */ +); + +/* inner product of two SKP_float arrays, with result as double */ +double Inner_product( + const SKP_float *data1, + const SKP_float *data2, + SKP_int dataSize +); +/* Solve the normal equations using the Levinson-Durbin recursion */ +SKP_float Levinsondurbin( /* O prediction error energy */ + SKP_float A[], /* O prediction coefficients [order] */ + const SKP_float corr[], /* I input auto-correlations [order + 1] */ + const SKP_int order /* I prediction order */ +); + +/* Chirp (bw expand) LP AR filter */ +void Bwexpander( + SKP_float *ar, /* io AR filter to be expanded (without leading 1) */ + const SKP_int d, /* i length of ar */ + const SKP_float chirp /* i chirp factor (typically in range (0..1) ) */ +); + +#ifdef __cplusplus +} +#endif + +static void print_usage(char* argv[]) { + printf("\nusage: %s ref.pcm test.pcm [settings]\n", argv[ 0 ]); + printf("\nref.pcm : Reference file"); + printf("\ntest.pcm : File to be tested, should be of same length as ref.pcm"); + printf("\n settings:"); + printf("\n-diff : Only determine bit-exactness"); + printf("\n-fs : Sampling rate in Hz, max: %d; default: 48000", MAX_FS_KHZ * 1000 ); + printf("\n"); +} + + +int main(int argc, char* argv[]) +{ + SKP_int args, n, i, counterRef, counterTest; + char testInFileName[150], refInFileName[150]; + FILE *refInFile, *testInFile; + SKP_int nFrames = 0, isUnequal = 0; + SKP_int diff = 0, Fs_kHz; + SKP_int32 Fs_Hz = 24000; + SKP_float c, refWhtnd, testWhtnd, refNrg, diffNrg; + double SNR = 0.0; + SKP_int16 refIn[WIN_LENGTH_MS * MAX_FS_KHZ], testIn[WIN_LENGTH_MS * MAX_FS_KHZ]; + SKP_float refWin[WIN_LENGTH_MS * MAX_FS_KHZ]; + SKP_float autoCorr[LPC_ORDER + 1], LPC_Coef[LPC_ORDER]; + + if (argc < 3) { + print_usage(argv); + exit(0); + } + + /* get arguments */ + args = 1; + strcpy(refInFileName, argv[args]); + args++; + strcpy(testInFileName, argv[args]); + args++; + while(args < argc ) { + if (SKP_STR_CASEINSENSITIVE_COMPARE(argv[args], "-diff") == 0) { + diff = 1; + args++; + }else if (SKP_STR_CASEINSENSITIVE_COMPARE(argv[args], "-fs") == 0) { + sscanf(argv[args+1], "%d", &Fs_Hz); + args += 2; + } else { + printf("Error: unrecognized setting: %s\n\n", argv[args]); + print_usage(argv); + exit(0); + } + } + + Fs_kHz = SKP_DIV32_16( Fs_Hz, 1000 ); + + if( Fs_kHz > MAX_FS_KHZ ) { + printf("Error: sampling rate too high: %d\n\n", Fs_kHz); + print_usage(argv); + exit(0); + } + + printf("Reference: %s\n", refInFileName); + //printf("Test: %s\n", testInFileName); + + /* open files */ + refInFile = fopen(refInFileName, "rb"); + if (refInFile==NULL) { + printf("Error: could not open input file %s\n", refInFileName); + exit(0); + } + testInFile = fopen(testInFileName, "rb"); + if (testInFile==NULL) { + printf("Error: could not open input file %s\n", testInFileName); + exit(0); + } + + SKP_memset( refIn, 0, sizeof(refIn) ); + SKP_memset( testIn, 0, sizeof(testIn) ); + + while(1) { + /* Read inputs */ + counterRef = (SKP_int)fread(&refIn[(WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz], + sizeof(SKP_int16), FRAME_LENGTH_MS * Fs_kHz, refInFile); + counterTest = (SKP_int)fread(&testIn[(WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz], + sizeof(SKP_int16), FRAME_LENGTH_MS * Fs_kHz, testInFile); + if(counterRef != FRAME_LENGTH_MS * Fs_kHz || counterTest != FRAME_LENGTH_MS * Fs_kHz){ + break; + } + + /* test for bit-exactness */ + for( n = 0; n < FRAME_LENGTH_MS * Fs_kHz; n++ ) { + if( refIn[(WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz + n] != + testIn[(WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz + n] ) { + isUnequal = 1; + break; + } + } + + /* apply sine window */ + for( n = 0; n < WIN_LENGTH_MS * Fs_kHz; n++ ) { + c = (SKP_float)sin( 3.14159265 * (n + 1) / (WIN_LENGTH_MS * Fs_kHz + 1) ); + refWin[n] = refIn[n] * c; + } + + /* LPC analysis on reference signal */ + + /* Calculate auto correlation */ + Autocorrelation(autoCorr, refWin, WIN_LENGTH_MS * Fs_kHz, LPC_ORDER + 1); + + /* Add white noise */ + autoCorr[ 0 ] += autoCorr[ 0 ] * 1e-6f + 1.0f; + + /* Convert correlations to prediction coefficients */ + Levinsondurbin(LPC_Coef, autoCorr, LPC_ORDER); + + /* Bandwdith expansion */ + Bwexpander(LPC_Coef, LPC_ORDER, BW_EXPANSION); + + /* Filter both signals */ + refNrg = 1.0f; + diffNrg = 1e-10f; + for( n = (WIN_LENGTH_MS - FRAME_LENGTH_MS) / 2 * Fs_kHz; + n < (WIN_LENGTH_MS + FRAME_LENGTH_MS) / 2 * Fs_kHz; n++ ) { + refWhtnd = refIn[n]; + testWhtnd = testIn[n]; + for( i = 0; i < LPC_ORDER; i++ ) { + refWhtnd -= LPC_Coef[ i ] * refIn[n - i - 1]; + testWhtnd -= LPC_Coef[ i ] * testIn[n - i - 1]; + } + refNrg += refWhtnd * refWhtnd; + diffNrg += (refWhtnd - testWhtnd) * (refWhtnd - testWhtnd); + } + + /* weighted SNR */ + if( refNrg > FRAME_LENGTH_MS * Fs_kHz ) { + SNR += 10.0 * log10( refNrg / diffNrg ); + nFrames++; + } + + /* Update Buffer */ + SKP_memmove( refIn, &refIn[FRAME_LENGTH_MS * Fs_kHz], (WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz * sizeof(SKP_int16)); + SKP_memmove( testIn, &testIn[FRAME_LENGTH_MS * Fs_kHz], (WIN_LENGTH_MS - FRAME_LENGTH_MS) * Fs_kHz * sizeof(SKP_int16)); + } + + if( diff ) { + if( isUnequal ) { + printf("Signals differ\n"); + } else { + if(counterRef != counterTest){ + printf("Warning: signals differ in length\n"); + } + printf("Signals are bit-exact PASS\n"); + } + } else { + if( nFrames == 0 ) { + printf("At least one signal too short or not loud enough\n"); + exit(0); + } + if(counterRef != counterTest){ + printf("Warning: signals differ in length\n"); + } + if( isUnequal == 0 ) { + printf("Signals are bit-exact PASS\n"); + } else { + printf("Average weighted SNR: %4.1f dB ", SNR / nFrames); + if( SNR / nFrames < SNR_THRESHOLD ) { + printf("FAIL\n"); + } else { + printf("PASS\n"); + } + } + } + printf("\n"); + + /* Close Files */ + fclose(refInFile); + fclose(testInFile); + + return 0; +} + +/* compute autocorrelation */ +void Autocorrelation( + SKP_float *results, /* o result (length correlationCount) */ + const SKP_float *inputData, /* i input data to correlate */ + SKP_int inputDataSize, /* i length of input */ + SKP_int correlationCount /* i number of correlation taps to compute */ +) +{ + SKP_int i; + + if (correlationCount > inputDataSize) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (SKP_float)Inner_product( inputData, inputData + i, inputDataSize - i ); + } +} + +/* inner product of two SKP_float arrays, with result as double */ +double Inner_product( + const SKP_float *data1, + const SKP_float *data2, + SKP_int dataSize +) +{ + SKP_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0f; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data1[ i + 0 ] * data2[ i + 0 ] + + data1[ i + 1 ] * data2[ i + 1 ] + + data1[ i + 2 ] * data2[ i + 2 ] + + data1[ i + 3 ] * data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * data2[ i ]; + } + + return result; +} + +/* Solve the normal equations using the Levinson-Durbin recursion */ +SKP_float Levinsondurbin( /* O prediction error energy */ + SKP_float A[], /* O prediction coefficients [order] */ + const SKP_float corr[], /* I input auto-correlations [order + 1] */ + const SKP_int order /* I prediction order */ +) +{ + SKP_int i, mHalf, m; + SKP_float min_nrg, nrg, t, km, Atmp1, Atmp2; + + min_nrg = 1e-12f * corr[ 0 ] + 1e-9f; + nrg = corr[ 0 ]; + nrg = SKP_max(min_nrg, nrg); + A[ 0 ] = corr[ 1 ] / nrg; + nrg -= A[ 0 ] * corr[ 1 ]; + nrg = SKP_max(min_nrg, nrg); + + for( m = 1; m < order; m++ ) + { + t = corr[ m + 1 ]; + for( i = 0; i < m; i++ ) { + t -= A[ i ] * corr[ m - i ]; + } + + /* reflection coefficient */ + km = t / nrg; + + /* residual energy */ + nrg -= km * t; + nrg = SKP_max(min_nrg, nrg); + + mHalf = m >> 1; + for( i = 0; i < mHalf; i++ ) { + Atmp1 = A[ i ]; + Atmp2 = A[ m - i - 1 ]; + A[ m - i - 1 ] -= km * Atmp1; + A[ i ] -= km * Atmp2; + } + if( m & 1 ) { + A[ mHalf ] -= km * A[ mHalf ]; + } + A[ m ] = km; + } + + /* return the residual energy */ + return nrg; +} + +/* Chirp (bw expand) LP AR filter */ +void Bwexpander( + SKP_float *ar, /* io AR filter to be expanded (without leading 1) */ + const SKP_int d, /* i length of ar */ + const SKP_float chirp /* i chirp factor (typically in range (0..1) ) */ +) +{ + SKP_int i; + SKP_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/How to use the test vectors.txt b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/How to use the test vectors.txt new file mode 100755 index 0000000..827696d --- /dev/null +++ b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/How to use the test vectors.txt @@ -0,0 +1,15 @@ +Use the following scripts to verify the decoder implementation: + +o test_decoder.bat / test_decoder.sh + + Make sure the decoder executable to be tested exists in the parent directory, and run + test_decoder.bat (win) or test_decoder.sh (linux/mac). This will run the decoder + and compare the output audio file with the reference audio files. The result is + written to test_decoder_report.txt. + For each file, the bitstreams are either bit-exact or they match up to a certain + average weighted SNR. The compatibility test is passed if each file is reported as + "PASS". + + +NOTE: When using the shell script, make sure it is marked as executable. + This can be done by: chmod +x *.sh diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_20_ms_24_kbps_10_loss_FEC.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_20_ms_24_kbps_10_loss_FEC.bit new file mode 100755 index 0000000000000000000000000000000000000000..6315116d6a33a6ad7ab864a8ee6ca0914f445435 GIT binary patch literal 41125 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

^9F13f;tMDBw+lB>0Otr-ueh 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 literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_40_ms_16_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_12_kHz_40_ms_16_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..24bbb1c6661bb58fe88f7e5700255a554472b1d6 GIT binary patch literal 25590 zcmV*LKxDroAyY|AOJ7zqHvnijbV9Q+iN+AST}6T9HXYT~cK`nH5i_*27@JI|_fy6g zTi(k`gI<0w4&A&DE5+veD5Q_n|4;x$^4+eiiwFZ4iXn*7Z;F*#mCb509UQ`=e5*M! z;?3g=m$BF!g?gKZGpQ_h;T&Gb&PARxv(P(fMVOTgfwp%~ZL+wk^xzH&cH5zV)&+@H z07Vj{NvBdEFg`;hRAE`);H%BIH%KnJ;w=9<$r&n$pzGTXR5qb7;$xAiwle*u6Vci; z!UJGmcn*o}btXEb0ryL~0Zi*$!G<9_Cv+(h==zvII%rx^07dX{kw)kVaPwtAOss(L z-@lBLIsskieP0NMpeIz=WK{?V^f7w#+E{K?m8YvT`ugB_fDY31hV>rs08F8;O%I4l zoaKwuCs19LRFj%29E!r7)& zlu6qqbhZM(-y1+$Gkp5zHCk0GVgN?us#`a=`2uoeW>xd=T99Q}e#oc^xVPMA==o#i zW&6@fN#G)JutHwCEVDF-xLIYpj@qoLiCLu|D(noA98%7@QL?ztP>)i$p z94W8*1IhTv#VX*GcVU|+a{x#Obu%s8@tgZde3l_$*(%$v%(;ceTc{aQycFbycja3& zd~9c6M3?40s_?R41u!qG?*)T1D87}NYf*J?(zcz`eL2gVdmE_q%|2M!CT4&eg?N+5 zhh@7zkZ!xFz%iY8!}DCisoe*;s)?K+5Q8m*A5#ET4P#>;HAE>}+gb%BvuN_ME$E0BE8Kk`o}}0t zpdftg=`yKS$(>(T0Cg1=QERM5t%dnbkg2wWPE!0#Gxq~}f6L!!itp-hU*xsP^9I7i zpqP%te=cCoNVxw?9Hd7uA(VC}LmcW(ZTR%3{;fPltLE|2vZTsA+HL~y4nlQE0Cj>1 zR9~XQ(A?+^>r9$qkcqY#xBAUYll6BrU&p1)5^)26xlZ8}$qez= z+RD*b@>CCZOy+I_{zoGxv0(sp7MV5swx>XZH2n{nWe#Iv%ZE?8fHD^oG%&>A<{cj` z6Nob*(#vdkyi?Gqw43^&qU6Y|(kR!4r$%MOzC KNx0$BkIiucd8^(MV3!otkE9p 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 z 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 a4~Hd;BH>#daOV8E9oR3d=-Y&({r~?(;rML; literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_40_ms_20_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_40_ms_20_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..a8dae4d267743491a15740d81dc59fb47744c4d9 GIT binary patch literal 30704 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 literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_60_ms_12_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_16_kHz_60_ms_12_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..bd1aa1b30fe2aca7fd812870f9dec8d656820267 GIT binary patch literal 19096 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 b;+a_{)RV@`{?gKD?94zL-R^`t7!3YD1)GH# literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_40_ms_24_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_40_ms_24_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..02858e555854871b7a3ab150c25fae4bd82bff73 GIT binary patch literal 35977 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 Nc{h@|mL@-W|Np7VfJ^`Y literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_60_ms_16_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_24_kHz_60_ms_16_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..ef5bcf0cb3e3c822cc9020fb926c64209f9c09f7 GIT binary patch literal 24404 zcmV)0K+eA-AyY|AOJ7zqcL1itoaz(BvX1Gf(0(GE!9J94LWq(K{x2t@?V=oqO?4IA zsPT%vaoYvXV96q0<}|miTK4xPv_<1*j(!`r)*2qON)s-vF+mCu9FeXf)>zw$Hxzd} zJ#qMbM*g)lVj6x9ifMvYmv{eyEiNCsno~~)f3ljH|GEH+CVo=d;zk8>@F5m)-C7d1 z;73gITBRPxuOjeVy}v0kes?DC8M!9!>^P(9wEY?VF6R+^Lud zlR2YEZ^JkuD#`EE;>&%D>i&^KiL%hd>M?&v(K;hSb-~1Z5VHr6T>aTPYoM5**{aCH zd?RVWNfNUooyAexwTP^Sry607FNi1LsoQl9i~P{7!4J5vDO7v*=r7ji47J2Ygbs(` zybv^jYK6|LYRY*Xzl{Kjyjl%Hv%v~zb8;S#kzMcz^=_Hf{9{*jT(9s1`-X2Lb?%610R|;T`i1^zcoFrdF>OC^2A$41) zPw@XD&Ej9yaFLc6>{zI`m|u^eZ+r(8YZJbs=g2|0-{hk_IG2E)OmGDN(B}c=>g$Rh zh5)pQX|b60Q{ss)ungGJyQMCKzre5onWk`TG8Oem=qu0aMd4`|UDwN}`O{^{J)gfB zNmv)3uBGC7*!t^^;I5&s6333)aN>xn%-Z=Z>CU4A9u;}ZJX&nGQ88=23rNG=m$)Lb zH-w57MhLht^T3kZ6WwJ%Ys!7?DI@|D7Tvo;{TV0!jR3X8@l0n5f{=YZU%Le^JZp%X zKXuE1gB{={+zutjnBrstLP9-^RdjxHy~~$;5gpAa#VW*ny)s6cu{0d7jmK*$^xP(6 z<3cm2u z|1Z3mzpxAYZ4&G#xqc#E#`7PK0JTF9kZ`kshM6b^ZL6t~^laE7BzdC3Dm^&q)RI1u zXm4)&y^W>qLSJO(0-u%7=Z{Nn$sjnkG!3EsRhsXo6<8#6+x%^@uRAUpcZb|HJ%U5c zbK*y*V=0r{t1gKnrQcQlyacTnLZyE3uziG<&yfC!3$qCa|- zSlORMaZBd^lK{0pr1VAxCU{#8QEcU5vb5bp6}Z4LvHguXC@P|+Ez7wA7*JU}iz2F| z^nsMIQ^dM7PoF0;Y9r~e`tx?HsE&L{lfW*;8{O}dVP6LgniQ%6=JUNm=_ZAGuHMa8 zssW0K-q2CxJN23Cm65x*5?D{6GH-#;?NFBsP#lwvr>=feZFvG3O&|yJH(&Q!*f%F$ zUzPy2l7g0|Kk0_CCUvy6ny7iPnrWOEL+gsm{?|!oFD&_etHM2@+{&+z(PQ$JLXmu$vv#X?PzgtBLO-elTCHZ{%aOVl zBrmjm^h7bUGpYLYbpvO&qr1V?VSooYc#4@&vr#5m`wnWE<-rU{b&+R+jYTR~GK>JW zGoj!w))saTL4-MZ?dvRW8t^%3}@Ba8R{mXxg0JVAWYJ7Xhm~9^gdlu8U z=(XTi0>Mc)8}?;=GW~sA7jbR{D(p+1v9V6b+a7ky!MYs(BA>lObC+WAme(V#SRrvy z$&M(ezi*+;aVW#pxJKv}J~hX9anEl5JGI917AMv)+JWX2dY~1j*yooUuKk=ZsccabebBLsx6N)}+!jHlr}J1db$1_`oU$ zk759j^Gp&nA4nwpGMhBxpSnTws(Z9JVZDaj*~#vc7fM%eu;`WQU1Zm1+_Dw%t=c#_ z%+2v~a_feRwD96I=7)rXUd2Eg!;GE))5jxDgW5LRYx~|VI&&<5RM&bj6Oa|@|7ifP zc(qfPYkPmL2v?2o3Z>2E{p@lzlLA#8m>I4%g3ug>e`0wcoon#&}OWvJ!&bH)FIV6v}Y zTL7%$`pVk~*f=$Al2dw4ex+>YW%MDVZOzl&z;-54?7wmZer$T(U~BN092`R4YyPMYo5r6dGoM&bgK-FR&s+enoqY>bX4phI z;t}-Hg+U)HEMAG1y}#E;sj5w9Bi{v8+gP6)R3%pDhZ0&{15>tZcjtU{4T_jr7z$>e zjNdoTdV|x`vz{#3i|xH^QP>DNj^Y4{LKCtJg-Y{k0IqlvF)(aZyMRR3-41Z?N+-3< zZ*cdSb&9|id;6Lr)TYx6lFr4eUuVJ&ZgH%d(u-ap)Kd9Z5j=P+c7?}cJx`AQFx~;4 z*o}13O4-qgo&w0KWPWqhMj=3?c58A7!vk>pVjT^I!w_Fh0IKY#eyNLXQ@9xV*GH69 zir27Xf2nqa(7uR8nXH;AzogvEFG)j;@mvZP&v#H<33tK-$=gjpJX}Qi`3r zJXgX?=C81zjbAMQv%2Dvw2rsC8%})Vu>%??te1aL6$z3@H@rHJh&JDylNN2#<%hq0 z&B%C^JT(BRok7reQg$O=UZ6O)Iz?n3GcpiNZIBz26qiXc@@WTHKju9 z3a-NeYamT1pxD?)zAU~%_J*Jj)g%6`l$=@4j|NFaCYETZrrZs1dgdB@w&QGBqg8jW z^>CtkWqiFsLc;nE$#m&*aEhJVuXF&Vv?QZANgv(EzvdNDp=)8~Hg-LDc5*3;C(BoJ z1Bn$(-+vv>-n4;Kuz1`EWo2pw52Ta`8O(8C1a1u^(IX4maKQ({l{0}8$!#)jr0O{0F8}__I}oKog~NEp|fFD zlMLQ4OEBGX6Z{)3RoipGQH|!N6+)xh0H7(^o^(|^&U&Yv_GQ_;WnWV&al^QNLn?_9h_4^@`GZS-d|GC#e{uk%Vy0DiLXG0P!E@2w zCv3)_=b5A-THghjrpo})dki&LS}q|ACy4V57S|4jJ%+C~=s|^Qm)-=z@l+aC{duNm zenmyNV&az}Qo}FhG?{j7NmC`i>W~eSWy5rXw;>vS73ZkNMv=`A2g#l!mXSCLe^>yB z+J5rtRFmxt(6KHS4|oHLsJn=EuE{Yi&3Zo65@hPakFTD3<{wtc#U>(m=ytNQ+J;ND zL|U~{(%UI+4c{QT*3wVFrYqg1*VgE%o80Hs9b{Yk7*BeARXGmr|q z$ilD~kHRGf&HooqX9(=x$8=`sPQ5QRhGv9B!RSt)dM0C%ch^}mfJ;qk8~~ zYqSi&bn%ca!%@|$+bLQKVIFFOc2~m=eM95t%#bMomANnfYM@5{dc81~WH>`jB;gs2 z{1pVFP14UTN5&UnHxSE4{)4p@H1?=w>%9$4^f5+x+8&)fvB%M|BbN7(B1%VtOwkON zL591)Y)zA+0O1Y6Dk>=cm*;W-id7c~qsk!9{YQZ6vxxHBZ#6ig!K(_baSh(WsAFxG z9|kIi+%z^XyXCc zG0-=@JajO>5y+Yl1HxmWS1PvD;dq;4f3id*P*j&M4y!3(Lci<*Dr7e57ztbfaw~rf z5*4g_nm4{I5={u&9{V--4-hc0el)LMT~XZWD}!cWQZ&}J_K$}EjIPUt2%bNLe zhOom$@Y3NzU`&e5(>Y^p=*raL0q(+dpA~vtTr}OWM-N5wHxOVr0xWVlNjGK3HDZWE zP=8aPNHlT*#uxJZ+EBe_aPrs8`+Fqb!6@j^#iu0Ph~Nn903OZgzYc(1{79 zsu!0*a9}hxAV#g9dtdyicEcOY52&J2>t{Fl z|9~;sT}eiY#Rut-ORTC7yN54RjftU7_cJs7Q;@-5PXMHiG(#Is#r!E&JO{lSVl2bz zEhC6#vFyJ+3dHVs$=Ml7ry z^{R)vBQr55-)aDX0&d`RuF)#G!ol>x(7%~I46RjOt4aKCrs?&=#r-QovnqAr;9O7h zSp6|$W~b{%*}*w5EU^F$Jf>6KUm|tVL{tw`JktSLsu|!Fyz^z;x?A;leLEEr4?(0y zn}pBzTzg%{WO9L0xfNX4U`vzb@zAIe(uZ`OefjLm##``4k%`JYDU%tghYh-~MPkiEk2(pjU>X^p_3 zC_i5$dxZEZ9hi@T^(qMly3aV?em42+|FK_xGXSNE0!?>Au9g_X6`VLo8&8!$!JC_#uX6yU?HPPc^ud~*tbVkXunrkcj231@ zv-y1~l12NnN0XJw8$MBqf+~KH@vea6pJkeBF=twr!<7eHjWgM#{VJ>D3+n3u9^sKh zU-tMMN#b3d!|Ek@8^%h*BqNt25_&TOndX@QTq5l?{n5lZmc=pcn}1#arFt9<>t{?x znKyVIeM(S$R!1fnvNm#vNfQ6;;g&* zY@*`kyVJ+r>*DoyXw-iOeeKrkDKy8(`pgB+P}8=|GJj+Mfm-$)S~+y906zRNwP*?Bmdyu~<9P zeb)hNZPwVTDICdFn&d-AV_&8Bl1U78aDlL2W=zX}asY(o7up0|aXqL_F*g=;6121y zE?oWn7ow}41U2+t!q;F?@-0~zEYR}WEmWut*^nngO46d7!+F0F9dWljVj2zXox+8P zURK`3zVZ+TxS_&8wcObT_i#taEN24+)PXXi<|sHpak@+E#3c03K33QNcL1dRX*q9P z5th3L=!2#4RX%q%C~qB779J{$Fu=L*v_DPo>-zn zpC^wdLKV4xe`)}RNR1JW1=pvU$Xiy1@q*I&q4F`O1i2ap4A@Dn!*_qkdQS%Kvo=uP zTC3}uULe>Tn{bS){?nFYf37yKBC4jJE88~E=NB^*vu({JM^4ei{mNc|t<7#PA)a05 z2$e3Q??#YA&5}&q|7ZZDu3-U1fq{@k!4eXZpmo3R=3O9t<_CNn_CT~*x&MwY6_Gs9 z5;|3RbcG&?3P*|iksqgQ7RE9{ATSal*9&{QBqRE$PhdPzEhNH;u2+XFc4sm991;8- zYEfp*{JANx08yQ^F!cX=0JRb@)|-+fW2#JlKJt3qZ|-u0;^wbKN1FF zI{_uiO>Q|h7))F_7`7OEI6^S;H=acU9eeWAQPE(5F{~GJb#V}+w0=u(Rf1=GE^}{% zr$=9iwt(g`HI*oILk`cr!>*7z48c^N>z(6aaWJ#8=p(GeCv?Rl1WvzW0EC|(d^HzN zJ_zlI7TyaDGiEu3O=$X?5pC_3Yq5GE_3*x1Kr=4=I1M^nY~3v-jEcL}>t>gLLu^XL zV@DzfUjS~B&wiS^vT1uvLGl_khZV(zNX~PMKg9gBF~pZ2+Zc^9{RN;U2hn z&91%n^*DbSQc0`uRh-TVQ)r3FoWh8Za>dQLnk6Bd(!*|wcC;@|e#R;f2sp1RfTRaP zovOd}SH$2N+dJPK&q!l{#{*flRvYgR~_v|Sm+9Qa;V8nSd`VYy#2@Oy#s zKoE1Nx=l9bwcdL2|6Bls2m%S`f)`R@@#+HnkXY0Tq$pcM`7q;N?zNT}H<;AXMah)f>ORtj6 zT>yVf0IWHy;8>CFHMF(ikB8h+c2a8hxd1Yaa2aZC2Kf*W>3odYmx4X;x^3lNhLgiD zp0^5uX2OAAF^vp?1N7VBSlkx)P|gFVF#&(}TR{M-UO}=M%dR;*RqnKaeKKW0^ns$* z?&eqWRFj*cpp6#Ed$2ON!LC-5byFFv>4}jTm;Yb*VCP#KbPd9O# zS+#-Kl|PT90xvSJ4`yPWpq&uUj=-t#DGFWm(=-xWD^i;G%*m-M(8`f|)RZiLk>qAn zOh_;Y+XtSQ8WIC77(Oo8lK_ypfa-rUmQ!;N z&kiPlcTiC)UWaw5)*kAmar--(!o`({$uaf4q7EXPYDAO4A01B+oUu2ct;Xj;*ZsW! zV?JAa_!Ku|cThh~(i&a%{p?Hfd^8C5&N?6h3zNQ`ZV`jN#JMSrjtZTKZ2hf#N@9ohaj?~Par0&B@8|1H7201Ll zU_~GQ(HS$?9zke>w}1!Z~%x&`6U=x;Y~Z?WmSyY zoZ_S-!=y|1+x}3af~6eVpPV9IUqq zX-1f&bJEcCH@|Dqo{}75?FQFxbDAk{>xuy>|08s78Ee#C{0H2)|kYfO2lZ z6tY($Zy;g%H1m{9g`w~!Su6s={2U@4=`Ocni!RK)S1+x2IdXuvqxVWd<2m$y`MuXf zLCs!cL?@j?oXiQTE}yXGCf z`T7IrCr0e5{GzM{6ZEo>t20A3>#JOSiu!24xbjZ&lX#pU*eOQa58^1xbW#6{ag84=32?{Q?fh{5+0-Mhk(wRAC@i@#X&|+k*dxuLi)$51 zZYhFPa|YpBImy{dIPpZy32B8U9n&W4hpT;C!PIYN0Dol!AY)V|80X4KEvzc@ppWnY z&}n(~`vq*f!%&n0+u%h=DqmK^C6sx;{ek@O8mTkFqDlbOY!ByTg9v+#TH!sSjo*j` zW}3$Q)8*=)p&UxRImdwc5uT#nZft5QJ`=6l9=FFE%>)! zRe{wA%a)jliPKL{9-^E)-CNgj1G!7vxkRrm7A&q_3sop>wgU0is z;T#J8bpWs??Tbu?2mI($d-`FcM7jy{P^Q^5DV{_?vF|VPB8B}cJTTJh==A{)nuW~&| zH#VF!enOG6oh>Gh**96>pYwln0EPFMOo(DazpYGOWo}g0?UPy2(D0B zYtF5&MufS5dz>KxdC7>BJnTU7Ih3S<7pOoK@2o0+SO9^c&N52grRzI_h%@B$3Ry?# z622roI3y3-k+^6On$uE#qByn$+8M&Xj842ffD^Lasy{6Ns;S>mHge>#ymP!n@EggKlnTpVs1-3N)!H1!Co2u zEhvYoYD#L4k^{y6bpVB|5nzbaxrEnM#)UhJJ&TrzQ$whJ1)9s^G4l%L2aSWh;4)}d zWg%$VNX(km(p;gaXfy%6iL#OqB2SQ^XN~o0XI8;rSM;} zdWPKNg5NbZG*00&J1@MT+)&w_x%t3F$-6Ke4CjN`63FTao#Tx@mTdZFN)E5+!Y`z31 zSc^3PsV(vijcyGy5V5cbw_O(#G`a2)7?a!BitH00;Yn_{=$e`Pe>?wXe?S6EN9ROL z7;&31#Xtb4qDWrQDT-gkU-Tz@%#8>H%~1X!v>^(@1~ZG?8n?Rf$b|!km;O#aY?enY zFDelzwtZEwmU~L1YHOYN2?t+q0HrjzJ<-lI0Pwo_U>buIB{gv}GRkpZpqms#?`|Xq z^b=1=n+Ebv6ys+2s*UG5e|2INac*VV{0RjwOJHKEGNgso5T`2T_RrMTnO^5)Q zRqjr3;^Ms9?HQ_~k{6F%#RSC~cfS(aj{owlIIeztOk+bw?t)T`T;uC0=AShj0KNFj-yb6%w(d2 zIezc?LnYUYjG1xawl$wc0I4;1JOkDY#P{WyCaO#LnQ59NPdhUELJ?{aZuT!5YxKJi zUZ8eku^Ip$0*PT4G&ml?TIb=Z%IaV<`tu^kUpg-W4u44itqJTaDd%)u6dU)lYuAAx z7iEA*P~)ElC`mCgn_=IeKY*s|79k+XW8OBRe%|*EKN`AU+C2)E5U_f&X!+YBxp+#q z=mvZxQ&Iqk33fLM<0lB>w2BhZ?2OF`YnX)yt?Oy(2SyGx_i&-*zQVE0TZM5i9n2FX z{)j;dQCE!7zoZZP$bu`r+1&~leT-BgkJTt2gQcW=&f4a{hc5uBHFZ^)wN~!jbbh5$ zN4sBE8856jqyKIrP8gpK&Y8IyVLR@(D;*!?GD%wIq-;N^o%h#$+PX zDnw#&``gezfS4xMY6=XP|IEn z+Ep`7yp#_x_uWN~mPNA%A@PtJF1&y`efc9)D#q;)^Q~kPSR7}B!D9JQQ z*j;xkb2qDR0Hs;aH23SV(Lt?P{V_97GNG9r?Y|twlyt~Z{$({ES`i}_4InJgK~%wj z(vdNO548?O(bKP^vUqDxsA1s3jm506)klytElTJb-7E@X)T+p%;cR1;5PtwM}mR!lA znnzhPv|8QfIvf~W**~Dp;q7i+2F|msiK&oTvWC`hYZQQ>7ezQRfFSw@2mPQahPB6! z{pj-V%fc@Hy5&g!cmRp;98)Ts=tMNme?ZVWul=P4Qd|`9UVAk41WlncYWa zEU8ApY<<^LnF;ObtVTkWp z_Y`aUbWZvcQXR=?Rwfoqq%p6e7&%`>f` zr?9lU;PFXoCJwJ8dH*rkXRU>g8xJ$}sBoIh;DN?YBPQpQJx;DcLv|KE9EXN6bUmwt z>Rx00fk-sVwWAm4H6N^+uPZk)hd6v5Z{8$w+4it7eYCN_4py1AZ(9I{pB+b5I=WlE z)dPeq`zdOG-ec!spOVL%=Dl%yJCGXm`#_(da5WRaj&e^l0prts{Rfau+r?ek(xG7P z8O%PyE3tBDeU3fFlh`uA8CX@N#lUhi>TE#1kk4}feLt@sfX{j_ssY_2w*`sZDef@> zoEI35fs10e%KP|$lR=9yh^}dn5xMpndsr^9MI(zX#I;g-n8?!27xrj&THt4XgvTgw zNcS^6O`Ka9g79I{QR&~58IRxyaYlNnV6-qG*k+#K*iJ=G#7;Y>DXSWBBXRG?CW_>ZE zUf=J1G{*5%ilf%a5T+%ME0da2rDlPTo0;XG&58I9 z!~^0pn}3~9cbkF;^e^7m{q|2WAqd&HxHApdD$T$Wu|j8MD1CR{*QV9ql=p+5m^OZKa`vD0~(-!0d*nr1@3(@=jHj_BfY2oW3$Kia~m30y!cDOZ|RE zRQ<)5d+g0$2PxEJXN=D+J;h1!sZ_+-$krdUs23s(k5nHTvt_YRSFvS7=OX+SNYG&W z_n%|{rK*)je$gZv%)5si%N#=fO>Wairot)PioII}NhKV(f_u>C!+6#YgRfjHPL~V% zuOmafVkp&7F&%U6V8tKJyR1m&$69oxm51UUeIF-U$7N4R&alNs~BqdO@rB-X=nvmUp3qf*^zkcDsC=1mj1Dae`o-u zH2j8W&JrNbY#PVd*RtL5r>aW+Wwqy_??$k*bGmL14K=1o<0X@xKgSfGn`Qv9HvFkz zBq6HzR?G1LCZEc665}+|7Zcnbw_rm;-JQKS-bu23Omg)t_ckWy5SQYufjxF zQQ>Q!zL&;dflgm{9U|LZv*cCbJW%4t_F(WZHm~G2_{AE3Gytn1j$3&T{=>Plp=fb& zT4#tvtqzec=KL3F6P!aH)v|t~t}%X%fJ3FRWsst4G#eE-N>@t&sNS<=v}}X$=nI9X zj?=OLad?Ctu7?jD^73bHM(Okz#{bv_hE-i`>=Jb$B?(}@Cjf#Z**sRTG$pQ2-i;6m zmvbs+hp@?z0ogZm0F&DWjq4&E<-}Uaet*TspEedF_}R{o34KG#7!5B-Z0o-yhh+Mp z7PBBy_1^lYYlTa9@9v2U}556C{lBBQL)D>W0UH>-UcK=Vp zU-CG^pxOA8bviBcoiq6@lAsdxS@bP~WdMRrs(@MyRf++I&$zIGB`S7jk*wMpxK-U12%y!Cb;RK==^{zD8#q2SBl znj=IbmB&?OT}Gcu@M^koie+s2UG~dUHXd66N*qnii7+;O@!+B=rU&XS0VV(Ua{#p6 zM}*S*x%mn4-*fxWPnrFPkSu)oup>jR6qTtnD1M72re(`5Mel6WlW$-UX+-3t_m|RE z7?gQSdFSIbxsAn{Qxlitr~6JHfra?p` znQi36$3D}B=DL(+P|haGBQF#ynK`ZuAK0>vfyl1P@@yY$rGhPK*8E26RuGfr)$}ZZ zuVeTs=1mB9ftL(+=(+2GKgI@v=c+-`RxU zdnKpl18E!~;`5vcP5PYmDXXrOovqtnlOc98=zMY5RAtbMJ2;J4p%pJ!#l_JW%0dLu{cu?~GHb6TvIHL6Xl<@st7O(qD&EnxPz zd6cP{}mC#Ji9z@&OKmHB2v&vQS>!TPBSsFBDA=b^<$NKkI?;D%v0PFp1wjhWLO ziUY{KK8;sm0FlM&@I=_b&9Tk8ed_Q`HMjI|9psN5Zf>0N!9vZuTeO+Q?rx}r&xQS6AY&F z2t6S--X#7g*mVl!T;=z%AOi{ARlpb=(PtCsuu+Xg%2LC#Rnq+`Q+tVK?ofYy0E%fV zR=2IVD&Aw7-1vns-vCsOip7#nlD+(+_t?s33JnCHg11LbXdR3$)i&?U0M=-eCTG!Y zO)P31mo$!Wm&cXtdNOc00Egc+jB}pz@1?W9Y$cgp75X3~;t9JwNzxCq4I^(e;*G=Z ziKpAswH3|%6EC22me&47UmJ4(wq{f}U1hvI-n@(~P{g!TivHtL-$tbV2kP(4CRP;W z%r@ekNyd%d8jMuUgs~bqjFphdhz9Ld{EY4mA?b~}z6$<9$pTvA@YbM;%K-uC>^<1p zbo&dK<6~Pny+}G1x52-J+C8T4r96pmFVfAR8vd(i0E#uC{&E49(6f|>wKO*g0~l;0 zcCE$+cMwXEYTqqD+xkubTC0A74~1?YTr|%Rqc<{wm=7-P5_&O62L#EU3;b(RLx#licMF4>Ef6;frrOjGF`Oq=dTjVsh zGhESp$>-KW2gaFJjWUM-@{2V#unqcpZ&EGC6EG zNOimFy1$D6qS;{9Pw#csv${=Ve3-)tF&V{ulQX)slg!G{`crUc%&pMq?^G|1_JTp} zqbo;_A(v?#L4KKrDn*GbP;i42up#-vNt3F4?$>1Lhw+m0iqbDIXbK9aX?0HX^ADXD)( zyL@Ad%=ueTq}N7Be|Blo0Kc^luq4!+i3O*u-?G66ip|iT@5)Lck&WJuCawfPIfe9GZ!A9J#@TvrtQH z0Ezqg4#&>QeBxdsqj|f~<(_ZYsF2*o0tm{<$)kSj+n52$k96=_Pm}-RY2vR8)v>Y9 zCH`Qpucp>;6rcG^#T$XbgrVa8JF@*4EK;_Kohf1bPdt_uy$fv@fq?v%eRL|C@d#1k zy3rbt|9$|ED;tF9&9TvVNn)+MsrP5NF;bf3ghwAx0%qCGUg9t&EdX9@G1U`xq-;Ha>fsf`OE-=$+oD< z%B5GhlZjU^dI2=ABaivWD29pT`D=%H(HvIp|6KsKV}iT9Ht8>O4^0mR^VMS|Cqrfl zkxFb@HcZ|hhq<#~@$RcSG0~xwdF?xfb!}{R%ry}$XOIVY!7H`Q3MH^wJ=~xZ} z?&k~K;QKYpmL(97RA(6je;anIK?NQSBf`0nNn zjZ&TdMgVY`PcVuG-71f6#s7S7U%6{F%C((X(rPBI2IG*TL4Y(MteHYDx&OQ-Pn6v` zfN=&XY4YlCV7;6AO4c*|v-$p5vgseS#!}v&yo@a!0r*P!FMJE){z#*< zaR8&Hn-R|+26!g73@CVNdK(6_Ucj~nF4RHA0js|or_9$dfmkF$vhe;JK={N-IoKG- zw-%jb<-0K<_&v?4L(1%yVzfDKnsa41HwZqK!~WnaWM#NzJY0yN{Q-GWf)XV80QI^1 zZS$l1U88;~a|%yr0F%PDdP4d^(*c<(O8MxCc3mo5SrF{;Y=*`c@|)2LaAU`#-1bqq169}oi3oYSix8mIN3KX+_)}y}^k2_=et*BtW`y=&lLAb+_$2Ou;>p0< z2$FcKQRJDZOXv~JKVSf=fH=1YnvpOCxj@(vxRbG_o)s7R2+A#R9@eVO!8x|L$uQ*? zvxG(Mo9Vu3y)LS^z0PPbmu6#JQq|mviLx@?&erxIb535j8B7JkHKr@i{v{Oul}7CX zYJmw3%XOBC0I)Iig0Cxh0d5Duh|Z}#e(*NDA>hkKS2rkN5rvmiLH2oos$~(B9Huea zda|xcvsWQmW8h4hzw&#){?viBt5aaShU@CP(60U}WxbwAclvL7*vD(|c<|Q0`=P7i zrrpl(c2pnb?ttvY8(JR4wMjsvch$uk@EHiM?n$gZ)#(hLi8bYL3%_3gjR-0#Z#^BylcdSO94O1~nq=jO%|LWOZlDuq z>-R*D)s;cu(ACDmFm*%4>WaCpJJG@z!u9?{cpHS4Ri%%30IdP@wZcq;$Vc+pXyAw- z7LKLimO`iLj&HQ-6i`XhK`s_Z-K{}snl2W7jaW3O(0F}GkG(+{9Ej%=zV?`wdLwIM zC7-=JN+)8kAzc&@Tk#ifQIN8t{umxQ9NrY?i-wrW(*NzWNTtu!C=&`Z!56}q;Dk1k z|78G(4+!wG9UQ2f!wKKX;lwh)`2W?H(K2(N^%DEZnZi8$CtH0w2nMJlTUV1ce zr5BM&Jv-Z_OVM^+KvDQcTQplji@k1Bi*ly934(14B-L7WaV5({=f!=_S% zZ_a{@XCNbLS-0@s%iUBT(3C&Ve3-Qs;@*G${s}Y|{fCTXBWcA-LY%8zcTxa>nepPj zAh1CdCn!#ajv7SrjB!?wgE5KAZs!0ZE#c+Ewd9rv=6>vb<)~`v3rR*_#Q-6X^X1i2 zLDuB|&=_STEHDb_a4P! zT+*Gov*HeyPWsdtkjcTom+H&PO(X6*2Nb_1DbG07;6`>wNdDg{aOf4*3q(7QAi!cb zlp`l7hRZZHL1nw_2^cDTFCMB6Qv{3wrKt4El+wbJcg=r&0E}WJ^acbQSI*5HU>c7A z#|@Tjj3qG{c#F9~b z-*4 zrpTOpCaoV_0E%_%=3N)%^qc*3!hdU8rj|?d>tz4WTE|X-DO!G{biUy1uUH1)wtCv7 zO-jg`)ft^OVKfyia5HdwM~fpY>V@Ywhr$tEdlc!)x6CWpt)%2WY_GZ~G95;{^JD;o z6xr6!rZKK;LuSV<&i6(JS!EoNnEd1he9IUePBzRHdfm z3_yC#s{x4dH6V25I8=E`;*^#nXfs0UmLZTDvs+F^>`Yo^nn2{H$7I!1EMjkD&1#B1H`id4 zJW}@Y3P=#I27G(;?xH%TmZU6>2G!hD_UU$Fl;9geRwTN)$c|q)0Ii8CEfzl5lpq@B zuDM!Kn(M~NV`f%x%Q0aW7xP6{_&_V>$KMo5AX#Wn2^4v&d(}RZYwPt-hhPAy57klb z2w%MXU$I7+>SJUS6XB#WFJPUd@H{T$!DhRXAE0L>n(;7{tu9y9$DUX>yPA!S-9UYm zbO%_X%riPrZSAtB5KSjCipa9ECpQxxX<2K4@?(!#d2hh~wE~}e0HA>iSKrVd3tlU= z-sXkUddm8gZ2O#^#t_@#WLpEDwhHW4hYrX>9DeWHq|0yXCrmvrg8QtA5;%cn?4Zbt zfDXI-zqRFBMNF;oP@ei^MTFOE)iCQOd&w+rwoXLLL6xuA_4X_8?_GHbzItjpgtCbZ z7m`*>e4B}HcL19yL(((bz*f~!74l&W1f|GtUL7&>$d;K4o^6D)76ZVWe;+^!>*7x( z!Rxj1V@1Q~n7?RsvS)d~0a^3@6{Wv^&I5o!*8+xZ;aUQ@QDPsRA%(}j(gQ#mRw#G& zG*rD`%u0Fp*bRtxHoOQJCJHHx9sUP)|6c&0H$?r|aNCuGiGWyV4Qtn|Et52`u|}gQ z7+CK|RYor65(yQn)T;0EACcy%0Wzk6k6pTF5=$s@yZ4>Cy*9AvOKGEtm%s(fi~Hye z=B=@dShAzMYM_XMHa(VFxu1OirR#YE3$Iw1=K#CCX~BfLm0?w4)PgTbc1-=BE)6aj zDCuwiERzkXfkzrNm#!z$22L=&sb*r1vBWZ24h;JPl%T>akL+_Q!65dn7QG8hrL`VK zr#$|>-#!c{*(`72g|>PLmeW5hGzn*&Zsn#)c6xPv*L(Z<=!iLtzj6S!>*3mqLF87t z)&7smycl6;z1V_zE76+`t1Sb#ZE*9rkKDM!zNBN2X6kU&Xa`aWeGb0Dl62ET!x&{+9Gey3F{b@5u}FFkyL8C5w7J>egq zjnB2A<-Qv@)uea`DMCNtC%K;|ZiZ3O29j2?CHs=m;jYKt8Gv6@m|<)tSrS@V7s51c zkg=z%f1X%A6AcZBsu_bqwf>ef7Po$XZvdu;BC}%h+e&JIz-=TY=nh-F?e#T#{~0p~ zhJ8FsY*Mq!0V5yW;EALLp7!HbH;+=^Y#|}*`C)E>$&u?Fit+85{}K{^xu+NpkN29A zJ!-)Ig2WQlH>XBymb+TPGUa0GXpOc7O{_=$nkK6p^<7D$Kwn+}ppV?@h7e6@lk)o* zk9up+Jmy}1w)4F=Sz$iKblfY@qF5o*BsP@sLRCZdf$-S*>L}%iAT3I{f;o>4((g&v((0Yu7WtJo^QDZqCCrybb9OuCZzQa8yFp@C*+3H~ob z*ds;TYBwa9f)4ez1bvV+PS!W1thE4>En1W{A|=bW+<-~%b6@0CJa{83CSo|Sv`ui@ z?<+9G!#@jbE3I_OgMV3?&JQz}J6N#fl%G&4`=ZiOCZzGhC?+3514z_Q$Y_6r0HC-d zC;VM=_7NG1h+s)^aiZ(w?xn1Y-(f0;yz>1c8dgubRo{Jh^{lSS9Yb`_s~p#Z{TJNHHAQb)Tr|uU&b(2$~>x-)iTXfabRP4 zo59$U44U}>#TMY?ah~U3qipznr=;V}|0vHMjlDyJ`Woe7;*020$S|X<(d{Lr9xhnp z#k7?7VvwV#S}A5d_iyBC=1K2|zij}ZxITx5=`u3CvJ@QiOfG~cQ-?cP%{ZT7c(2aI zMb0(=w`?B-Q;E#;`RBA2TjLr5c5DDE=oaM6--R!45`&&W+?4*|r_!oFcC7-eX?Z_Q z-hO3di?S>B#Gl;Ukfx(T5(Qrl#|h_8h2rchLXI@a~-{LbNv z2w(m;xJ0tiRyk%;=6!TA76-P>j?iby*0#2; z62w%r!xf~c54vEIr+7P0AH7X*r@pj8nJJH_q+-m#RWrM((kf?W$}Wt`H?6V1B)zzS zo(JnIemj410HCTrBD)7^HCPo34A2nIxHBg0Z|6mojshCOh{UyeyIour4Ru9TpGE8` zGN)L$!j;JNhpPh)q;WjL>&QC(F80>5U%+=7xorfITz)!U1kF+H72XQdyLR9{Pvn<- zeKB!@WN|X2IHHT9%31q~y0pJ)0HAn2T<90enq7~owV4OOR5bTNXJT98j+ym;$+(fx zci>t!t@816{GPC`V+blOr`P_XIv|fKfi;1a@c9mFKPC1%k8JoQZ?g(S^3pmQ5M(Tz$8f$oPHPS7B zRWyX$ii!p$Qx=BK-$e&ek-)U+uZRj1smT@dIf8e=ZzJH!UN zSB#Rs1V6z^8s1*ZK`6t2+D1<3ik!29bl-0Ok5r)xP<{|L1ke(eVUbMfiS-+gI3?Vy zk8y*7xj%~lkKj~lJimbLs%sQ9w4Jok@r3Ofz#}-@r-6Dh@VGYwj_)cw(KK*Uc6p4}%&u zt*l@TxTKQgtDd>~37_u@ZBPeE@L|+u<2kr~gZ{q4gyuVdUj2~BXv|$}b;(5|taMlJ zRY{`jB9cDhZhTM(e6axf_DDKu0HBzXV=pDws}99FQI6rc9Tp;JQepsf^OwJ9+k zx4;STN8qEZkly?sg=w6Zg0#?mquOrP9A!#9kVh8Tv>uCxhXBb?!+|A0KxkGTU`|aa zl^HSl_00YP?rR&Kx@A(gY5<^lK4}_9z7BBTwUkI8dFj0OvaoJr&PH`>-)iHx94kRr zhmo8R^bd&!JQjDImpe_7SbtCGH7k5!(g`0HrGiQVhBS)Y(kXWXZKHw*P*PeUSXMdu zCSx&7jx#2%&?;Vhp1(kCjRuB)Y5=Ch89_f=6%mqdLtIa=cT0N7ui4tSyYm|{pOfFG zEQjT_4lm4s&7`E}ffFhhLEHFEQsP?7*Vp!mu+#J_)sbuPS!KUf^*`%!s9;D8-_#Lp zzqJ{GqlUvB0wsW(5p7fzA8o2FQAR^t0Yba*yJS*xBNKYA-6qocLE!G3U zCqn048%}ba<^zaHzLw+A(BSb2KRW;35hrA;_Iv;_Y!l6D8lP`(eISB6E^QpGfCj?4 z`)gbs5`4a{&fFpvQ#lh~WdNq`@?}PEGNOpvxJ&jQu-MyOEFG^N@V#b6g_TZ8vUzOh zz@mT^wWG9AX1=3oA(@-DLo*8y zZ(G|8nco6R?*E%Y_R4>H0G*~E=h7U=@0&FSfw|(HW;~CTECSK{hC#b`&0K7?w7_0A zN*kBPi0H-Kvo`Q&E-C#8hZuL0;|l5eUH4vOgApwG+pp2|W;MrBqRT6KQ4XW9!hT?i zpm$7@fQ^8L&l`UVTnQ^?29v}-o}BWuOJPiRsm*f0G`#7|NIx2o;6as9fM$r zsxddHMt*gy~e$szBf^RHpBHM4Za7#t+Vf_X_CPQSlDkIN zoB$zn8^HCgCju&|du_~96K!n}M>CT{X6po6gg_6g@aFGD`qLcML&fj(oU#=bct3Wd zA{%ehgn!2WF+=azmD%uNX~_c4Rrlp|P7p=k1crn*aOoc(O_f;zAXvBzjAsD0@o;GN z1PPqlg>B}Z{{WaqK4nvGD-fYyt+$0IA%TF9k|0Eeq#6sMy?jIt*>QaItAhF6Q{&wf zE4~zbPK1GVx)TYV_(vm=^!_yb^)xV7WFAkU-F4Ys%r0LktN0BtKY>MHjL%>IvA;(O zdA=`g=0OQ8j7D>l)qn1G!hfcWQsb`Nf~-cQNFDNT{sq$LgQ}{eD{hgAj?St(wnsrr zfFRbQifx-)M>>I(b*QoebkE8vyKgqMi`oF~`w`F7ZYm`ZICO=7lK`csrS9%p0jGzT z%BjdkeA2UOJAuwZdc!;exH&fp15AILrS$wk=+Va1G^?2A^z`2->0W)poa=F;VL0{R zkxpaN>z6kQ+2d@DXt0^gMT~59&TA(Z=4%W*zMQseh6EldwTDPemZ%j|zTW15v#`>? zNi1vM;r3_A`_{8<0*TMPEo15cene;Te?WH?ic6rIX>$1Yrw`+X_-ja;PkVANpD&mRGdu7C1Ij<56xF2*X=qYUvYvOU-oF-oA7{!0Galh z8XCiMWHdlo&5+|1N?c#yvrFJ5i%RGuoE#{8-ny={vpzWT$ z0PQz(KhHs+*jDfm1Il8#gc@`Plw#TLEM>Ad!S5JPLN}gBDP;e3-8r*4wBTI4%M85jMMQkDUBgh%P>F!WSZk8o2#U-tlgA0J}7)uoApSdu~!}C}$516*us90rb6j z_nF|C;p8U2?i5xjz=P9u`W98Je?;f%1vdVq3A%+gaKK;cA?q5Nx$=0*I&|=9z5^=j zqHSVbv$zemaq=q9RUb2?@9-Q7;)Nd~mn7p$vrkHLI?C@ijC1wO`Cn-Oprm-$7xm-y zapi2!GW& z2u=1#fnYmLjeo%dnE~}MB0(|y`@VfY!&+rz{G>N`k706RR#X^2^X%9ElYao9v6z?K zalrn1&kYI57Mc=k9-nq)M#K*L;(ujs#&^vl#t#=4E=cDV2vlDV6RvHu@o18Nf||5% zFZ)3#mPbJsW4uUt_Lt1eFgTBsZ=(<&&9gXB%P_sV`=|q7>&Bpx^yNoIta3*~_@moE zk#LSW{{5M);cmH^lzFhITYrE6o}E-sBahz`&AS+;=z1+=V2Ac`UlizKr+z}B+4C1F zwq@CsZz!hiYD=SKzAZFl5D~&dCBH-kLKFt{8J(}E@_MNwjt(zYQD zLg~%htuXfah^~9OPfXZ)T{f;&V-c?(gN06f(Gy%dJb)hu>eR1vwS2)MF_zf^)1yB6 zrg^2`3+_cjJc_FR|9=3WtZ>4cq|Ztm99mBDETNiGAw3P(olZP%zu3<5b-n7tw)5}1 zYvc?Yl!5H0!>(3=RS77a2)o-LB5s^kDG&2)RxquPE7}gVEj6IlwaMhI}Xf3UJ~Wy5!=*&xcx3aqok>k{)*lO2OY?bCknxFMzOD zasZ&XdTX50-CYQeh-V{zj-4Kf#nx~1XGIvp_w$(q=~*cR(ZV00vX%l1ksejZ3JuF* z=M7Myi=fuzRT}6Q&25|NY%OR9ivWq!5qE&5JhZh%Q3P)Y`iF;6EOu$)uVq#&-+VjA zfEt{3i%}>X7YBxae*n96i-wKR5@{pCPEPhM3>{rALL%I+Ma79i(g9q`g0Z_A*d#?1 zeDcf*a_Us}t3~&IucY}2jsUOX&74&qu zLUVmQyxBo>>|aLr`rFcLTOv0h7JZhx7hd)DHpON*xP#6h*~a&{U}Y!C9n$s^B?;lF zm}3%0v^k(0wT^wCDpZ`X`UIs%`$BU}W&8Xrwx|SH0ueUY!j9htw52L7M6iEw0HCe$ zKbdTw|1tPHJBFE)PZu-ckJkwAT`{mLLKR@Fh(P@5%vRuK_xL_(1l_f@1VOalm9?&Q z78`DS+yOz=Q3{5Jv)mB1(5c5B|Ki@fN4?cR8EZN#WFF;2?|UcM2p@*A!8?lZZ@_9I zdXh2L|7!r1B|5)7J1ddE5?^@qy=CzLhz&QKmLM>Q=tz)#2qn9n*s*24Q=0nh(#^6hd>ea%UoKJ1#6@5t@%4e(;*tH1mrmbt)fv;zl>rK{%=jPmBEi&jv0Qw1 zxKzyRxyna%HE4{Eq{1|K^||{_sST) zo@tLcrdJd4&bcoUIWwvXW)^tUgrIRqAVoUbkQb!~IvmhtEEQ1)KYakZdM6S>(#giU zroZvKcPcI&??y9`PzIU9SLAPeNnKY}VNY~rO+3UVHru%x@OHnPJz@j)de7hovxEqB z8x#h4%x*L(;jWWM4zZzII*R~&>g*es{!Aq~p@8M$s__DexZczaZQce>M7|Y7E z(-aKu5O+{N)#@f0_H zr5JjfOtVU8Jx{MNe9TO%zBTx~ccfQC)!9Lr!{)oiEIz1{;ZrK(MpR|+9&G)0{O`=x z+@iVK;^Dp;Vi<6mgk9+5db1pu;C~7e8Z?+=uLm#F#0!S^k_M%?%2c=5wAkAmgfi? z2^)7EtCrVp%a9pY_T2s38zfa7ewV4q8b5dtPPzN75)LTvwrXKD%3cHnnL?Z)3Rv-r z0J|?|ORBCyaQ@Uefry^vm4Jjp{24narJ_?QDJ3b}xLxa(x%Ey1Uh=jRkU^x7^=kj` z`EPV7zE2r(H3OqUa{LZ!LO2(ho$KVtbS4(IFY*#P^g(!UHWTo7VP8?&{+^hrbBsQ0 zh@zNBRZkhxEvBX;wm3T9n7re6S5bd{0H-I^fk%WNz^=EROl`0V0Xs!I!2%6TLa<|C zP^Ww}U6@ov3u}?hN8y1Ass^nVmkxlGj}2+Uiwv96MW|dBrqQAQVL0Y#5baY&N>1pW zu}Y_J)ycebjwhc=YV7bF;ttnWsHI(^U52;!^_h=PyUBKBL(O&Y_*fCQ1yTQM0HD5( z;P>m;j9=IfkDH$cEZX&Wsp%~oquDoHzxYC@E$Bl7fd2h`nqb>j%Pa{K&Wyd+ZdK1A zSlyA_e0{U6G4-Z+LsP83bfSndpl z4attyt*3|pyHj2mo}XIWF#QbgC_zTc8QTqyZ^sj0yv&i5$UcL%WVHP&*Unz|v zT&cXs-GQTPY|Sf{g7e!woZJ|~@~td%Btc(UM2Rumh8IFcvj;ya@%V8AIT>%o`W{3u z%V{v4o+C6@0t;}gfEJWUf!N@=#~Zb4!F7WzqQ}+p@|bfOY>AqGbpW8V%FKbeiH_{> z3w$1qD&Ru2W3+^@e$D_ZZPNCsHlOR0IVV#q$F;LP9ZOm7J)XF!-|`y!IG|+g+IjS(8;%o zKz6^90HDE?ctS&oE1P3HkbC1@_jHbG_Aj=P>DIEwghht;Lv)txP{=~6u~d*}jfCBI zi0MT%eN7IhrXHLs%!Yr;pSDZ;tDKW1Vh*Qg9fz&etit`BZDApqrZ#HWg_j72Oy~mg z==Y3Dq?VnM>?7viN>^py*mOsUANHEhE)WiMJm{B964VfC$h`cts{+3RNen@L0HDAI zHL6f3zSzvG(sh}beRJX z1KrMnV(KLr5r&?kj^=y8_a4wN&{4y!==e53!Gb?OBg4i9+W*gnfAqb_E~PT`4$Wap zF?@f9BO#(2|JLS`Z(-tu(8zaX0HDE?ct0jRwu7ahcvW4!VnNZs0LK14cL%XL4%@8k z)szwJ`xs~CkE>p~vq<|iZKChma&My!;|T;AtvPX!{!~C(rg=h4!`^6*bDK7KO?skA zqRLEMOI_{#p_N^$D0kBSn&o%^oDm3A87POK-;Is!Jv_$zFizSLZ4wF%y08erCO8r# zOt;>%o{uPGz9`7{%2^be-ts9@M8Om(WL$7Cz6YOU1gHvxv2P@KSNr*Ml8xy-EG+SN zh&oJ#PNTxG)lCTXw6Q$my3kCAxUUCo-$m<558O*0xcOFpkN}{;>C4URcK=$Ld+=X& zy=6RQ5B8$4SdI|@%RwZ>{ea`P+B784QRde&N6r?^#Wq3@V{Pm`A<7|#*fwp&aECQK zQRAQk10x3$sDujr?7@8vSW+Of7)S0IzQ)I4{4W8FD>~Sy5jp|n>mB?64mvWOn$oD- z{l98dyWv~v_V_C7YFZkWGd0QA6!3e`H@{*4pu(Q0$Pq_na2#6+NFS(>y&MoH!4){0 zp#8uV33`&kHctR;QDu*gxjprEj0lor_ooqLOf78|ClCZIfDhgQyMINFwo_;GB|*!H z+wz`qzYN*YuFtgY6L&C&NKiu;mOo$sn}!=E&nr>4ah-!sfImnw#eQT>6`!7S5@hNz z@(9zYSgvP9rgbS_!Mmz(==XPVI}`Ryxqoq)?f$C*t9-= zlXXK5>teGni0P+Ow4d64asZd{lb9bjtw0w5??#DkYEILsdX5N5xLXQd7S}ibUx9UP zmK}yoU8D~%hRx1dmg0{1A?O&cG5~5eyVH~~YZZKay!Wu=Sld?1o->4b3NW6b=bwm} zPyRnw;{sh>GlUry-tkhIcEK?#3>o}@Sm`OBSpbjyxZ$uCE!nsPA0N4>Kf|hU5Jzb) z4buXmCU$cB7H0?u0g9erzMnmm?yLqQG^l_{!p9z44|ygAHY@!}-<>E;Q&M;?j!Fyr z_p|ZY&Z(G73{!pko>p-fMe(~c=%iDM|CrkTwizV zBXC_tzKt1yjxsB>dWI=wNvXELQ&iIgsoNw$zGhSnK zy8LGIVYYuM$avTtTqz^nm$P6&R}QzIcL0`!h;RduPt`#%5i!Hg;w~h7xs4ouIgbjo zL&AMoG(`<8VZbbziq+mo?)mmKxETW>8WeLk?_7pTFY_K`{a=;%i(oGZPUJ%8G0m zrS9+a`_Jq6oaa2_{XFmYIhTvWLeJ2^(Mk#d1m^NOY&X3wc1UX+FWXDe1BKsTwRuH0 zjSY=Z(gUXA@v|ylwioeqKq(OIF|a!DeOE$ArPqdgbKZJ+3k?*XW<1i0UK8&Bd|7%` zKZHRu!N1Xw87Q>{w>7><(J%4K#Y7XmjW~4g4_w#7&YOuid}gXc12IoKy`+dNe=KLHT*3wOI=jLRzZtlVHYXvv-5(LN z!kxUAeoc%Th+-BKyU|wdA-oedNE`}?mSz)MBw5S3N<@1*SDUulk>qZ056ifDIc4>ep^1bnq6={DH!c#G32i1cBV!Td8 zZk{8t0oEt~=f7YJyWADQKG&HdY> z+(^dtH9K9fj|>P61%;*=^{aiO0)pEFDf~TqFD|kcnL1Jee*8wYbN$myCnFv_HIPOg z`=T4}4{RtrvweZ11bpo?DQnl~iBnzCy_7(>v5CEF`$EejL{}mL@HNeO>;HAw{5d~m z@Rpws1tjW9Shn3)Lt;&p4iXO-Md^wh=>Weri)ShMbJKY5yu;A4$k)hL5Gc^GkHh~B_KQql2J8a znw+_FzDSopPkAT7WX+FP+pkQ2&PV*v$NE4~r`03l<6!vh{9X1WWjYw;B zq@0+p<1%L8`8zZ~Ilq+A@o^qvmeS>H`t{-0-{H8b6b3*`7nYV-IA$l4VqkI*?D_p_ z%>F&$E2?OK3CoZ-vnP((_aZE){kXm#E%W4b90TZiF`DR`-aI5#HAD=$T4u;Iiy>|5 zCw~^vfN^7*O@dRwBmb4qZ~rQD5t?6i1{FxaXti$-lz)6bW#eue-!07N!O;Osh^u#v z(T8WMZ%l_e1xxSL1~p>Q0GTI0_Cb3}aY)7!U-4yuBl^xe@c|4#hPU#Asp!nwD&|J> z2N?75hULLCFG+t{W`I3e-ekbG{Yna3z;VCJI(GeL@FaxzdVU~ALf#&QUeJe z-M4ZAbfu;xS%Q1?5YD4DZxhCwr!Q$j#qtVJ1r z(a%g;an8@uH(>-+gq2$i{C1`|`|VkViFEPIz)}1%Gme)I(0cb}lgPI4X5=3{{z>e| zQMT%E!T^x^D~q6ktX4uZJ5s{L<*t-+O+o61aRz`UzUJ>E&?-7MOv)ZaSox$nESl!y zawP%|Bg|8wak)<)vQ%5N)LWq&T`i=>@=gu;*8W^kGe4gyVQB$>ZUM!M%|rU3!fUSx z(@mqpQGovChwAf*&D(R;e$rKKf(Z*aMKmCv6fn{_GDWQp)&5eQRWOcKE>yxH0j15A zpVKtr%ACgU&Emy173ae-0MT0iMM!<9>-Ce}g{s|l4w{SCqjep5(~405^{Z@#hM(Mt z^nt7b50faVNcuV&@Q+Y!dYsmu`1br1`K`q)ImjQ*tBM4y?olX}$-g4@xg&zvnaz6` z0~BD?Bs@BZ$Ts+pvKCI}G{DsCmCxw?f4}jX1Y~^gJG6Li?dx9?|G0lf} z&Wde}7SxZtR&+k@xWv)|nH$$a%LfV9)h#gf@?+LajtC&m7V@4K|4qYS*5R$*mvt&2 z_WC5}i`+IM|8iAuA)E)c!e@{Ahb){%6T^{!uZ&Lrs*}TMw=%oZ3G>6j14t^gM%E2z zsmpQLdR~$nhQpTzH5O5@HSKgR|2-`s6G*<@aVO`z^iMZEbZmC*Ri?@OOHJK!VxM1b zqcS&c--Th2;OA^LtxrPYHS%L05h|+uxv3To`*`HfG^iS&e=k8qm=5Cs+H2P;8SQ*{ax|BoV)6$KYuJCI5TvA8)pT zMHxps_0(f>+G%0tiRc|HA3rg=b_*%ydFweA#+>$9AF(XdhPdTuI8O6#>RBgU)cw@$ z5xttLO^}TQ%sbTsnW&i07m{BLqxZeiz#;~aw!3)n)F1v)xX_(SwtF}sJD$~M0@6|M z=m2$D)M$H2-D9_xK~rwC&I@)BS|EPr&3<-a?Lcao81+nIQ2|E* zM0gahu_KY`Mt($8fG<@nxF$4?jp)O{k4k31Fy7I0>0M!us-mSt{8n2bW~)msqnFBa zq%oWx&=Cn+76fwRzH0rP|DY?kRW^DMFp8xIl$Rb8XuY-gBuV$$!GVeS$;Y*1lK10C za51nhC~%^{DQ%1?M(d*cwxTK(5SjWiD&4+9S9<5&D;}s3MzQogP)vtKrpk$F9 z>+#V4>XQNgBi*GkhY@p=l}Vd~qe1u@h30h?i}V{IhLxzm9&Xlu?M3A`(%AWW;8{Va z-{*qD?^&T7Q8*?*8~opnWu?ab(QkGCQ50IJPd}u0P1g7}cn9h&L0s*)clY*L$7Ud!#nou{A8x^A8l|2JUiFL zJaNcdXGg%WDg)(v_ad}|Jqo1xsDJ?N>Q2=X7b~?0WxFE;(#V1;zrO`SG+9lrEZ1)s z1DJnZFc_J)_3KT1sdmeib3gQ`dd=TV&EKcoBDx1ir3z86a%*4YFR^Mv&T5V}eiH7A0 zF7->U-Hi(krvnWBmgRd}knHE5d03L*YpR#gz26!%mw=(tW0vCU7*X zF-9z;UARl}6KTKl&?oX+{6ulDt(`F^N94l?*OH{G|PrxIKlXRhLw?8e=HemsW50(x=NKdn1tTEbe*GY0@}ljWM!;*`qGs*83u{$3HKpOlGGu|&nv>|57L)RnuAyQs zNOA%+he8;SyHUSPhm-oI9uryPSOAg6C#epz_uJO3{HIUO!g4~)ym`Vqtng20jJDB$ z)&4hr+f8}Hr>~WB#A@_me`df4KB z@|C*rb5G0I)$JG<0UbHv^q1V&eN{mpjcI-4SQarsX(fpZq$315n}w3?8}938x8HgE zO|=>!5Gj3p^BWx?A6eaUTCVVJB23=w2+|?p@F9lIOZCuW^=;G4vfS03d)|oLj)h`S zEUl)PoMN4&(vIMtR`gJ$Am&ed6ew=LQfUtbfPl&sz#uAISX!`EQn+M{f3t#v_pDn) zg9k!qzGa6&x>1krLD=s}HGPZ}s;?fTD1NBvTM*XC2lt96aogi^9jJQRLhBMicZHF@v(PScO0d{=s4C-L$v3>XqF3XR;m zLG=8`+BgfUks1hyXBF&wlezA=Q4jWtA%LV?ZRhAfQzeCIKYy$x4ql?jQ`i4uTI(Fz zdwTva{gI8$aR$-yZ^9w51r=@J+Eq}O6W|#1pXHhT9O**oZ^$HFmu~V=Xu>1}m$0@7`Dr!4#PD`$nthx+6N{t4 z<&>i5mUt$B7?+;7u%@Z%IpG~xvqX0?#%No!U&~+gZ5sucI%_zcvwDs&m~<&lF@iSD ze^kpq7s-sZ;Q3pw+Bdh|jPSwW=>fBq2y;DK`A#cMsUVwr=yD44N9dgLD6 za(`f@StUR7y%9M(mfLx>S9$@`1~P8}S!>pE*LX|)Ws#EQR5b!ntxg_mO(o@FbaI+q zIHVvoDiWHqbOasNwlEFo%*|yA#jDmqpWd)*3a#x|Z`f#@95nO01S|h#1c;;n?Xsm? z=Jt-`j@G{SMPF+F2vx`92j~G)o(EITu5#fy zreE@J0@XVt9ccjzO=N)NvLLTybwb0l#}fNE*k1N;8Y`;89O=Y-_CGHi*UBE8<7t3& zCUzRdKzjIIyPn-<Svm23?8xfI(n0eJE=d_xAgb#cePKRd!L^n`jrsB?!Sxczns78gXNdIYUmUn}@A9XmU#nGFW}%@a z(2@X0bqx7CHOBQ}A%4v+J7qYKr8|4?6i#i8M@^R-{)nE$KxUv)-38sFx;1XKY^TcK zHbNgvJ6THGBLV7c-n?}Eig`i*@shlx)H@znY<>eFvFRMG24Yv^^}C?QCN0(k-re~V z3Re%iES25WH^}4679!v+#QhqTaCh0wH63U1ZdI-{{nGqwIBn_oQc0$D(2g(}>u+;qsmc>8s zyNiFj#*_2=q5&c?VlKAL+EDw>V)yGV!mf!psvxMpP#nx?*1(dD6l%IIVv-$u#T-=4 zPgs0fVe6yb?L*q6q~~LiA|3mUNdBO}d>j%G_I=u)Ft~7i#8W7NpDp@QtqB7_%|yNA z^QhN3LiipliQYHK=#FR&xLO4tET}nsI|xtj?FpO_6o#j?w||AM)2g!4b&Jw^2Dqbi zPY+F`t?ouCctXgMj47EkOE@}rr<=%stl}eV>az6a{y0NO1K4f4_7xS`ypKt7b)OrH z^C$s3Z@qS0PGEU0-WUOSQt~HvS&vF6ZcJxzNGX+zPOc6GF^M`K?s6XzRZp*!ah0Sh zI4i}`!U6MXwBZiv+bjYp#*IJtmyj;#%v z|Es&vp=GQQ!o)^;pJeC(n;t(ImJnfAj+p?CMnTA$! zUioSpcV{6(@>j0~3vXsu+q_w?BL|`a%VwCyeF7B-T)wi{@WHKCE^2j|mt2b7j)gzB zr=j!^G+Aa8}5E$uJ>xiG|*%ls$s6aU^NPYVgE97#d?tf+~sQ~s_mYz7+mda zc_T+hC}vAlr8ZW_t~tn^0f9#G|8mB&zpZKitMGoCvS)=_wBW(H2*i>!@zGV;P|p*E6`7w z1}LT@ANFuiKl#s)iI3lJ7Y7^T{4{lT0Z}_Yt6aRb^s`n$pVN^72(la)hCRtzPwA+n z1A@E_58WfFP40$jOERl6JDKB(;RT7SPkG*G?-$eSO9ed+w-Xnie;hLTQ!(W5>io7hw zY%c~Ile1$P0atIrQ@%X%8NEso?wYdD0_ledv>Bn zbE_G75btnZb(5Y)Kt#VO{rsutqs~D@5V0B-n(9-Dkl1W>n!5i8<2AQpMNo03A!lwD z|1Yl`y@9`3u2T5kP@C(0t?BLyzwSAUTxYGk)FC7Dn%wBI*fI+u;fhY`MR-7uAK`m- zpKK)d({OfO>6fRK#+-@H5NTXJDiI{d7xP#tZ6dE8fvDJx% z&_z=8l0#UHOr(E+eUw`b1Jxp&y!$fgKHri?u}6F=1Jwlw?5gyDbL8zVCrXj+*dUv# zXP@^987i`Kavj#_@vnv90sfHU%_Rzr4#(A7wSTGTZHhD9(9nsTOjmiU7mLs9@7=gp zbSHxGV}J=nWS_cX=E37EY0-n(tm~JeZ^FuPz4>BkN+R!L&f2n{N3iZNIZxyZTTzfx zSXPe8!v6t*YBlO4!zCOAxLSw|V%T)AR7DXSBiV78I%T4<^kt(y|~fPzK1&(Zle$oh+l#cIlbL{ zlR|fQJpMV;ExV(?Qi0bozocgT1!?45piqH=nc{ZZt|HV@(Zz1{wp(v}czZ$zxNOUh z&NS7%#QnF2qZP^#UlsQbp*!hwnDXoG5i=$8=B?UKNM^lB`NnZDR}In=Q(CS9V!KrKGSCNJsRU@|&gNNHZ`g|q3%URC3g^D1 z3eh#7@@Fi?xbMrMq8s-+$HU`;#60pj(d+Q=KAA*EmKz=x%?~D8>uFj3;OI%8_^+rqG$Hpol8ZZ5J6@S}F6G9=z^>+S6x0$_>(4D2ftWytizBWb?Fd5%Gg>koI zgBY}|ryT9a%g2yOrBT=uKDI0Wy6we7Y}l{ili%pej~3HMqDc1CK1e1bn4wz)JC;04 z%GGw_>lvM%H*^N_UE05S9|>-aL(lrJM-ZfRDy-;lj_Kfug4C7k4ILrmIy{xGDNkAq zANg`UdNjY-7Y+|7+zu0LkE=~Q$dqZ(^HpPXA&;Jw$HD5gHP5$}VgfHs)M@;p$N|;d@u->12=?7P@eejFk*KSHBCh(b?uV z^yO)wd-NFVfavnnr}OlN1%d2d-A9EGZv)*~#TJe)qBWY>ZI& zOVRzRxastIFZinoZwm9RH_xm72xx3Up(Dt#Q2O7jFh_Ldd-Ad0ItbVt1J7KZhux}= zEvCDDQui!C1uJR-Bk6bU^sy0m{Ws6cEAQcD&nr_G4|E|ta@kME$(>l}+Ah|R$XcD4 z>SZdNqXCwN=Udhg|M9KKcfEwM9y8V&ayUFIG+jE6=p>v`I3QHy$d)fw;Md9E3k)FFfacX-Dqx5;u^%jAp?&H6z>`ws7lmmx)Q zwZ(sw;y7Duay8{FQPOl^bX60BXzKR7A0F~ZMfXp};6ikJm$isI_b^=U9NDfKnO5mq zl4b3=_(1Kslg{S90D5!9t%xIcFZ~D}(4BHP9KHPc4g7eZ`0A??7oA-hi}<}2L)Lh& zyHBtXk^MuvpO}@lI=^4meoxHfz7AtzM~uCrzRpK z;J_U{zBoqG;cUlvHQeW*zO9D|HVLZ9)F18ox4`dc9kBLe_SoALBA#DmJ%PpVKWv~p zRIo4FWROrfH>Upff`q`1K)fLZ9u$Jkkwb^Fy|9_&OYJ$3@QO;=eL8S<;l|T zx@myY52833lz(&Q&eE>PeFiv#xeA}Fy$Nfo>eqUJ75gE$*7Ho21!kp{^Q($Tjo&N( z(f3!M7Ss2=Ft0Iet#VB<6EoZ z{c!*W*SCz7Q~N9B1pbSCxxcfUBzmLbU(5r=o@c~`i)tbCu|$_wP!ySU|`Bj#~05~N(0(=~!qPH{$U+kqfX*Cwkekht>gx?Mnt+~CZ`|dJf&MvZk z&0qDO)lOqq#89MU0QdLD`Q*vYwIs**f7LfHcCT&mVWlna-H&pqTK0jvlRw5Neb>5S zSkxHlwJ+Jo0L4|#q|aSM*?*Pd)ng^AU&5&XS6Y3a3)ae?Y?p=o8%z{A55IEza%hF4 zsb=Kuh;f|_NSas<{uR^LRD#w>0{!IdnjrYY1@l~|Eu}SSj5V*K_LtHJ1~;j~k${ua z`P^14ErfM-l+mX}m*fl&Q}&S9fOKIRQFBUqej5LfvvR+99j?mnarnRPZS{Ss=XP2$ ze_(yUWrYOLvz73JTIGNSBm=bV;nB5`u()AV_z2gGh&jgn%?sFCdM8 z2<|uhzCU;F+_^L7Jm)#jIkPAhJr#8|3j8b2Y;FJ*EY~KUMsF)Lu zr|d(~Rwi6tXXxAel}L!WKiv6R)Z$U$c%4t$MpGy@6B3fXc>C%q@!5xTvQW?eoZ$MU zOeB!Bw%e;)oisz(WL~SBFi6^!vD8hxEhR;7TR6FVkoQ zBu(%zgcuQj|KM3H<)%ZRJSil#=iX2vc!aalPjk8Uk=?KZ0Z9=Xb~#Pujh&_txR+R5 zp$Q?bHH~i1#Nn7{YcNR6$X%2(X4b1&aU@!83y zY(G|s)D3xt(E4X96154Zg@mK`Mz;nP50Q3w%B>_Slu_OVyaMBRJ(L()NJyX;$BRFi z7wkU;T=ew%Q~yb`6v`CA@|0Uae@RZY31WVrnH4z$jN z-9i~*TgBqZQ)>-y(|0MCS2S+(aq@C;>M7$mTdzh&WfB7p=2wPU~K{ghFF6&`kwKmr$JJv_5%XT?~py$6Jlpv^|Ph-2?3 z)>vQ)g?6P|eP8RD&TK`*m*J4Wz`IlNKZfOBEFnf5QfB7(Thq$_dx9p5$% z8j?T~D!LwJ7S{nHRRVYA!RD!Erpdh7kNW-)L%e1aCN!(}!?z!hLa<3DiVXRg=Zw;ihIIRnQ@+Bsr6NFlD|q^YW& z`byhfE@$kW*%>q)L^tw%dVkCzylhW7eTb^mAVz=1hq-9kk;(7@1;p@b{#TJ97QXMr z-sl4IdPbP$pK3D#qSy5=%Y=;QmgnTB9%3WI;SilK`StfFN>+83j}_S^l}R94cM(i1t|==qV?gk$6o z*-_icv;BtOpR@k!kvkYHeRvUrA%=vXbEGy7`;-$b49F8h{P&47PA^6j9FK_PNg&P_ zO=}abb%r>r%PAcc5ZU~e!&{3wk~VKYVy3`n+;vc+dL=nTSML~wCCRozGVJ1aYqmxm zmR5-&gQ#t`-Xgwm!?@o0tCwsW{rYt+NCJsZuM{8p2K>02l7O8Kz+QrP%MHJ}MX)1n zTT0*m#`a27>A_fRMhlCb6NLI060ki~Mp^ZQYDh~!r#At__l;&iK&p$q0{Ad-axzoD zYWGckr92YiYVF!KpnrrnU`i{9{wdg00szXDoT$UPNE|(vG-*%nANS<|>X!O#j z2UWj)MVN&&Acv@X?nzyJ7&mbi*dm%UC^qhX%*+IgCrMtJGMui)aHq7xZcejajzw#L z0-{NYh{5T26}J8t+m(^`QEgs(Ar0VUYP0zL94f-Ke=rj@1M0oAyJ#|qW=AT!)BWBf zh1Y&n-xVZX2m~|9Aqwk(c*nG<(Ybp6zp;gt-8mYy%M=i)bm^`t-D{^TS$~QazDjPa z!&O>vQv8rzV@5T>;+Xx9{EnE7-%2&=nPd=M$x9qA>E%(PI%7$-x%dYrTwp3A0+X$j zw{LVG2Z@}X>);MRF?mu!^k-U@U-VwH6FHiBTim9|cPAd(A=7Lmffzo0Rp;4+VOCjN z27sMtrl}=5G%!~4TraMliWf*Ew%lYthGglbTO@Dzlj=V6;;uU0e(*0cHn1;xT@eOx zGt4Yp@@U^HdbmOQ3WE=Evmk1&wC{xyLPDV_U61zEk$uEO5NFQ4WhL?I2J@#sK$v&E zWFAG~6pYm@lR$iMnp~BQ=#tRY^Q{5!Qzk_{zfCvLj&qZUe0Ng6M4jr~R zDh|AbNi9oO$(M+b5b5*yKM@k2p4XQVN*^SIu?&L53ma24JnMBVNsd?Xb`NVcNEd5^A zAk&!+W_!) z1{?iZU7|#Gm{)F$D^?rzDzgSo3WlJzDA=LqOcZ_>Lm&k33f$!i08aX23jx85`QMkRZ3qlc;_CBBu^37Ec*Uh@c(K zB`*09*C|fH8q2?wHK!46>0&_!5tWAx<%q0C=`={}d*%-rR%4ct5K*RjmOg#waSVf+ z^6KbgmnD2o24UzI0HgIt;OL1u!atq zQ$C6yT>YtnZxbHUY8UQ_geVv6r|ND=9!acaGXxKk8mo4IUGkYwD5yxLb>yB1D(#A} zfX`rmeA0faAjl6nqWRZijBy%(iVN%9)-i8!BjGtV#@Ge}9FrQvmt{37|L63jtB;xH z_BWt4xF+tNxy_IaMnBYr1F59l#H6=(U+ACzXFE+YaGn;UC|eu**`3Nn8_tqgQNWI3 zI-PFBJR0f^@uh9MWDr-xWZ$QP^?VO;-pxwHC;2;3dU8ZI7y{$~SB1JpvNO7G%lHijCBJkGC9~NsAcv4)I6VdUmJ;{a zwM}r@9f;Z_^?}C2|Kgd_3g2Y45tqvD*et|QLfCV1@kc-V8*={HwJPrO?E5UzjmRhRR84*x^a0JMC0@`fLH7Lp8KR1*K=Mfh_q8hbN7|iuh8f}vERBqkIvu>HkXsY z!U)0lag=WCY2;>GcHO~XHTZfM`)DH4p8xe;A(n!Nre80xu!^8e9ADRA>>Zg_Aa|PD z%f6tbAFtTo;VTCER^a=}e;Vtd(L;eXxbwXB^+3@4r)HW759|Er_lQONnFTQDasm{$};*;%1??cNklPvS%9|uauFspPgk5& zIcDLh^^8gx6cB|#igqVKCO4`2-^#!*`px$)t^~k#X?SO_|Ne9tw9sSHA^PruDxiUA zco@c79}p*$726{5J1<0-Dz@VF-!bXzAt36zLxNK(EptqP6q80<_f!CwBHvgLTZ<-7=VC*x?)^=&v03!6C564h+#rId;JneMq?lWzZ=yK>Yx1w``xb zxIn$vN7=&CYpm7L9Rv{92rW}wg8zqDAe@EdHE4;oi#x~=5NBS%D=M_}H)8_Wrn;%( zJTWBx)JWd@15ai>d!0DIn2;DZzLrG9*t}gV0!X493rrO?E5#P_^i8HE(9m4t$JJtm z2Ny=ES6?>$0iS1-4pnqy+}iafG8i}=jluw~a9I2k*7~hn;vn=%BWzA$7N|Eg&1lh@ zpy=3q7rHZm;Y$+Bf$%HfekCs&Z8ZH>_mFh#b`Pz3?Q=ey;CY)<4L zpr $O9suTTu&_&Z9$RG0&v;{W6G*(XRf(Z`4?L%=ZPtjGG8~L>{~_vY>(}QgCn6 zWzq6F*EXB=-zQwx_>rXk=lvELMEar{{W=?)h3!oGR1y>5COjz*M3Btm==&DIKHkZ< z7nQrcTi#RQQ8yzYyq|4)qVJTi@w-%dh`19xKMcYk?Eer0myU_g=*DabgKI#ob{+OG zy4q^%s^r3Y4Macx(jy_Ap!~F_0c4A5cPPCafA!l5fE7N0Zo-Wu{<3`Z z%>%HaxXP9ka>58QG~I_^VfU zd)z|NGp+T*gC~kw`^R&WFd-l(5K}%EzX<40w!~!*d-v|v`c=qv93u;n5cxxeB&kb2 z9N*vLd9RxZA3+~UAQIK)-5`4{tL5cv8VpBFjbiY!18$gia+e|pvnhkybn=ju356DT%ip=Cjh90*_nS_6*SVJ)*!-?I0XvW|W z+X$Yd*b>2 z855{vf>>}U<Zx zoyW())bFsQQQ+X#4%P~vRQ)^e~!YTJpD)K~ipc13YI_;XU zX4#?tN}BeE*L}{Go8%Y+s!A4H9y-&?w7=61c>3D{Kh2U3X@I(-$>2D__Ol-O?yu<2T0SP~UpY*CwLevr~Z!O+G3~hsj)jp!bt0Spl zda910f(X9)&W=5-(XsepQk3a}!_6e$I)d{8>=nnnI=UoH=i+M6tnJKE%EgMYMoAv* z)kxCEv1Uv4(-KX(cx;gfrl4FBq!L~81eZ*{wRF#T)GT(TBT!ZkO8WCRJQpgkpqdF)0MA?q~M;xx4>&^GlX}Ve*y*V6y2%xB2|g zS8tA;QE9S$tRFgnH2lUv91!n$UF^JbgfG73QAr9>l%p7rkk-?Rgmk@hhtKYTH%SFu zn<8zRT=DN7vix`&pU@OU0*M&CaVHyr`)^Oa7b+lypnP0dcty*rmqH%uszQ0UP~?zg zR@~oZUP_p>Yv3+->o@O=HGl9$3GMm_Bew#{B;LDT1Y0Gtbs&05K4fU+ZWp*qe(eBM znmT3nU%2x~JHyju{%&Ooh;vtR%VTZXEc#(o#cwKN*ugIvJv1eR->grNGsU2J^2W9x z4y*HeQZv2%8Vzbo0B_{yc(NFRgG&%)ET#j z$c15To&q8!)CgpvYnl4yGx3SqYJl6%N1BZZ4sr7nuZ6$OSW7oilK=XHI zMZBJ^@zDcz#OE8baK=)WmM~UYI*u7egO1C0HXKx;vmBFqogsYqoeMccj3x9{{q#

VR~;@V4F$fh_E3N==~ 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 literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_20_ms_20_kbps_10_loss_FEC.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_20_ms_20_kbps_10_loss_FEC.bit new file mode 100755 index 0000000000000000000000000000000000000000..50b719f065c4b3fb5564dea22f660dceea2532d5 GIT binary patch literal 34525 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 QCK@Nvzmux33@d;C|M}1$UjP6A literal 0 HcmV?d00001 diff --git a/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_60_ms_8_kbps.bit b/external/SILK_SDK_SRC_FLP_v1.0.9/test_vectors/bitstream/payload_8_kHz_60_ms_8_kbps.bit new file mode 100755 index 0000000000000000000000000000000000000000..582cab2330fd9d13ae32c553ec2cfa148710748b GIT binary patch literal 12739 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�l{khRp@?SR09y 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¥Dc2JT=C_mXk-v6z_5bXT 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

Zc?<#?-SEqfnUshZij#>BP$ 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 z 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 ImGLNn`qBvN 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

p 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 WpXOl4#Z>9^T#wT$mS;i5jKvUO88%Lgx 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